diff -u --recursive --new-file v2.2.10/linux/CREDITS linux/CREDITS --- v2.2.10/linux/CREDITS Wed Jun 9 22:23:01 1999 +++ linux/CREDITS Mon Aug 9 12:05:09 1999 @@ -324,6 +324,10 @@ S: 75252 Paris Cedex 05 S: France +N: Ulf Carlsson +D: SGI Indy audio (HAL2) drivers +E: ulfc@bun.falkenberg.se + N: Ed Carp E: ecarp@netcom.com D: uucp, elm, pine, pico port @@ -453,6 +457,14 @@ S: Warrendale, Pennsylvania 15086 S: USA +N: Alex deVries +E: puffin@redhat.com +D: Various SGI parts, bits of HAL2 and Newport +S: 18 Bernier Terrace +S: Kanata, Ontario +S: K2L 2V@ +S: CANADA + N: Eddie C. Dost E: ecd@skynet.be D: Linux/Sparc kernel hacker @@ -946,7 +958,7 @@ E: nkbj@image.dk W: http://www.image.dk/~nkbj D: 4.4BSD and NeXTstep filesystem support in the old ufs. -D: Openstep filesystem support in the new ufs. +D: Openstep filesystem and NeXTstep CDROM support in the new ufs. D: Danish HOWTO, Linux+FreeBSD mini-HOWTO. S: Dr. Holsts Vej 34, lejl. 164 S: DK-8230 Åbyhøj @@ -1603,6 +1615,15 @@ S: San Jose, California 95129 S: USA +N: Augusto Cesar Radtke +E: bishop@sekure.org +W: http://bishop.sekure.org +D: {copy,get,put}_user calls updates +D: Miscellaneous hacks +S: R. Otto Marquardt, 226 - Garcia +S: 89020-350 Blumenau - Santa Catarina +S: Brazil + N: Eric S. Raymond E: esr@thyrsus.com W: http://www.tuxedo.org/~esr/ @@ -1638,12 +1659,13 @@ S: France N: Rik van Riel -E: H.H.vanRiel@humbolt.geo.uu.nl -W: http://humbolt.geo.uu.nl/ -D: Maintainer of the mm-patches page (see www.linuxhq.com) -D: Documentation/sysctl/*, kswapd fixes, random kernel hacker -S: Vorenkampsweg 1 -S: NL-9488 TG Zeijerveld +E: riel@nl.linux.org +W: http://www.nl.linux.org/~riel/ +D: Linux-MM site, Documentation/sysctl/*, swap/mm readaround +D: clustering contributor, kswapd fixes, random kernel hacker, +D: nl.linux.org maintainer, minor scheduler additions +S: IJsselstraat 23a +S: 9725 GA Groningen S: The Netherlands N: William E. Roadcap @@ -2189,6 +2211,7 @@ E: R.E.Wolff@BitWizard.nl D: Written kmalloc/kfree D: Written Specialix IO8+ driver +D: Written Specialix SX driver S: van Bronckhorststraat 12 S: 2612 XV Delft S: The Netherlands @@ -2253,6 +2276,7 @@ E: lnz@dandelion.com W: http://www.dandelion.com/Linux/ D: BusLogic SCSI driver +D: Mylex DAC960 PCI RAID driver D: Miscellaneous kernel fixes S: 3078 Sulphur Spring Court S: San Jose, California 95148 diff -u --recursive --new-file v2.2.10/linux/Documentation/Changes linux/Documentation/Changes --- v2.2.10/linux/Documentation/Changes Fri May 7 09:31:25 1999 +++ linux/Documentation/Changes Mon Aug 9 12:05:09 1999 @@ -11,18 +11,14 @@ functional and running at least 2.0.x kernels. It is originally based on my "Changes" file for 2.0.x kernels and -therefore owes credit to the same people as that file (Jared Mauch, -Axel Boldt, Alessandro Sigala, and countless other users all over the -'net). Please feel free to submit changes, corrections, gripes, -flames, money, etc. to me (kaboom@gatech.edu). If you do so, you don't +therefore owes credit to the same people as that file (Jared Mauch, Axel +Boldt, Alessandro Sigala, and countless other users all over the 'net). +Please feel free to submit changes, corrections, gripes, flames, money, +etc. to me (chris.ricker@genetics.utah.edu). If you do so, you don't need to bother doing so in the form of a diff, as this is generated by texinfo so a diff is useless anyway (though I can incorporate one by hand if you insist upon sending it that way ;-). - For those of you in Europe, -http://www.datanet.hu/generations/linux/Changes2.html is an -English-language HTML version. - The most current version should always be available from http://cyberbuzz.gatech.edu/kaboom/linux/ as well. @@ -30,11 +26,26 @@ http://www.linux-france.com/article/sys/Changes-2.2/Changes-2.2.1.html pour la traduction français. - Also, don't forget http://www.linuxhq.com/ for all your Linux kernel -needs. + Nihongo-ban ha kochira desu (text & html) +http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.2/Changes +http://www2.palnet.or.jp/~matsuda/Changes-2.2.ja.html + + Visite http://www2.adi.uam.es/~ender/tecnico/cambios22.html para +obtener la traducción al español de este documento. + + Also, don't forget + + http://www.linuxhq.com/ -Last updated: March 16, 1999 -Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). + http://www.kernelnotes.org/ + + http://www.kernel.org/ + + for all your Linux kernel needs. + +Last updated: July 13, 1999 +Current Author: Chris Ricker (kaboom@gatech.edu or + chris.ricker@genetics.utah.edu). Current Minimal Requirements **************************** @@ -53,16 +64,16 @@ - Procps 1.2.9 ; ps --version - Procinfo 16 ; procinfo -v - Psmisc 17 ; pstree -V -- Net-tools 1.50 ; hostname -V +- Net-tools 1.52 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; basename --v - Autofs 3.1.1 ; automount --version - NFS 2.2beta40 ; showmount --version - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v -- Pcmcia-cs 3.0.7 ; cardmgr -V -- PPP 2.3.5 ; pppd --version -- Util-linux 2.9i ; chsh -v +- Pcmcia-cs 3.0.13 ; cardmgr -V +- PPP 2.3.8 ; pppd --version +- Util-linux 2.9t ; chsh -v Upgrade notes ************* @@ -86,9 +97,9 @@ compiled under 2.2, for example. As of 2.1.115, support for the deprecated major 4 /dev/ttyp* devices -was removed. If necessary (eg, you get "out of pty" error messages when -you obviously are not out of pty's), create major 3 /dev/tty* and major -2 /dev/pty* devices (see Documentation/devices.txt for more +was removed. If necessary (eg, you get "out of pty" error messages +when you obviously are not out of pty's), create major 3 /dev/tty* and +major 2 /dev/pty* devices (see Documentation/devices.txt for more information). In general, you should make sure that your /dev directory is up-to-date if you are experiencing any problems. @@ -134,8 +145,8 @@ release. If you upgrade to libc-5.4.x, you also have to upgrade your dynamic -linker (ld.so) to at least 1.9.9, or all sorts of weirdness will -happen. Actually, ld.so-1.8.2 and later will work, but 1.9.9 is widely +linker (ld.so) to at least 1.9.9, or all sorts of weirdness will happen. +Actually, ld.so-1.8.2 and later will work, but 1.9.9 is widely available, so if you need to upgrade, use it. If you get a release later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are fixed in later releases. Please make sure you don't install ld.so-2.x @@ -158,9 +169,9 @@ of your boot scripts calls ldconfig, /etc/ld.so.cache is deleted. Init, however, still references that file; as of 2.1.122, the kernel will consequently not be able to remount the root file system r/o at system -shutdown. To fix this, upgrade to at least the pre6 release of GNU -libc 2.0.7. As a temporary workaround, modify your boot scripts to do -the following before calling ldconfig: +shutdown. To fix this, upgrade to at least the pre6 release of GNU libc +2.0.7. As a temporary workaround, modify your boot scripts to do the +following before calling ldconfig: ln -f /etc/ld.so.cache /etc/ld.so.cache.old @@ -197,6 +208,12 @@ and binutils-development packages (Debian puts bfd.h in binutils-dev, for example). +Bin86 +===== + + To compile the kernel on the IA32 platform, a real-mode assembler and +linker is required. These are found in the bin86 package. + Gnu C ===== @@ -287,19 +304,17 @@ larger swap spaces, you need the new mkswap found in util-linux. You also need to upgrade util-linux to get the latest version of mount. - Partitions on 2048 byte sectored media (certain magneto opticals -most prominently) were broken throughout the whole of 2.1 kernel -series, meaning that you will be unable to use 2.1-partitioned media on -Linux 2.2. This is not a 2.2 bug - 2.2 finally does the right thing! -[If you have to interchange media between Linux 2.1 and 2.2, your best -bet is to not use partitions at all but create the filesystem on the -raw device (e.g. /dev/sda) instead. This is also known as the -superfloppy format.] - - To properly create partitions on 2048 byte sectored media with Linux -2.2, be sure to use no less than fdisk version 2.9i and invoke fdisk -using '-b 2048' as an option. - + Partitions on 2048-bytes-per-sector media (certain magneto-opticals +most prominently) were broken throughout the 2.1 kernel series, meaning +that you will be unable to use 2.1-partitioned media on Linux 2.2. This +is not a 2.2 bug - 2.2 finally does the right thing! [If you have to +interchange media between Linux 2.1 and 2.2, your best bet is to not +use partitions at all but create the filesystem on the raw device (e.g. +/dev/sda) instead. This is also known as the superfloppy format.] + + To properly create partitions on 2048-bytes-per-sector media with +Linux 2.2, be sure to use no less than fdisk version 2.9i and invoke +fdisk using '-b 2048' as an option. RPM === @@ -311,7 +326,7 @@ ====== A new "stable" version of DOSEMU is available for 2.2 kernels. -Upgrade to 0.98.4 or later. +Upgrade to 0.98.6 or later. Loadlin ======= @@ -329,7 +344,7 @@ Parallel Ports ============== - As of 2.1.33, parallel port support can now by handled by the parport + As of 2.1.33, parallel port support can now be handled by the parport driver. Be aware that with Plug-and-Play support turned on, your parallel port may no longer be where you expect it; for example, LPT1 (under DOS) was sometimes /dev/lp1 in Linux, but will probably be @@ -351,7 +366,9 @@ When you build your kernel with Syncookie support (CONFIG_SYN_COOKIES) the syncookie code still defaults to off (unlike the 2.0.30+ behavior). You have to explicitly enable it by issuing the -following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies +following command: + + echo 1 > /proc/sys/net/ipv4/tcp_syncookies Bash ==== @@ -381,8 +398,8 @@ To mount SMB (Samba / Windows) shares, you'll need to use the smbmount utility included with release 2.0 of Samba. Documentation/filesystems/smbfs.txt has more information about this. -Note that smbmount must have been built against 2.2 headers to work -with 2.2; if all else fails, recompile it and hope it works ;-). In +Note that smbmount must have been built against 2.2 headers to work with +2.2; if all else fails, recompile it and hope it works ;-). In addition, Mike Warfield has a script and some information at http://www.wittsend.com/mhw/smbmount.html that you will probably find useful. @@ -445,6 +462,7 @@ backing up your copy of rvplayer, and then editing it by: dd if=/dev/zero of=rvplayer bs=1 count=1 seek=657586 conv=notrunc + dd if=/dev/zero of=rvplayer bs=1 count=1 seek=665986 conv=notrunc If you're lucky, you'll then have sound.... @@ -519,6 +537,13 @@ ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.15 ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.15 +Bin86 +===== + +The 0.4 release: +ftp://metalab.unc.edu/pub/Linux/GCC/bin86-0.4.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/bin86-0.4.tar.gz + Gnu C ===== @@ -598,9 +623,9 @@ DOSEMU ====== -The 0.98.1 release: -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.4.tgz -ftp://ftp.dosemu.org/dosemu/dosemu-0.98.4.tgz +The 0.98.6 release: +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.6.tgz +ftp://ftp.dosemu.org/dosemu/dosemu-0.98.6.tgz Loadlin ======= @@ -620,7 +645,7 @@ ========== The 2.9 release: -ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9i.tar.gz +ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9t.tar.gz Autofs ====== @@ -635,16 +660,16 @@ ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz -The kernel-level 12/04/98 release: -ftp://ftp.yggdrasil.com/private/hjl/knfsd-981204.tar.gz -ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-981204.tar.gz +The kernel-level 1.4.4 release: +ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.4.tar.gz +ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.4.tar.gz Net-tools ========= -The 1.50 release: -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.50.tar.gz -http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.50.tar.gz +The 1.52 release: +ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.52.tar.gz +http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.52.tar.gz Ypbind ====== @@ -664,8 +689,8 @@ The 1.14.7 release: ftp://ftp.gnu.org/gnu/bash/bash-1.14.7.tar.gz -The 2.02.1 release: -ftp://ftp.gnu.org/gnu/bash/bash-2.02.1.tar.gz +The 2.03 release: +ftp://ftp.gnu.org/gnu/bash/bash-2.03.tar.gz Ncpfs ===== @@ -676,14 +701,14 @@ SMBfs ===== -The 2.0.0 release of Samba: -ftp://ftp.samba.org/pub/samba/samba-2.0.0.tar.gz +The 2.0.5a release of Samba: +ftp://ftp.samba.org/pub/samba/samba-2.0.5a.tar.gz Pcmcia-cs ========= -The 3.0.7 release: -ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.7.tar.gz +The 3.0.13 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.13.tar.gz Setserial ========= @@ -695,8 +720,8 @@ PPP === -The 2.3.5 release: -ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz +The 2.3.8 release: +ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.8.tar.gz IP Chains ========= @@ -714,8 +739,8 @@ DHCP clients ============ -The 2.0b1p18 ISC dhcpclient release: -ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl8.tar.gz +The 2.0b1pl27 ISC dhcpclient release: +ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl27.tar.gz The 1.3.17-pl2 PhysTech dhcpcd release: ftp://ftp.phystech.com/pub/dhcpcd-1.3.17-pl2.tar.gz @@ -735,15 +760,15 @@ Fbset ===== -The 11/04/98 release: -http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19981104.tar.gz +The 2.1 release: +http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.1.tar.gz PCI utils ========= -The 1.09 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-1.09.tar.gz -ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-1.09.tar.gz +The 2.0 release: +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz +ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz Tunelp ====== @@ -767,8 +792,9 @@ IP utils ======== -The 03/01/99 release: -ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.1.99-now-ss990301.tar.gz +The June 1999 release: +ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990630.tar.gz +ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990610.tar.gz Patch ===== @@ -791,7 +817,7 @@ your favorite Red Hat mirror site before installing the non-RPM version. Remember, you might need to use the --force option to get the upgrade to install. ftp://contrib.redhat.com/ , -ftp://developer.redhat.com/ , or ftp://updates.redhat.com/ will have +ftp://developer.redhat.com/ , or ftp://updates.redhat.com/ will have almost everything you need, and Red Hat 5.2 ships with most necessary software. @@ -802,5 +828,5 @@ Please send info about any other packages that 2.2 "broke" or about any new features of 2.2 that require extra or new packages for use to Chris -Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). +Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). diff -u --recursive --new-file v2.2.10/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.2.10/linux/Documentation/Configure.help Sun Jun 13 19:54:06 1999 +++ linux/Documentation/Configure.help Mon Aug 9 12:04:57 1999 @@ -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 @@ -4032,7 +4037,13 @@ MB/s with wide FAST-40 LVD devices and controllers. Recent versions of the 53C8XX chips are better supported by the - option "SYM53C8XX SCSI support", below. + option "SYM53C8XX SCSI support", below. This option will configure + a different driver. + + If you want the kernel to select the recommended driver for each of + of your NCR/SYM53C8XX controllers you may just configure both the + NCR53C8XX and the SYM53C8XX options to Y, or if modules are preferred, + load first the sym53c8xx.o module and then the ncr53c8xx.o module. Note: there is yet another driver for the 53c8xx family of controllers ("NCR53c7,8xx SCSI support" above). If you want to use them both, @@ -4989,6 +5000,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 +5137,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 @@ -5734,7 +5765,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 +6523,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 @@ -7360,6 +7410,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 @@ -8110,6 +8172,16 @@ If you haven't heard about it, it's safe to say N. +Cyclades-Z interrupt mode operation (EXPERIMENTAL) +CONFIG_CYZ_INTR + The Cyclades-Z family of multiport cards allows 2 (two) driver + op modes: polling and interrupt. In polling mode, the driver will + check the status of the Cyclades-Z ports every certain amount of + time (which is called polling cycle and is configurable). In + interrupt mode, it will use an interrupt line (IRQ) in order to check + the status of the Cyclades-Z ports. The default op mode is polling. + If unsure, say N. + Stallion multiport serial support CONFIG_STALDRV Stallion cards give you many serial ports. You would need something @@ -9191,7 +9263,7 @@ after the PnP configuration is finished. To do this, say M here and read Documentation/modules.txt as well as Documentation/sound/README.modules; the module will be called - sound.o. + soundcore.o. I'm told that even without a sound card, you can make your computer say more than an occasional beep, by programming the PC speaker. @@ -9764,6 +9836,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 @@ -9830,6 +9907,20 @@ connections. See Documentation/isdn/README.x25 for more information if you are thinking about using this. +ISDN diversion services support +CONFIG_ISDN_DIVERSION + This option allows you to use some supplementary diversion + services in conjunction with the HiSax driver on an EURO/DSS1 + line. Supported options are CD (call deflection), CFU (Call + forward unconditional), CFB (Call forward when busy) and CFNR + (call forward not reachable). + Additionally the actual CFU, CFB and CFNR state may be + interrogated. The use of CFU, CFB, CFNR and interrogation may + be limited to some countries. The keypad protocol is still not + implemented. + CD should work in all countries if this service has been sub- + scribed. + ICN 2B and 4B support CONFIG_ISDN_DRV_ICN This enables support for two kinds of ISDN-cards made by a German @@ -9872,6 +9963,24 @@ called hisax.o. See Documentation/isdn/README.HiSax for more information on using this driver. +HiSax Support for EURO/DSS1 +CONFIG_HISAX_EURO + Enable this if you have a EURO ISDN line. + +Support for german chargeinfo +CONFIG_DE_AOC + If you have german AOC, you can enable this to get the charginfo. + +Disable sending complete +CONFIG_HISAX_NO_SENDCOMPLETE + If you have trouble with some ugly exchanges or you live in + Australia select this option. + +Disable sending low layer compatibility +CONFIG_HISAX_NO_LLC + If you have trouble with some ugly exchanges try to select this + option. + HiSax Support for Teles 16.0/8.0 CONFIG_HISAX_16_0 This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 @@ -9890,13 +9999,15 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Teles 16.3c -CONFIG_HISAX_TELES3C - This enables HiSax support for the Teles ISDN-cards 16.3c. - - See Documentation/isdn/README.HiSax on how to configure it using the - different cards, a different D-channel protocol, or non-standard - IRQ/port settings. +HiSax Support for Teles PCI +CONFIG_HISAX_TELESPCI + This enables HiSax support for the Teles PCI. + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Teles S0Box +CONFIG_HISAX_S0BOX + This enables HiSax support for the Teles/Creatix parallel port + S0BOX. See Documentation/isdn/README.HiSax on how to configure it. HiSax Support for AVM A1 (Fritz) CONFIG_HISAX_AVM_A1 @@ -9906,7 +10017,17 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Elsa ISA cards +HiSax Support for AVM PnP/PCI (Fritz!PNP/PCI) +CONFIG_HISAX_FRITZPCI + This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for AVM A1 PCMCIA (Fritz) +CONFIG_HISAX_AVM_A1_PCMCIA + This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Elsa cards CONFIG_HISAX_ELSA This enables HiSax support for the Elsa Mircolink ISA cards, for the Elsa Quickstep series cards and Elsa PCMCIA. @@ -9949,7 +10070,16 @@ different cards, a different D-channel protocol, or non-standard IRQ/port settings. -HiSax Support for Sedlbauer speed card/win-star +HiSax Support for HFC-S based cards +CONFIG_HISAX_HFCS + This enables HiSax support for the HFC-S 2BDS0 based cards, like + teles 16.3c. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for Sedlbauer cards CONFIG_HISAX_SEDLBAUER This enables HiSax support for the Sedlbauer passive ISDN cards. @@ -9986,51 +10116,46 @@ See Documentation/isdn/README.HiSax on how to configure it using a different D-channel protocol, or non-standard IRQ/port settings. +HiSax Support for Siemens I-Surf card +CONFIG_HISAX_ISURF + This enables HiSax support for the Siemens I-Talk/I-Surf card with + ISAR chip. + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for HST Saphir card +CONFIG_HISAX_HSTSAPHIR + This enables HiSax support for the HST Saphir card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Telekom A4T card +CONFIG_HISAX_BKM_A4T + This enables HiSax support for the Telekom A4T card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Scitel Quadro card +CONFIG_HISAX_SCT_QUADRO + This enables HiSax support for the Scitel Quadro card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Gazel cards +CONFIG_HISAX_GAZEL + This enables HiSax support for the Gazel cards. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + HiSax Support for Am7930 (EXPERIMENTAL) CONFIG_HISAX_AMD7930 This enables HiSax support for the AMD7930 chips on some SPARCs. This code is not finished yet. -HiSax Support for EURO/DSS1 -CONFIG_HISAX_EURO - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for German 1TR6", below. And vice - versa. - -Support for German tariff info -CONFIG_DE_AOC - If you want that the HiSax hardware driver sends messages to the - upper level of the isdn code on each AOCD (Advice Of Charge, During - the call -- transmission of the fee information during a call) and - on each AOCE (Advice Of Charge, at the End of the call -- - transmission of fee information at the end of the call), say Y here. - This works only in Germany. - -Support for Australian Microlink service (not for std. EURO) -CONFIG_HISAX_ML - If you are in Australia and connected to the Microlink telephone - network, enable this, because there are little differences in - protocol. - - Please don't enable this in other countries. - -HiSax Support for US/NI-1 (not released yet) -CONFIG_HISAX_NI1 - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - -HiSax Support for German 1TR6 -CONFIG_HISAX_1TR6 - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - NOTE: If you say Y here and you have only one ISDN card installed, - you cannot say Y to "HiSax Support for EURO/DSS1", above. And vice - versa. - PCBIT-D support CONFIG_ISDN_DRV_PCBIT This enables support for the PCBIT ISDN-card. This card is @@ -10731,6 +10856,11 @@ Choose Y here if you have this FM radio card, and then fill in the port address below. + If you have GemTeks combined (PnP) sound- and radio card you must use + this driver as a module and setup the card with isapnptools. You must + also pass the module a suitable io parameter, 0x248 has been reported + to be used by these cards. + In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at @@ -11452,6 +11582,14 @@ boards from BVM Ltd. Everyone using one of these boards should say Y here. +Compaq SMART2 support +CONFIG_BLK_CPQ_DA + This is the driver for Compaq Smart Array controllers. + Everyone using these boards should say Y here. + See "linux/Documentation/cpqarray.txt" for the current list of + boards supported by this driver, and for further information + on the use of this driver. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -u --recursive --new-file v2.2.10/linux/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt --- v2.2.10/linux/Documentation/cpqarray.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cpqarray.txt Mon Aug 9 12:04:38 1999 @@ -0,0 +1,107 @@ +This driver is for Compaq's SMART2 Intellegent Disk Array Controllers. + +WARNING: +-------- + +This driver comes with NO WARRANTY. It is not officially supported by +Compaq. Do not call technical support. Use at your own risk. + +Supported Cards: +---------------- + +This driver is known to work with the following cards: + + * SMART (EISA) + * SMART-2/E (EISA) + * SMART-2/P + * SMART-2DH + * SMART-2SL + * SMART-221 + * SMART-3100ES + * SMART-3200 + * Integrated Smart Array Controller + * SA 4200 + * SA 4250ES + +It should also work with some really old Disk array adapters, but I am +unable to test against these cards: + + * IDA + * IDA-2 + * IAES + +Installing: +----------- + +You need to build a new kernel to use this device, even if you want to +use a loadable module. + +Apply the patch to a 2.2.x kernel: + +# cd linux +# patch -p1 diff -u --recursive --new-file v2.2.10/linux/Documentation/filesystems/ufs.txt linux/Documentation/filesystems/ufs.txt --- v2.2.10/linux/Documentation/filesystems/ufs.txt Fri Apr 16 08:20:23 1999 +++ linux/Documentation/filesystems/ufs.txt Mon Aug 9 12:04:38 1999 @@ -30,6 +30,10 @@ used in NextStep supported as read-only + nextstep-cd + used for NextStep CDROMs (block_size == 2048) + supported as read-only + openstep used in OpenStep supported as read-only diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/CREDITS linux/Documentation/isdn/CREDITS --- v2.2.10/linux/Documentation/isdn/CREDITS Wed Jun 2 11:29:27 1999 +++ linux/Documentation/isdn/CREDITS Mon Aug 9 12:04:38 1999 @@ -24,7 +24,7 @@ Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) For his Sync-PPP-code. -Karsten Keil (isdn4@temic-ech.spacenet.de) +Karsten Keil (keil@isdn4linux.de) For adding 1TR6-support to the Teles-driver. For the HiSax-driver. diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/HiSax.cert linux/Documentation/isdn/HiSax.cert --- v2.2.10/linux/Documentation/isdn/HiSax.cert Wed Dec 31 16:00:00 1969 +++ linux/Documentation/isdn/HiSax.cert Mon Aug 9 12:04:38 1999 @@ -0,0 +1,76 @@ +-----BEGIN PGP SIGNED MESSAGE----- + +First: + + HiSax 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. + +However, if you wish to modify the HiSax sources, please note the following: + +HiSax has passed the ITU approval test suite with ELSA Quickstep ISDN cards. +The certification is only valid for the combination of the tested software +version and the tested hardware. Any changes to the HiSax source code may +therefore affect the certification. + +If you change the main files of the HiSax ISDN stack, the certification will +become invalid. Because in most countries it is illegal to connect +unapproved ISDN equipment to the public network, I have to guarantee that +changes in HiSax do not affect the certification. + +In order to make a valid certification apparent to the user, I have built in +some validation checks that are made during the make process. The HiSax main +files are protected by md5 checksums and the md5sum file is pgp signed by +myself: + +KeyID 1024/FF992F6D 1997/01/16 Karsten Keil +Key fingerprint = 92 6B F7 58 EE 86 28 C8 C4 1A E6 DC 39 89 F2 AA + +Only if the checksums are OK, and the signature of the file +"drivers/isdn/hisax/md5sums.asc" match, is the certification valid; a +message confirming this is then displayed during the hisax init process. + +The affected files are: + +drivers/isdn/hisax/isac.c +drivers/isdn/hisax/isdnl1.c +drivers/isdn/hisax/isdnl2.c +drivers/isdn/hisax/isdnl3.c +drivers/isdn/hisax/tei.c +drivers/isdn/hisax/callc.c +drivers/isdn/hisax/l3dss1.c +drivers/isdn/hisax/l3_1tr6.c +drivers/isdn/hisax/cert.c +drivers/isdn/hisax/elsa.c + +Please send any changes, bugfixes and patches to me rather than implementing +them directly into the HiSax sources. + +This does not reduce your rights granted by the GNU General Public License. +If you wish to change the sources, go ahead; but note that then the +certification is invalid even if you use ELSA Quickstep cards. + +Here are the certification registration numbers for ELSA Quickstep cards: +German D133361J CETECOM ICT Services GmbH 0682 +European D133362J CETECOM ICT Services GmbH 0682 + + +Karsten Keil +keil@isdn4linux.de + +-----BEGIN PGP SIGNATURE----- +Version: 2.6.3i +Charset: noconv + +iQCVAwUBNj5OKDpxHvX/mS9tAQFHuQP/WeImlqCcDZ2d132yAvRBWFULlJoSf1P/ +c1lVTeaWvsSaY5Cu9hrKhXXhPzeEaitUbcUBPXdpzFWCA5CE902lnz7AhgRC+HF1 +0qiKgkZZyc/5HKasFymR1+IWSLw30GesP3Di/ZMR3NJi8SlY9PIjx7hnEMunGSRO +1ufPvfWWuu8= +=nGJk +-----END PGP SIGNATURE----- diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.2.10/linux/Documentation/isdn/INTERFACE Tue Apr 28 14:22:04 1998 +++ linux/Documentation/isdn/INTERFACE Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.8 1998/02/20 17:38:20 fritz Exp $ +$Id: INTERFACE,v 1.12 1999/07/13 20:59:59 werner Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -478,6 +478,14 @@ 1 = At least one device matching this call (RING on ttyI). HL-driver may send ALERTING on the D-channel in this case. 2 = Call will be rejected. + 3 = Incomplete number. + The CalledNumber would match, if more digits are appended. + This feature is needed for Number-Blocks assigned to + a line. In this case, the LL driver should assemble the + CalledNumber by handling keypad protocol and try again + later with a longer CalledNumber. + HL drivers serving ordinary lines should interpret this + return code like 0 (nothing matches). -1 = An error happened. (Invalid parameters for example.) ISDN_STAT_RUN: @@ -526,7 +534,9 @@ driver = driver-Id command = ISDN_STAT_BCONN arg = channel-number, locally to the driver. (starting with 0) - para = unused. + para.num = ASCII-String, containing type of connection (for analog + modem only). This will be appended to the CONNECT message + e.g. 14400/V.32bis ISDN_STAT_DHUP: @@ -645,3 +655,21 @@ arg = channel-number, locally to the driver. (starting with 0) para.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. ISDN_STAT_L1ERR_RECV: Packet lost while receiving. + ISDN_STAT_DISCH: + + With this call, the HL-driver signals the LL to disable or enable the + use of supplied channel and driver. + The call may be used to reduce the available number of B-channels after + loading the driver. The LL has to ignore a disabled channel when searching + for free channels. The HL driver itself never delivers STAT callbacks for + disabled channels. + The LL returns a nonzero code if the operation was not successfull or the + selected channel is actually regarded as busy. + + Parameter: + driver = driver-Id + command = ISDN_STAT_DISCH + arg = channel-number, locally to the driver. (starting with 0) + parm.num[0] = 0 if channel shall be disabled, else enabled. + + diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v2.2.10/linux/Documentation/isdn/README Wed May 20 18:54:34 1998 +++ linux/Documentation/isdn/README Mon Aug 9 12:04:38 1999 @@ -31,7 +31,7 @@ This mailinglist is bidirectionally gated to the newsgroup de.alt.comm.isdn4linux - + There is also a well maintained FAQ (both english and german) available at ftp.franken.de in /pub/isdn4linux/FAQ/ This FAQ is also available at http://www.lrz-muenchen.de/~ui161ab/www/isdn/ @@ -41,11 +41,11 @@ In the following Text, the terms MSN and EAZ are used. MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies - to Euro(EDSS1)-type lines. Usually it is simply the phone-number. + to Euro(EDSS1)-type lines. Usually it is simply the phone number. EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and applies to German 1TR6-type lines. This is a one-digit string, - simply appended to the base phone-number + simply appended to the base phone number The internal handling is nearly identical, so replace the appropriate term to that one, which applies to your local ISDN-environment. @@ -56,13 +56,13 @@ A low-level-driver can register itself through an interface (which is defined in isdnif.h) and gets assigned a slot. The following char-devices are made available for each channel: - + A raw-control-device with the following functions: write: raw D-channel-messages (format: depends on driver). read: raw D-channel-messages (format: depends on driver). ioctl: depends on driver, i.e. for the ICN-driver, the base-address of the ports and the shared memory on the card can be set and read - also the boot-code and the protocol software can be loaded into + also the boot-code and the protocol software can be loaded into the card. O N L Y !!! for debugging (no locking against other devices): @@ -74,38 +74,38 @@ 128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator: The functionality is almost the same as that of a serial device - (the line-discs are handled by the kernel), which lets you run - SLIP, CSLIP and asynchronous PPP through the devices. We have tested + (the line-discs are handled by the kernel), which lets you run + SLIP, CSLIP and asynchronous PPP through the devices. We have tested Seyon, minicom, CSLIP (uri-dip) PPP and mgetty (compiled with NO_FAX), XCept. The modem-emulation supports the following: 1.3.1 Commands: - ATA Answer incoming call. - ATD Dial, the number may contain: + ATA Answer incoming call. + ATD Dial, the number may contain: [0-9] and [,#.*WPT-S] the latter are ignored until 'S'. - The 'S' must precede the number, if + The 'S' must precede the number, if the line is a SPV (German 1TR6). - ATE0 Echo off. - ATE1 Echo on (default). + ATE0 Echo off. + ATE1 Echo on (default). ATH Hang-up. - ATH1 Off hook (ignored). + ATH1 Off hook (ignored). ATH0 Hang-up. - ATI Return "ISDN for Linux...". + ATI Return "ISDN for Linux...". ATI0 " ATI1 " - ATI2 Report of last connection. + ATI2 Report of last connection. ATO On line (data mode). ATQ0 Enable result codes (default). ATQ1 Disable result codes (default). - ATSx=y Set register x to y. - ATSx? Show contents of register x. + ATSx=y Set register x to y. + ATSx? Show contents of register x. ATV0 Numeric responses. ATV1 English responses (default). - ATZ Load registers and EAZ/MSN from Profile. - AT&Bx Set Send-Packet-size to x (max. 4000) + ATZ Load registers and EAZ/MSN from Profile. + AT&Bx Set Send-Packet-size to x (max. 4000) The real packet-size may be limited by the low-level-driver used. e.g. the HiSax-Module- limit is 2000. You will get NO Error-Message, @@ -114,13 +114,13 @@ driver may not be selected (see "Automatic Assignment") however the size of outgoing packets will be limited correctly. - AT&D0 Ignore DTR - AT&D2 DTR-low-edge: Hang up and return to + AT&D0 Ignore DTR + AT&D2 DTR-low-edge: Hang up and return to command mode (default). AT&D3 Same as AT&D2 but also resets all registers. - AT&Ex Set the EAZ/MSN for this channel to x. - AT&F Reset all registers and profile to "factory-defaults" - AT&Rx Select V.110 bitrate adaption. + AT&Ex Set the EAZ/MSN for this channel to x. + AT&F Reset all registers and profile to "factory-defaults" + AT&Rx Select V.110 bitrate adaption. This command enables V.110 protocol with 9600 baud (x=9600), 19200 baud (x=19200) or 38400 baud (x=38400). A value of x=0 disables V.110 switching @@ -142,24 +142,24 @@ The value 198 is choosen arbitrarily. Users _MUST_ negotiate this value before establishing a connection. - AT&Sx Set window-size (x = 1..8) (not yet implemented) - AT&V Show all settings. + AT&Sx Set window-size (x = 1..8) (not yet implemented) + AT&V Show all settings. AT&W0 Write registers and EAZ/MSN to profile. See also iprofd (5.c in this README). - AT&X0 BTX-mode and T.70-mode off (default) - AT&X1 BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0) - AT&X2 T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0) + AT&X0 BTX-mode and T.70-mode off (default) + AT&X1 BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0) + AT&X2 T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0) For voice-mode commands refer to README.audio - 1.3.2 Escape sequence: + 1.3.2 Escape sequence: During a connection, the emulation reacts just like a normal modem to the escape sequence +++. - (The escape character - default '+' - can be set in the + (The escape character - default '+' - can be set in the register 2). - The DELAY must at least be 1.5 seconds long and delay + The DELAY must at least be 1.5 seconds long and delay between the escape characters must not exceed 0.5 seconds. - + 1.3.3 Registers: Nr. Default Description @@ -172,7 +172,7 @@ 4 10 Line feed character (ASCII). 5 8 Backspace character (ASCII). 6 3 Delay in seconds before dialing. - 7 60 Wait for carrier (ignored). + 7 60 Wait for carrier. 8 2 Pause time for comma (ignored) 9 6 Carrier detect time (ignored) 10 7 Carrier loss to disconnect time (ignored). @@ -203,8 +203,8 @@ 1 = T.70 protocol (Only for BTX!) on Bit 2: 0 = Don't hangup on DTR low. 1 = Hangup on DTR low. - Bit 3: 0 = Standard response messages - 1 = Extended response messages + Bit 3: 0 = Standard response messages + 1 = Extended response messages Bit 4: 0 = CALLER NUMBER before every RING. 1 = CALLER NUMBER after first RING. Bit 5: 0 = T.70 extended protocol off @@ -215,18 +215,25 @@ an incoming call happened (RING) and the remote party hung up before any local ATA was given. - 14 0 Layer-2 protocol: - 0 = X75/LAPB with I-frames - 1 = X75/LAPB with UI-frames + Bit 7: 0 = Don't show display messages from net + 1 = Show display messages from net + (S12 Bit 1 must be 0 too) + 14 0 Layer-2 protocol: + 0 = X75/LAPB with I-frames + 1 = X75/LAPB with UI-frames 2 = X75/LAPB with BUI-frames 3 = HDLC 4 = Transparent (audio) 7 = V.110, 9600 baud 8 = V.110, 19200 baud 9 = V.110, 38400 baud - 15 0 Layer-3 protocol: (at the moment always 0) + 10 = Analog Modem (only if hardware supports this) + 11 = Fax G3 (only if hardware supports this) + 15 0 Layer-3 protocol: 0 = transparent - 16 250 Send-Packet-size/16 + 1 = transparent with audio features (e.g. DSP) + 2 = Fax G3 (S14 has to be set to 11) + 16 250 Send-Packet-size/16 17 8 Window-size (not yet implemented) 18 4 Bit coded register, Service-Octet-1 to accept, or to be used on dialout: @@ -254,6 +261,9 @@ Set on incoming call (during RING) to octet 3a of calling party number IE (Screening info) See section 4.5.10 of ITU Q.931 + 23 0 Bit coded register: + Bit 0: 0 = Add CPN to RING message off + 1 = Add CPN to RING message on Last but not least a (at the moment fairly primitive) device to request the line-status (/dev/isdninfo) is made available. @@ -262,7 +272,7 @@ All inactive physical lines are listening to all EAZs for incoming calls and are NOT assigned to a specific tty or network interface. - When an incoming call is detected, the driver looks first for a network + When an incoming call is detected, the driver looks first for a network interface and then for an opened tty which: 1. is configured for the same EAZ. @@ -270,7 +280,7 @@ 3. (only for network interfaces if the security flag is set) contains the caller number in its access list. 4. Either the channel is not bound exclusively to another Net-interface, or - it is bound AND the other checks apply to exactly this Interface. + it is bound AND the other checks apply to exactly this interface. (For usage of the bind-features, refer to the isdnctrl-man-page) Only when a matching interface or tty is found is the call accepted @@ -301,7 +311,7 @@ Always use the latest module utilities. The current version is named in Documentation/Changes. Some old versions of insmod are not capable of setting the driver-Ids correctly. - + 3. Lowlevel-driver configuration. Configuration depends on how the drivers are built. See the @@ -310,7 +320,7 @@ 4. Device-inodes The major and minor numbers and their names are described in - Documentation/devices.txt. The major-numbers are: + Documentation/devices.txt. The major numbers are: 43 for the ISDN-tty's. 44 for the ISDN-callout-tty's. @@ -350,45 +360,64 @@ g) Set the timeout for hang-up: isdnctrl huptimeout isdn0 - h) additionally you may activate charge-hang-up (= Hang up before + h) additionally you may activate charge-hang-up (= Hang up before next charge-info, this only works, if your isdn-provider transmits the charge-info during and after the connection): isdnctrl chargehup isdn0 on - i) Setup the interface with ifconfig as usual, and set a route to it. + i) Set the dial mode of the interface: + isdnctrl dialmode isdn0 auto + "off" means that you (or the system) cannot make any connection + (neither incoming or outgoing connections are possible). Use + this if you want to be sure that no connections will be made. + "auto" means that the interface is in auto-dial mode, and will + attempt to make a connection whenever a network data packet needs + the interface's link. Note that this can cause unexpected dialouts, + and lead to a high phone bill! Some daemons or other pc's that use + this interface can cause this. + Incoming connections are also possible. + "manual" is a dial mode created to prevent the unexpected dialouts. + In this mode, the interface will never make any connections on its + own. You must explicitly initiate a connection with "isdnctrl dial + isdn0". However, after an idle time of no traffic as configured for + the huptimeout value with isdnctrl, the connection _will_ be ended. + If you don't want any automatic hangup, set the huptimeout value to 0. + "manual" is the default. - j) (optional) If you run X11 and have Tcl/Tk-wish Version 4.0, you can use + j) Setup the interface with ifconfig as usual, and set a route to it. + + k) (optional) If you run X11 and have Tcl/Tk-wish version 4.0, you can use the script tools/tcltk/isdnmon. You can add actions for line-status changes. See the comments at the beginning of the script for how to do that. There are other tty-based tools in the tools-subdirectory contributed by Michael Knigge (imon), Volker Götz (imontty) and Andreas Kool (isdnmon). - k) For initial testing, you can set the verbose-level to 2 (default: 0). + l) For initial testing, you can set the verbose-level to 2 (default: 0). Then all incoming calls are logged, even if they are not addressed to one of the configured net-interfaces: isdnctrl verbose 2 - Now you are ready! A ping to the set address should now result in a - dial-out (look at syslog kernel-messages). - The phone-numbers and EAZs can be assigned at any time with isdnctrl. + Now you are ready! A ping to the set address should now result in an + automatic dial-out (look at syslog kernel-messages). + The phone numbers and EAZs can be assigned at any time with isdnctrl. You can add as many interfaces as you like with addif following the - directions above. Of course, there may be some limitations. But we have - tested as many as 20 interfaces without any problem. However, if you - don't give an interface name to addif, the kernel will assign a name + directions above. Of course, there may be some limitations. But we have + tested as many as 20 interfaces without any problem. However, if you + don't give an interface name to addif, the kernel will assign a name which starts with "eth". The number of "eth"-interfaces is limited by the kernel. 5. Additional options for isdnctrl: - "isdnctrl secure on" + "isdnctrl secure on" Only incoming calls, for which the caller-id is listed in the access list of the interface are accepted. You can add caller-id's With the command "isdnctrl addphone in " Euro-ISDN does not transmit the leading '0' of the caller-id for an incoming call, therefore you should configure it accordingly. If the real number for the dialout e.g. is "09311234567" the number - to configure here is "9311234567". The pattern-match function + to configure here is "9311234567". The pattern-match function works similar to the shell mechanism. ? one arbitrary digit @@ -398,23 +427,23 @@ a '^' as the first character in a list inverts the list - "isdnctrl secure off" + "isdnctrl secure off" Switch off secure operation (default). - "isdnctrl ihup [on|off]" + "isdnctrl ihup [on|off]" Switch the hang-up-timer for incoming calls on or off. - "isdnctrl eaz " + "isdnctrl eaz " Returns the EAZ of an interface. - "isdnctrl delphone in|out " + "isdnctrl delphone in|out " Deletes a number from one of the access-lists of the interface. - "isdnctrl delif " + "isdnctrl delif " Removes the interface (and possible slaves) from the kernel. (You have to unregister it with "ifconfig down" before). - "isdnctrl callback [on|off]" + "isdnctrl callback [on|off]" Switches an interface to callback-mode. In this mode, an incoming call will be rejected and after this the remote-station will be called. If you test this feature by using ping, some routers will re-dial very @@ -435,14 +464,14 @@ only while an interface is down. At the moment the following values are supported: - + rawip (Default) Selects raw-IP-encapsulation. This means, MAC-headers - are stripped off. + are stripped off. ip IP with type-field. Same as IP but the type-field of the MAC-header is preserved. x25iface X.25 interface encapsulation (first byte semantics as defined in - ../networking/x25-iface.txt). Use this for running the linux - X.25 network protocol stack (AF_X25 sockets) on top of isdn. + ../networking/x25-iface.txt). Use this for running the linux + X.25 network protocol stack (AF_X25 sockets) on top of isdn. cisco-h A special-mode for communicating with a Cisco, which is configured to do "hdlc" ethernet No stripping. Packets are sent with full MAC-header. @@ -454,7 +483,7 @@ NOTE: x25iface encapsulation is currently experimental. Please - read README.x25 for further details + read README.x25 for further details Watching packets, using standard-tcpdump will fail for all encapsulations @@ -462,16 +491,16 @@ without MAC-header. A patch for tcpdump is included in the utility-package mentioned above. - "isdnctrl l2_prot " - Selects a layer-2-protocol. + "isdnctrl l2_prot " + Selects a layer-2-protocol. (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available. With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be possible too. See README.x25 for x25 related l2 protocols.) - isdnctrl l3_prot + isdnctrl l3_prot The same for layer-3. (At the moment only "trans" is allowed) - "isdnctrl list " + "isdnctrl list " Shows all parameters of an interface and the charge-info. Try "all" as the interface name. @@ -479,13 +508,13 @@ Forces hangup of an interface. "isdnctrl bind , [exclusive]" - If you are using more than one ISDN-Card, it is sometimes necessary to - dial out using a specific Card or even preserve a specific Channel for - Dialout of a specific net-interface. This can be done with the above + If you are using more than one ISDN card, it is sometimes necessary to + dial out using a specific card or even preserve a specific channel for + dialout of a specific net-interface. This can be done with the above command. Replace by whatever you assigned while loading the - module. The is counting from zero. The upper Limit - depends on the card used. At the Moment no card supports more than - 2 Channels, so the upper limit is one. + module. The is counted from zero. The upper limit + depends on the card used. At the moment no card supports more than + 2 channels, so the upper limit is one. "isdnctrl unbind " unbinds a previously bound interface. @@ -494,10 +523,10 @@ If switched on, isdn4linux replies a REJECT to incoming calls, it cannot match to any configured interface. If switched off, nothing happens in this case. - You normally should NOT enable this feature, if the ISDN-adaptor is not - the only device, connected to the S0-bus. Otherwise it could happen, that + You normally should NOT enable this feature, if the ISDN adapter is not + the only device connected to the S0-bus. Otherwise it could happen that isdn4linux rejects an incoming call, which belongs to another device on - the bus. + the bus. "isdnctrl addslave Creates a slave interface for channel-bundling. Slave interfaces are @@ -539,9 +568,9 @@ isdnctrl eaz isdn1 4 # listen on 12345674(1tr6) only. ... isdnctrl eaz isdn2 987654 # listen on 987654(euro) only. - + Same scheme is used with AT&E... at the tty's. - + 6. If you want to write a new low-level-driver, you are welcome. The interface to the link-level-module is described in the file INTERFACE. If the interface should be expanded for any reason, don't do it diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.2.10/linux/Documentation/isdn/README.HiSax Tue Apr 28 14:22:04 1998 +++ linux/Documentation/isdn/README.HiSax Mon Aug 9 12:04:38 1999 @@ -1,7 +1,7 @@ HiSax is a Linux hardware-level driver for passive ISDN cards with Siemens chipset (ISAC_S 2085/2086/2186, HSCX SAB 82525). It is based on the Teles driver from Jan den Ouden. -It is meant to be used with isdn4linux, an ISDN link-level module for Linux +It is meant to be used with isdn4linux, an ISDN link-level module for Linux written by Fritz Elfert. This program is free software; you can redistribute it and/or modify @@ -25,31 +25,50 @@ Teles 8.0/16.0/16.3 and compatible ones Teles 16.3c Teles S0/PCMCIA -Creatix PnP S0 +Teles PCI +Teles S0Box +Creatix S0Box +Creatix PnP S0 Compaq ISDN S0 ISA card AVM A1 (Fritz, Teledat 150) +AVM Fritz PCMCIA +AVM Fritz PnP +AVM Fritz PCI ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8 ELSA Quickstep 1000 ELSA Quickstep 1000PCI ELSA Quickstep 3000 (same settings as QS1000) +ELSA Quickstep 3000PCI ELSA PCMCIA ITK ix1-micro Rev.2 Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version) +Eicon.Diehl Diva 2.01 ISA and PCI Eicon.Diehl Diva Piccola ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D) Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter) +PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink) HFC-2BS0 based cards (TeleInt SA1) -Sedlbauer Speed Card (Speed Win, Teledat 100) -Sedlbauer Speed Star (PCMCIA) +Sedlbauer Speed Card (Speed Win, Teledat 100, PCI, Fax+) +Sedlbauer Speed Star/Speed Star2 (PCMCIA) +Sedlbauer ISDN-Controller PC/104 USR Sportster internal TA (compatible Stollmann tina-pp V3) -ith Kommunikationstechnik GmbH MIC 16 ISA card +ith Kommunikationstechnik GmbH MIC 16 ISA card Traverse Technologie NETjet PCI S0 card Dr. Neuhaus Niccy PnP/PCI +Siemens I-Surf +ACER P10 +HST Saphir +Berkom Telekom A4T +Scitel Quadro +Gazel ISDN cards +HFC-PCI based cards Note: PCF, PCF-Pro: up to now, only the ISDN part is supported PCC-8: not tested yet Teles PCMCIA is EXPERIMENTAL Teles 16.3c is EXPERIMENTAL + Teles PCI is EXPERIMENTAL + Teles S0Box is EXPERIMENTAL Eicon.Diehl Diva U interface not tested If you know other passive cards with the Siemens chipset, please let me know. @@ -113,7 +132,7 @@ correct one during kernel config. Valid values are "1" for German 1TR6, "2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel). -The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying +The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying the I/O addresses of the ISAC and HSCX chips, respectively. Card types: @@ -135,24 +154,37 @@ 11 Eicon.Diehl Diva ISA PnP irq, io 11 Eicon.Diehl Diva PCI no parameter 12 ASUS COM ISDNLink irq, io (from isapnp setup) - 13 HFC-2BS0 based cards irq, io + 13 HFC-2BS0 based cards irq, io 14 Teles 16.3c PnP irq, io - 15 Sedlbauer Speed Card irq, io - 16 USR Sportster internal irq, io - 17 MIC card irq, io + 15 Sedlbauer Speed Card irq, io + 15 Sedlbauer PC/104 irq, io + 15 Sedlbauer Speed PCI no parameter + 16 USR Sportster internal irq, io + 17 MIC card irq, io 18 ELSA Quickstep 1000PCI no parameter 19 Compaq ISDN S0 ISA card irq, io0, io1, io (from isapnp setup io=IO2) 20 NETjet PCI card no parameter + 21 Teles PCI no parameter 22 Sedlbauer Speed Star (PCMCIA) irq, io (set with card manager) 24 Dr. Neuhaus Niccy PnP irq, io0, io1 (from isapnp setup) 24 Dr. Neuhaus Niccy PCI no parameter + 25 Teles S0Box irq, io (of the used lpt port) + 26 AVM A1 PCMCIA (Fritz!) irq, io (set with card manager) + 27 AVM PnP (Fritz!PnP) irq, io (from isapnp setup) + 27 AVM PCI (Fritz!PCI) no parameter + 28 Sedlbauer Speed Fax+ irq, io (from isapnp setup) + 29 Siemens I-Surf irq, io, memory (from isapnp setup) + 30 ACER P10 irq, io (from isapnp setup) + 31 HST Saphir irq, io + 32 Telekom A4T none + 33 Scitel Quadro subcontroller (4*S0, subctrl 1...4) + 34 Gazel ISDN cards (ISA) irq,io + 34 Gazel ISDN cards (PCI) none + 35 HFC 2BDS0 PCI none - -At the moment IRQ sharing is not possible. Please make sure that your IRQ -is free and enabled for ISA use. -Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for -enabling at the moment, then boot linux with loadlin. +At the moment IRQ sharing is only possible with PCI cards. Please make sure +that your IRQ is free and enabled for ISA use. Examples for module loading @@ -169,7 +201,7 @@ 4. Any ELSA PCC/PCF card, Euro ISDN modprobe hisax type=6 protocol=2 -5. Teles 16.3 PnP, Euro ISDN, with isapnp configured +5. Teles 16.3 PnP, Euro ISDN, with isapnp configured isapnp config: (INT 0 (IRQ 10 (MODE +E))) (IO 0 (BASE 0x0580)) (IO 1 (BASE 0x0180)) @@ -210,8 +242,8 @@ Note: the ID string must start with an alphabetical character! Card types: - - type + +type 1 Teles 16.0 pa=irq pb=membase pc=iobase 2 Teles 8.0 pa=irq pb=membase 3 Teles 16.3 pa=irq pb=iobase @@ -227,22 +259,40 @@ 12 ASUS COM ISDNLink ONLY WORKS AS A MODULE ! 13 HFC-2BS0 based cards pa=irq pb=io 14 Teles 16.3c PnP ONLY WORKS AS A MODULE ! - 15 Sedlbauer Speed Card pa=irq pb=io (Speed Win only as module !) + 15 Sedlbauer Speed Card pa=irq pb=io (Speed Win only as module !) + 15 Sedlbauer PC/104 pa=irq pb=io + 15 Sedlbauer Speed PCI no parameter 16 USR Sportster internal pa=irq pb=io 17 MIC card pa=irq pb=io 18 ELSA Quickstep 1000PCI no parameter 19 Compaq ISDN S0 ISA card ONLY WORKS AS A MODULE ! 20 NETjet PCI card no parameter - 21 Sedlbauer Speed Star (PCMCIA) pa=irq, pb=io (set with card manager) + 21 Teles PCI no parameter + 22 Sedlbauer Speed Star (PCMCIA) pa=irq, pb=io (set with card manager) + 24 Dr. Neuhaus Niccy PnP ONLY WORKS AS A MODULE ! + 24 Dr. Neuhaus Niccy PCI no parameter + 25 Teles S0Box pa=irq, pb=io (of the used lpt port) + 26 AVM A1 PCMCIA (Fritz!) pa=irq, pb=io (set with card manager) + 27 AVM PnP (Fritz!PnP) ONLY WORKS AS A MODULE ! + 27 AVM PCI (Fritz!PCI) no parameter + 28 Sedlbauer Speed Fax+ ONLY WORKS AS A MODULE ! + 29 Siemens I-Surf ONLY WORKS AS A MODULE ! + 30 ACER P10 ONLY WORKS AS A MODULE ! + 31 HST Saphir pa=irq, pb=io + 32 Telekom A4T no parameter + 33 Scitel Quadro subcontroller (4*S0, subctrl 1...4) + 34 Gazel ISDN cards (ISA) pa=irq, pb=io + 34 Gazel ISDN cards (PCI) no parameter + 35 HFC 2BDS0 PCI no parameter Running the driver ------------------ -When you insmod isdn.o and hisax.o (or with the in-kernel version, during +When you insmod isdn.o and hisax.o (or with the in-kernel version, during boot time), a few lines should appear in your syslog. Look for something like: Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards -Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.1 +Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.9 Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8 Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0) @@ -257,7 +307,7 @@ Apr 13 21:01:59 kke01 kernel: HiSax: 2 channels added This means that the card is ready for use. -Cabling problems or line-downs are not detected, and only some ELSA cards can +Cabling problems or line-downs are not detected, and only some ELSA cards can detect the S0 power. Remember that, according to the new strategy for accessing low-level drivers @@ -265,8 +315,7 @@ insmod: Simply append hisax_id= to the insmod command line. This string MUST NOT start with a digit or a small 'x'! -At this point you can run a 'cat /dev/isdnctrl0' and view debugging -messages. +At this point you can run a 'cat /dev/isdnctrl0' and view debugging messages. At the moment, debugging messages are enabled with the hisaxctrl tool: @@ -283,28 +332,35 @@ With DebugCmd set to 1: - 1 Link-level <--> hardware-level communication - 2 Top state machine - 4 D-Channel Q.931 (call control messages) - 8 D-Channel Q.921 - 16 B-Channel X.75 - 32 D-Channel l2 - 64 B-Channel l2 - 128 D-Channel link state debugging - 256 B-Channel link state debugging - 512 TEI debug - 1024 LOCK debug in callc.c - 2048 More paranoid debug in callc.c (not for normal use) + 0x0001 Link-level <--> hardware-level communication + 0x0002 Top state machine + 0x0004 D-Channel Frames for isdnlog + 0x0008 D-Channel Q.921 + 0x0010 B-Channel X.75 + 0x0020 D-Channel l2 + 0x0040 B-Channel l2 + 0x0080 D-Channel link state debugging + 0x0100 B-Channel link state debugging + 0x0200 TEI debug + 0x0400 LOCK debug in callc.c + 0x0800 More paranoid debug in callc.c (not for normal use) + 0x1000 D-Channel l1 state debugging + 0x2000 B-Channel l1 state debugging With DebugCmd set to 11: - 1 Warnings (default: on) - 2 IRQ status - 4 ISAC - 8 ISAC FIFO - 16 HSCX - 32 HSCX FIFO (attention: full B-Channel output!) - 64 D-Channel LAPD frame types + 0x0001 Warnings (default: on) + 0x0002 IRQ status + 0x0004 ISAC + 0x0008 ISAC FIFO + 0x0010 HSCX + 0x0020 HSCX FIFO (attention: full B-Channel output!) + 0x0040 D-Channel LAPD frame types + 0x0080 IPAC debug + 0x0100 HFC receive debug + 0x0200 ISAC monitor debug + 0x0400 D-Channel frames for isdnlog (set with 1 0x4 too) + 0x0800 D-Channel message verbose With DebugCmd set to 13: @@ -317,27 +373,39 @@ Because of some obscure problems with some switch equipment, the delay between the CONNECT message and sending the first data on the B-channel is now -configurable with +configurable with hisaxctrl 2 in ms Value between 50 and 800 ms is recommended. +Downloading Firmware +-------------------- +At the moment, the Sedlbauer speed fax+ is the only card, which +needs to download firmware. +The firmware is downloaded with the hisaxctrl tool: + + hisaxctrl 9 + + default is HiSax, if you didn't specify one, + +where is the filename of the firmware file. + +For example, 'hisaxctrl HiSax 9 ISAR.BIN' downloads the firmware for +ISAR based cards (like the Sedlbauer speed fax+). Warning ------- -HiSax is a work in progress and may crash your machine. It has not been -certified and therefore operation on your PTT's ISDN network is probably -illegal. - +HiSax is a work in progress and may crash your machine. +For certification look at HiSax.cert file. Limitations ----------- At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines. -For leased lines see appendix. +For leased lines see appendix. -Bugs +Bugs ---- -If you find any, please let me know. +If you find any, please let me know. Thanks @@ -354,8 +422,10 @@ Stephan von Krawczynski Juergen Quade for the Leased Line part Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE), for ELSA PCMCIA support + Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff + Ton van Rosmalen for Teles PCI and more people who are hunting bugs. (If I forgot somebody, please - send me a mail). + send me a mail). Firma ELSA GmbH Firma Eicon.Diehl GmbH @@ -364,20 +434,23 @@ Firma S.u.S.E Firma ith Kommunikationstechnik GmbH Firma Traverse Technologie Australia - + Firma Medusa GmbH (www.medusa.de). + Firma Quant-X Austria for sponsoring a DEC Alpha board+CPU + Firma Cologne Chip Designs GmbH + My girl friend and partner in life Ute for her patience with me. Enjoy, -Karsten Keil -keil@temic-ech.spacenet.de +Karsten Keil +keil@isdn4linux.de Appendix: Teles PCMCIA driver ----------------------------- -See +See http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html for instructions. @@ -451,7 +524,7 @@ /sbin/isdnctrl l2_prot isdn0 hdlc # Attention you must not set an outgoing number !!! This won't work !!! # The incomming number is LEASED0 for the first card, LEASED1 for the - # second and so on. + # second and so on. /sbin/isdnctrl addphone isdn0 in LEASED0 # Here is no need to bind the channel. c) in case the remote partner is a CISCO: @@ -461,11 +534,11 @@ e) set the routes /sbin/route add -host ${REMOTE_IP} isdn0 /sbin/route add default gw ${REMOTE_IP} - f) switch the card into leased mode for each used B-channel + f) switch the card into leased mode for each used B-channel /sbin/hisaxctrl HiSax 5 1 - + Remarks: -a) If you have a CISCO don't forget to switch off the KEEP ALIVE option! +a) Use state of the art isdn4k-utils Here an example script: #!/bin/sh @@ -517,6 +590,7 @@ /sbin/isdnctrl encap isdn0s cisco-h fi fi + /sbin/isdnctrl dialmode isdn0 manual # configure tcp/ip /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP} /sbin/route add -host ${REMOTE_IP} isdn0 @@ -526,6 +600,7 @@ /sbin/hisaxctrl HiSax 5 1 if [ ${I4L_LEASED_128K} = "yes" ]; then # B-CHANNEL 2 + sleep 10; /* Wait for master */ /sbin/hisaxctrl HiSax 5 2 fi ;; @@ -547,4 +622,3 @@ exit 1 esac exit 0 - diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.act2000 linux/Documentation/isdn/README.act2000 --- v2.2.10/linux/Documentation/isdn/README.act2000 Thu Jan 7 08:41:54 1999 +++ linux/Documentation/isdn/README.act2000 Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -$Id: README.act2000,v 1.1 1997/09/24 23:50:16 fritz Exp $ +$Id: README.act2000,v 1.2 1998/04/29 19:49:06 he Exp $ This document describes the ACT2000 driver for the IBM Active 2000 ISDN card. @@ -7,7 +7,7 @@ Version. Currently, only the ISA-Bus version of the card is supported. However MCA and PCMCIA will follow soon. -The ISA-Bus Version uses 8 IO-ports. The base port address has to be set +The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set manually using the DIP switches. Setting up the DIP switches for the IBM Active 2000 ISDN card: diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.audio linux/Documentation/isdn/README.audio --- v2.2.10/linux/Documentation/isdn/README.audio Tue Apr 28 14:22:04 1998 +++ linux/Documentation/isdn/README.audio Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -$Id: README.audio,v 1.5 1997/02/23 23:53:46 fritz Exp $ +$Id: README.audio,v 1.8 1999/07/11 17:17:29 armin Exp $ ISDN subsystem for Linux. Description of audio mode. @@ -50,13 +50,25 @@ the application. See below for data format AT+VSD=x,y Set silence-detection parameters. - NO EFFECT, supported for compatibility - only. Possible parameters: - x = 0 ... 31 - y = 0 ... 255 + Possible parameters: + x = 0 ... 31 sensitivity threshold level. + (default 0 , deactivated) + y = 0 ... 255 range of interval in units + of 0.1 second. (default 70) AT+VSD=? Report possible parameters. AT+VSD? Show current parameters. + AT+VDD=x,y Set DTMF-detection parameters. + Only possible if online and during this connection. + Possible parameters: + x = 0 ... 15 sensitivity threshold level. + (default 0 , I4L soft-decode) + (1-15 soft-decode off, hardware on) + y = 0 ... 255 tone duration in units of 5ms. + Not for I4L soft decode (default 8, 40ms) + AT+VDD=? Report possible parameters. + AT+VDD? Show current parameters. + AT+VSM=x Select audio data format. Possible parameters: 2 = ADPCM-2 @@ -102,13 +114,14 @@ C Touchtone "C" received. D Touchtone "D" received. + q quiet. Silence detected after non-silence. + s silence. Silence detected from the + start of recording. + Currently unsupported DLE sequences: c FAX calling tone received. b busy tone received. - q quiet. Silence detected after non-silence. - s silence. Silence detected from the - start of recording. Audio playback. diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.avmb1 linux/Documentation/isdn/README.avmb1 --- v2.2.10/linux/Documentation/isdn/README.avmb1 Tue Apr 28 14:22:04 1998 +++ linux/Documentation/isdn/README.avmb1 Mon Aug 9 12:04:38 1999 @@ -1,10 +1,22 @@ +Driver for active AVM Controller. + The driver provides a kernel capi2.0 Interface (kernelcapi) and on top of this a User-Level-CAPI2.0-interface (capi) and a driver to connect isdn4linux with CAPI2.0 (capidrv). +The lowlevel interface can be used to implement a CAPI2.0 +also for passive cards since July 1999. -The Author can be reached at calle@calle.in-berlin.de -The command avmcapictrl is part of the isdn4linux-utils. -t4-files can be found at ftp.avm.de. +The author can be reached at calle@calle.in-berlin.de. +The command avmcapictrl is part of the isdn4k-utils. +t4-files can be found at ftp://ftp.avm.de/cardware/b1/linux/firmware + +Currently supported cards: + B1 ISA (all versions) + B1 PCI + T1/T1B (HEMA card) + M1 + M2 + B1 PCMCIA Installing ---------- @@ -26,32 +38,145 @@ AVM GmbH provides several t4-files for the different D-channel protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn. -If you do not compile the driver as modules, you have to add the -card(s) and load them after booting: - -avmcapictrl add 0x150 15 -avmcapictrl load /lib/isdn/b1.t4 1 - -if you configure as modules you have two possibilities: +if you configure as modules load the modules this way: insmod /lib/modules/current/misc/capiutil.o -insmod /lib/modules/current/misc/kernelcapi.o portbase=0x150 irq=15 +insmod /lib/modules/current/misc/b1.o +insmod /lib/modules/current/misc/kernelcapi.o insmod /lib/modules/current/misc/capidrv.o insmod /lib/modules/current/misc/capi.o -avmcapictrl load /lib/isdn/b1.t4 -or +if you have an B1-PCI card load the module b1pci.o +insmod /lib/modules/current/misc/b1pci.o +and load the firmware with +avmcapictrl load /lib/isdn/b1.t4 1 -insmod /lib/modules/current/misc/capiutil.o -insmod /lib/modules/current/misc/kernelcapi.o -insmod /lib/modules/current/misc/capidrv.o -insmod /lib/modules/current/misc/capi.o +if you have an B1-ISA card load the module b1isa.o +and add the card by calling avmcapictrl add 0x150 15 -avmcapictrl load /lib/isdn/b1.t4 +and load the firmware by calling +avmcapictrl load /lib/isdn/b1.t4 1 + +if you have an T1-ISA card load the module t1isa.o +and add the card by calling +avmcapictrl add 0x450 15 T1 0 +and load the firmware by calling +avmcapictrl load /lib/isdn/t1.t4 1 + +if you have an PCMCIA card (B1/M1/M2) load the module b1pcmcia.o +before you insert the card. + +Leased Lines with B1 +-------------------- +Init card and load firmware. +For an D64S use "FV: 1" as phone number +For an D64S2 use "FV: 1" and "FV: 2" for multilink +or "FV: 1,2" to use CAPI channel bundling. + +/proc-Interface +----------------- + +/proc/capi: + dr-xr-xr-x 2 root root 0 Jul 1 14:03 . + dr-xr-xr-x 82 root root 0 Jun 30 19:08 .. + -r--r--r-- 1 root root 0 Jul 1 14:03 applications + -r--r--r-- 1 root root 0 Jul 1 14:03 applstats + -r--r--r-- 1 root root 0 Jul 1 14:03 capi20 + -r--r--r-- 1 root root 0 Jul 1 14:03 capidrv + -r--r--r-- 1 root root 0 Jul 1 14:03 controller + -r--r--r-- 1 root root 0 Jul 1 14:03 contrstats + -r--r--r-- 1 root root 0 Jul 1 14:03 driver + -r--r--r-- 1 root root 0 Jul 1 14:03 ncci + -r--r--r-- 1 root root 0 Jul 1 14:03 users + +/proc/capi/applications: + applid level3cnt datablkcnt datablklen ncci-cnt recvqueuelen + level3cnt: capi_register parameter + datablkcnt: capi_register parameter + ncci-cnt: current number of nccis (connections) + recvqueuelen: number of messages on receive queue + for example: +1 -2 16 2048 1 0 +2 2 7 2048 1 0 + +/proc/capi/applstats: + applid recvctlmsg nrecvdatamsg nsentctlmsg nsentdatamsg + recvctlmsg: capi messages received without DATA_B3_IND + recvdatamsg: capi DATA_B3_IND received + sentctlmsg: capi messages sent without DATA_B3_REQ + sentdatamsg: capi DATA_B3_REQ sent + for example: +1 2057 1699 1721 1699 + +/proc/capi/capi20: statistics of capi.o (/dev/capi20) + minor nopen nrecvdropmsg nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg + minor: minor device number of capi device + nopen: number of calls to devices open + nrecvdropmsg: capi messages dropped (messages in recvqueue in close) + nrecvctlmsg: capi messages received without DATA_B3_IND + nrecvdatamsg: capi DATA_B3_IND received + nsentctlmsg: capi messages sent without DATA_B3_REQ + nsentdatamsg: capi DATA_B3_REQ sent + + for example: +1 2 18 0 16 2 + +/proc/capi/capidrv: statistics of capidrv.o (capi messages) + nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg + nrecvctlmsg: capi messages received without DATA_B3_IND + nrecvdatamsg: capi DATA_B3_IND received + nsentctlmsg: capi messages sent without DATA_B3_REQ + nsentdatamsg: capi DATA_B3_REQ sent + for example: +2780 2226 2256 2226 + +/proc/capi/controller: + controller drivername state cardname controllerinfo + for example: +1 b1pci running b1pci-e000 B1 3.07-01 0xe000 19 +2 t1isa running t1isa-450 B1 3.07-01 0x450 11 0 +3 b1pcmcia running m2-150 B1 3.07-01 0x150 5 + +/proc/capi/contrstats: + controller nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg + nrecvctlmsg: capi messages received without DATA_B3_IND + nrecvdatamsg: capi DATA_B3_IND received + nsentctlmsg: capi messages sent without DATA_B3_REQ + nsentdatamsg: capi DATA_B3_REQ sent + for example: +1 2845 2272 2310 2274 +2 2 0 2 0 +3 2 0 2 0 + +/proc/capi/driver: + drivername ncontroller + for example: +b1pci 1 +t1isa 1 +b1pcmcia 1 +b1isa 0 + +/proc/capi/ncci: + apllid ncci winsize sendwindow + for example: +1 0x10101 8 0 + +/proc/capi/users: kernelmodules that use the kernelcapi. + name + for example: +capidrv +capi20 Questions --------- -Check out the FAQ (ftp.franken.de). +Check out the FAQ (ftp.franken.de) or subscribe to the +linux-avmb1@calle.in-berlin.de mailing list by sending +a mail to majordomo@calle.in-berlin.de with +subscribe linux-avmb1 +in the body. + +German documentaion and several scripts can be found at +ftp://ftp.avm.de/cardware/b1/linux/ Bugs ---- diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.concap linux/Documentation/isdn/README.concap --- v2.2.10/linux/Documentation/isdn/README.concap Thu Jan 7 08:41:54 1999 +++ linux/Documentation/isdn/README.concap Mon Aug 9 12:04:38 1999 @@ -256,3 +256,4 @@ of the concap interface when a trivial concap protocol is used. Nevertheless, the device remains able to support encapsulation protocol configuration. + diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon --- v2.2.10/linux/Documentation/isdn/README.eicon Wed Dec 31 16:00:00 1969 +++ linux/Documentation/isdn/README.eicon Mon Aug 9 12:04:38 1999 @@ -0,0 +1,88 @@ +$Id: README.eicon,v 1.4 1999/07/11 17:17:30 armin Exp $ + +(c) 1999 Cytronics & Melware + +This document describes the eicon driver for the +Eicon.Diehl active ISDN cards. + +It is meant to be used with isdn4linux, an ISDN link-level module for Linux. + + 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. + + + +Supported Cards +--------------- + +- S-Card ISA +- SX-Card ISA +- SXn-Card ISA +- SCOM-Card ISA +- Quadro-Card ISA +- S2M-Card ISA +- DIVA Server BRI/PCI 2M +- DIVA Server PRI/PCI 2M (9M 23M 30M) + (Only analog modem functions of the DSPs are currently implemented) + +ISDN D-Channel Protocols +------------------------ + +- ETSI (Euro-DSS1) +- 1TR6 (German ISDN) *not testet* + + + +You can load the module simply by using the insmod or modprobe function : + + insmod eicon [id=driverid] [membase=] [irq=] + + +The module will automatically probe the PCI-cards. If the id-options +is omitted, the driver will assume 'eicon0' for the first pci card and +increases the digit with each further card. With a given driver-id +the module appends a number starting with '0'. + +For ISA-cards you have to specify membase, irq and id. If id or +membase is missing/invalid, the driver will not be loaded except +PCI-cards were found. Additional ISA-cards and irq/membase changes +can be done with the eiconctrl utility. + +After loading the module, you have to download the protocol and +dsp-code by using the eiconctrl utility of isdn4k-utils. + + +Example for loading and starting a BRI card with E-DSS1 Protocol. + + eiconctrl [-d DriverId] load etsi + + +Example for loading and starting a PRI card with E-DSS1 Protocol. + + eiconctrl [-d DriverId] load etsi -s2 -n + + +Details about using the eiconctrl utility are in 'man eiconctrl' +or will be printed by starting eiconctrl without any parameters. + + + +Any reports about bugs, errors and even wishes are welcome. + + +Have fun ! + +Armin Schindler +mac@melware.de +http://www.melware.de diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn --- v2.2.10/linux/Documentation/isdn/README.icn Tue Apr 28 14:22:04 1998 +++ linux/Documentation/isdn/README.icn Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -$Id: README.icn,v 1.5 1997/04/23 18:55:55 fritz Exp $ +$Id: README.icn,v 1.6 1998/04/29 19:49:08 he Exp $ You can get the ICN-ISDN-card from: diff -u --recursive --new-file v2.2.10/linux/Documentation/isdn/README.x25 linux/Documentation/isdn/README.x25 --- v2.2.10/linux/Documentation/isdn/README.x25 Thu Jan 7 08:41:54 1999 +++ linux/Documentation/isdn/README.x25 Mon Aug 9 12:04:38 1999 @@ -1,29 +1,24 @@ - -X25 support within isdn4linux - - -This is experimental code and should be used with linux version 2.1.72. -or later. Use it completely at your own risk. - + +X.25 support within isdn4linux +============================== +This is alpha/beta test code. Use it completely at your own risk. As new versions appear, the stuff described here might suddenly change or become invalid without notice. Keep in mind: -You are using an experimental kernel (2.1.x series) with an experimental -x25 protocol implementation and experimental x25-on-top-of-isdn extensions. -Thus, be prepared to face problems related therefrom. +You are using several new parts of the 2.2.x kernel series which +have not been tested in a large scale. Therefore, you might encounter +more bugs as usual. -- If you connect to an x25 neighbour not operated by yourself, ASK the +- If you connect to an X.25 neighbour not operated by yourself, ASK the other side first. Be prepared that bugs in the protocol implementation - might result in problems (even crashing the peer, however such ugly events - should only happen if your peer's protocol implementation has serious bugs). + might result in problems. - This implementation has never wiped out my whole hard disk yet. But as - this is experimental code, don't blame me if that happened to you. Take - appropriate actions (such as backing up important data) before - trying this code. + this is experimental code, don't blame me if that happened to you. + Backing up important data will never harm. - Monitor your isdn connections while using this software. This should prevent you from undesired phone bills in case of driver problems. @@ -32,7 +27,7 @@ How to configure the kernel - +=========================== The ITU-T (former CCITT) X.25 network protocol layer has been implemented in the Linux source tree since version 2.1.16. The isdn subsystem might be @@ -48,32 +43,33 @@ compilation. You currently also need to enable "Prompt for development and/or incomplete code/drivers" from the "Code maturity level options" menu. For the x25trace utility to work -you also need to enable "Packet socket" (I recommend to choose "y", -not "m" for testing) from the networking options. +you also need to enable "Packet socket". +For local testing it is also recommended to enable the isdnloop driver +from the isdn subsystem's configuration menu. -For testing you should also select the isdnloop driver from the -isdn subsystem's configuration menu. +For testing, it is recommended that all isdn drivers and the X.25 PLP +protocol are compiled as loadable modules. Like this, you can recover +from certain errors by simply unloading and reloading the modules. What's it for? How to use it? +============================= - -X25 on top of isdn might be useful with two different scenarios: +X.25 on top of isdn might be useful with two different scenarios: - You might want to access a public X.25 data network from your Linux box. You can use i4l if you were physically connected to the X.25 switch - by an ISDN line (leased line as well as dial up connection should work, - but connecting to x.25 network switches is currently untested. Testing - needs to be done by somebody with access to such a switch.) - -- Or you might want to operate certain ISDN teleservices on - your linux box. A lot of those teleservices run on top of the ISO-8208 - network layer protocol. ISO-8208 is essentially the same as ITU-T X.25. + by an ISDN line (leased line as well as dial up connection should work) + +- Or you might want to operate certain ISDN teleservices on your linux + box. A lot of those teleservices run on top of the ISO-8208 + (DTE-DTE mode) network layer protocol. ISO-8208 is essentially the + same as ITU-T X.25. - Popular candidates of such teleservices are EUROFILE transfer or any - teleservice applying ITU-T recommendation T.90 (i.e., AFAIK, G4 Fax). + Popular candidates of such teleservices are EUROfile transfer or any + teleservice applying ITU-T recommendation T.90. To use the X.25 protocol on top of isdn, just create an isdn network interface as usual, configure your own and/or peer's ISDN numbers, @@ -81,21 +77,18 @@ isdnctrl encap x25iface. -Once encap is set like this, the device can be used by the x25 packet layer. +Once encap is set like this, the device can be used by the X.25 packet layer. -All the stuff needed for x25 is implemented inside the isdn link +All the stuff needed for X.25 is implemented inside the isdn link level (mainly isdn_net.c and some new source files). Thus, it should -work with every existing HL driver. I was able to successfully open x25 +work with every existing HL driver. I was able to successfully open X.25 connections on top of the isdnloop driver and the hisax driver. "x25iface"-encapsulation bypasses demand dialing. Dialing will be -initiated when the upper (x25 packet) layer requests the lapb datalink to -be established. But hangup timeout is still active. The connection -will not automatically be re-established by the isdn_net module -itself when new data arrives after the hangup timeout. But -the x25 network code will re-establish the datalink connection -(resulting in re-dialing and an x25 protocol reset) when new data is -to be transmitted. (This currently does not work properly with the -isdnloop driver, see "known problems" below) +initiated when the upper (X.25 packet) layer requests the lapb datalink to +be established. But hangup timeout is still active. Whenever a hangup +occurs, all existing X.25 connections on that link will be cleared +It is recommended to use sufficiently large hangup-timeouts for the +isdn interfaces. In order to set up a conforming protocol stack you also need to @@ -114,104 +107,64 @@ isdnctrl l2_prot x25dce However, x25dte or x25dce is currently not supported by any real HL -level driver. The main difference between x75 and x25dte/dce is that +level driver. The main difference between x75i and x25dte/dce is that x25d[tc]e uses fixed lap_b addresses. With x75i, the side which initiates the isdn connection uses the DTE's lap_b address while the -called side used the DCE's lap_b address. Thus, l2_prot x75i will -probably work if you access a public x25 network as long as the -corresponding isdn connection is set up by you. However, I've never -tested this. - - +called side used the DCE's lap_b address. Thus, l2_prot x75i might +probably work if you access a public X.25 network as long as the +corresponding isdn connection is set up by you. At least one test +was successful to connect via isdn4linux to an X.25 switch using this +trick. At the switch side, a terminal adapter X.21 was used to connect +it to the isdn. -How to use the test installation? +How to set up a test installation? +================================== -To test x25 on top of isdn, you need to get +To test X.25 on top of isdn, you need to get -- a patched version of the "isdnctrl" program that supports setting the new - x25 specific parameters. +- a recent version of the "isdnctrl" program that supports setting the new + X.25 specific parameters. -- the x25-utils-2.1.x package from ftp.pspt.fi/pub/ham/linux/ax25 - or any mirror site (i.e. ftp://ftp.gwdg.de/pub/linux/misc/ax25/). +- the x25-utils-2.X package from + ftp://ftp.hes.iki.fi/pub/ham/linux/ax25/x25utils-* + (don't confuse the x25-utils with the ax25-utils) -- a kernel patch that enhances isdn4linux to provide x25 network - interface support. (This file is part of that kernel patch). - -- an application that uses linux AF_X25 sockets program. +- an application program that uses linux PF_X25 sockets (some are + contained in the x25-util package). Before compiling the user level utilities make sure that the compiler/ -preprocessor will fetch the proper (patched) kernel header files. Either make -/usr/include/linux a symbolic link pointing to your developer kernel's -include/linux directory or set the appropriate compiler flags. - -It is recommended that all isdn drivers and the x25 PLP protocol -are compiled as loadable modules. Like this, you can recover -from certain errors by simply unloading and reloading the modules. +preprocessor will fetch the proper kernel header files of this kernel +source tree. Either make /usr/include/linux a symbolic link pointing to +this kernel's include/linux directory or set the appropriate compiler flags. When all drivers and interfaces are loaded and configured you need to -ifconfig the network interfaces up and add x25-routes to them. Use +ifconfig the network interfaces up and add X.25-routes to them. Use the usual ifconfig tool. ifconfig up But a special x25route tool (distributed with the x25-util package) -is needed to set up x25 routes. I.e. +is needed to set up X.25 routes. I.e. x25route add 01 -will cause all x.25 connections to the destination x.25-address +will cause all x.25 connections to the destination X.25-address "01" to be routed to your created isdn network interface. - -There are currently no real x25 applications available. However, for +There are currently no real X.25 applications available. However, for tests, the x25-utils package contains a modified version of telnet -and telnetd that uses x25 sockets instead of tcp/ip sockets. Use -this for your first tests. Furthermore, there is an x25.echod and a client -named "eftp" (which contains some experimental code to download files -from a remote eft server using the EUROfile transfer protocol). -It available at ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/eftp4linux-* +and telnetd that uses X.25 sockets instead of tcp/ip sockets. You can +use those for your first tests. Furthermore, you might check +ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/ which contains some +alpha-test implementation ("eftp4linux") of the EUROfile transfer +protocol. + +The scripts distributed with the eftp4linux test releases might also +provide useful examples for setting up X.25 on top of isdn. The x25-utility package also contains an x25trace tool that can be -used to monitor x25 packets received by the network interfaces. +used to monitor X.25 packets received by the network interfaces. The /proc/net/x25* files also contain useful information. -The eftp4linux test release also contains an "ix25test" script that can -be used for testing x25 on top of isdn4linux. Edit -this script according to your local needs and then call it as - -ix25test start - -This will set up a sample configuration using the isdnloop and hisax -driver and create some isdn network interfaces. -It is recommended that all other isdn drivers and the -x25 module are unloaded before calling this script. - - - -Known problems and deficiencies: - -The isdnloop HL driver apparently has problems to re-establish a -connection that has been hung up from the outgoing device. You have to -unload the isdnloop driver after the faked isdn-connection is closed -and insmod it again. With the Hisax driver, this problem is not present. - -Sometimes the x25 module cannot be unloaded (decrementation of its use -count seems to get lost occasionally). - -Using the x25 based telnet and telnetd programm to establish connection -from your own to your own computer repeatedly sometimes totally locked -up my system. However, this kernel patch also modifies -net/x25/af_x25.c to include a workaround. With this workaround -enabled, my system is stable. (If you want to disable the -workaround, just undefine ISDN_X25_FIXES in af_x25.c). - -The latter problem could be reproduced by using hisax as well as the -isdnloop driver. It seems that it is not caused by the isdn code. -Somehow, the inode of a socket is freed while a process still refers -the socket's wait queue. This causes problems when the process tries to -remove itself from the wait queue (referred by the dangling -sock->sleep pointer) before returning from a select() system call. - - Henner - diff -u --recursive --new-file v2.2.10/linux/Documentation/mkdev.ida linux/Documentation/mkdev.ida --- v2.2.10/linux/Documentation/mkdev.ida Wed Dec 31 16:00:00 1969 +++ linux/Documentation/mkdev.ida Mon Aug 9 12:04:57 1999 @@ -0,0 +1,40 @@ +#!/bin/sh +# Script to create device nodes for SMART array controllers +# Usage: +# mkdev.ida [num controllers] [num log volumes] [num partitions] +# +# With no arguments, the script assumes 1 controller, 16 logical volumes, +# and 16 partitions/volume, which is adequate for most configurations. +# +# If you had 5 controllers and were planning on no more than 4 logical volumes +# each, using a maximum of 8 partitions per volume, you could say: +# +# mkdev.ida 5 4 8 +# +# Of course, this has no real benefit over "mkdev.ida 5" except that it +# doesn't create so many device nodes in /dev/ida. + +NR_CTLR=${1-1} +NR_VOL=${2-16} +NR_PART=${3-16} + +if [ ! -d /dev/ida ]; then + mkdir -p /dev/ida +fi + +C=0; while [ $C -lt $NR_CTLR ]; do + MAJ=`expr $C + 72` + D=0; while [ $D -lt $NR_VOL ]; do + P=0; while [ $P -lt $NR_PART ]; do + MIN=`expr $D \* 16 + $P` + if [ $P -eq 0 ]; then + mknod /dev/ida/c${C}d${D} b $MAJ $MIN + else + mknod /dev/ida/c${C}d${D}p${P} b $MAJ $MIN + fi + P=`expr $P + 1` + done + D=`expr $D + 1` + done + C=`expr $C + 1` +done diff -u --recursive --new-file v2.2.10/linux/Documentation/nbd.txt linux/Documentation/nbd.txt --- v2.2.10/linux/Documentation/nbd.txt Thu Feb 26 11:01:24 1998 +++ linux/Documentation/nbd.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/Configurable linux/Documentation/networking/Configurable --- v2.2.10/linux/Documentation/networking/Configurable Thu Sep 4 13:25:28 1997 +++ linux/Documentation/networking/Configurable Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/DLINK.txt linux/Documentation/networking/DLINK.txt --- v2.2.10/linux/Documentation/networking/DLINK.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/DLINK.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/README.sb1000 linux/Documentation/networking/README.sb1000 --- v2.2.10/linux/Documentation/networking/README.sb1000 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/README.sb1000 Mon Aug 9 12:05:09 1999 @@ -0,0 +1,133 @@ +This is the new release of a module network device driver for General +Instruments (also known as NextLevel) SB1000 cable modem board (also +called internal SURFboard). +I have tested and I am running this module on kernel 2.0.33. +Steven N. Hirsch gave me a diff patch +(sb1000-1.1.2_127.patch to be applied with 'patch -p') that allows +you to compile and run the driver with kernel versions 2.1.x. +Thanks very much Steve! + +Here you'll the following files: + +- README +- Makefile +- sb1000.c the actual device driver +- cmconfig.c an ifconfig-like program to correctly set the SB1000 +- cmping.c a ping-like program to test your connection +- ftptest.c a small program to test your connection speed with FTP + (requires ftplib version >= 3.0) + +The directory ppp/ contains the files I am using to connect to MediaOne +here in Jacksonville, to show how you can use the driver and the cmconfig +program. + +Clemmitt Sigler wrote a very good and useful web page and installation +script (for Adelphia PowerLink users but easy to port to other ISPs) +about this SB1000 driver for Linux. +You can find it here: + http://home.adelphia.net/~siglercm/sb1000.html +Thanks very much Clemmitt! + +To install and run it: +- cd sb1000-1.1.2 +- make +- make install +- configure the SB1000 card using the isapnp tools setting the correct + I/O's and IRQ. You can find more info about the isapnp tools at: + http://www.roestock.demon.co.uk/isapnptools/ + (once you're happy with it, you may want to set the configuration + at boot time in one of the /etc/init.d/ scripts) + IMPORTANT NOTICE: after configuring isapnp, please look in the file + /etc/isapnp.conf for the line beginning with: + (READPORT + if it says: '(READPORT 0x0203)' (which should be the default), then + go to the next step. If instead it says something like: + '(READPORT 0x020b)' or '(READPORT 0x)', then please + follow the instructions at the end of this README file before going + to the next step. +- install the PPP configuration files in the /etc/ppp directory; you + definitely have to change the file ppp@gi-on (the start up file), + setting the correct login name, the phone number for the PPP connection + and the frequency (k stands for kHz, M for MHz) for the cablemodem. + You'll also have to change the last line in the pap-secrets file + writing your login and password there (read the whole file for more + site specific configurations). + You may have to change the firewall file to suit your needs (IPs and + ports allowed to connect). +- start the PPP connection with ppp@gi-on and see what happens; you may + want to set 'pppd' (the last command in the ppp@gi-on file) to debug + mode adding 'debug' at the end of the command ('pppd' prints its info in + the file /var/log/messages and/or /var/log/ppp.log). To make sure 'chat' + s not having problems you may want to add a '-v' (verbose) after the 'chat' + command in 'ppp-on-dialer' and check the results in /var/log/messages) +- if everything is working fine you should see after a few seconds a message + likes this: + cm0: sb1000 at (0x120,0x310), csn 1, S/N 0x2a0d16d8, IRQ 9. + sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net) + and ifconfig -a should show you two new interfaces: ppp0 and cm0. + Typing 'cmconfig cm0' will show you more info about the cablemodem interface. +- please let me know if you see any other message coming from 'cm0' in + your '/var/log/messages' or '/var/log/debug' file, to help me debug the + code +- also let me know if you have any problem; if everything works (hopefully), + let me know which speed you can reach downloading the 5Mb test file using + this driver. +- if everything seems to work fine but your computer locks up after a while + (and typically during a lengthy download through the cablemodem), you may + need to add a short delay in the driver to 'slow down' the SURFboard + because your PC might not be able to keep up with the transfer rate of + the SB1000. To do this, edit the 'Makefile' and look for the 'SB1000_DELAY' + define: uncomment those 'CFLAGS' lines (and comment the default ones) + and try setting the delay to something like 60 microseconds with: + '-DSB1000_DELAY=60'; if it still doesn't work or you like playing with + the driver, you may try other numbers: remember though that the higher + the delay, the slower the driver (which slows down the rest of the PC + too when it is actively used). Thanks to Ed Daiga for this tip! + +This release has a few things fixed and a better handling of the frame errors. + +I also have slightly modified the 'cablemodem' script in the 'ppp' so +you may interested in having a look at it: I basically have added filtering +out broadcast messages (you shouldn't get them with a point-to-point +interface and so far the ones I have received were from hosts trying to +attack my system) and lower debug levels for the driver to avoid seeing +the 'frame error' messages (so far noone has noticed any problem with the +driver even with those messages). + +For questions, infos, etc, feel free to email me at: + fventuri@mediaone.net + +Good luck, +Franco Venturi + +Thanks to Edge for his useful comments and to Steven N. Hirsch +for his patch to run the driver with 2.1.x kernels. +Thanks also to Ed Daiga for his help in finding that adding a delay +in the driver fixes some lock up problems with some slow PCs. +Many thanks to Clemmitt Sigler for his (much needed) web page about the +SB1000 driver for Linux. +An interesting URL for Linux + MediaOne (although with an external modem) +is: http://rlz.ne.mediaone.net/linux/home.shtml +Today, Sep 22 1998, I finished writing a short utility (ftptest.c) to +'measure' your cablemodem speed connection in Linux, downloading to +memory the same file several times. To compile it you need ftplib, version +3 or above. To run it, type: + ftptest URL n +where URL is in the form: ftp://ftp.site.local.isp/pub/testfile +and n is the number of simultaneous FTP connections that you want to run + +--------------------------------------------------------------------------- +IMPORTANT NOTICE: if in your file /etc/isapnp.conf, you found something +like '(READPORT 0x020b)' or '(READPORT 0x)', (anything +different from the default 0x0203), you have to change the READ_DATA_PORT +parameter in the sb1000.c file as follows. + - edit the sb1000.c file, look for: + READ_DATA_PORT + (it should be around line 127 in version 1.1.2) + - change the value of READ_DATA_PORT to the same value found in + /etc/isapnp.conf; for instance, if you found a: '(READPORT 0x020b)', + then in sb1000.c you should have: + static const int READ_DATA_PORT = 0x20b; + - save sb1000.c + - compile and install again the driver + (i.e. do a 'make' and a 'make install'). diff -u --recursive --new-file v2.2.10/linux/Documentation/networking/arcnet-hardware.txt linux/Documentation/networking/arcnet-hardware.txt --- v2.2.10/linux/Documentation/networking/arcnet-hardware.txt Thu Jan 7 08:41:55 1999 +++ linux/Documentation/networking/arcnet-hardware.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt --- v2.2.10/linux/Documentation/networking/arcnet.txt Mon Sep 14 11:32:22 1998 +++ linux/Documentation/networking/arcnet.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt --- v2.2.10/linux/Documentation/networking/olympic.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/olympic.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/policy-routing.txt linux/Documentation/networking/policy-routing.txt --- v2.2.10/linux/Documentation/networking/policy-routing.txt Thu May 14 10:26:22 1998 +++ linux/Documentation/networking/policy-routing.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/networking/soundmodem.txt linux/Documentation/networking/soundmodem.txt --- v2.2.10/linux/Documentation/networking/soundmodem.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/soundmodem.txt Mon Aug 9 12:04:57 1999 @@ -42,8 +42,8 @@ /etc/conf.modules). Examples: - insmod soundmodem hw=0 mode=0 iobase=0x220 irq=5 dma=1 - sethdlc -i sm0 -p hw sbc type afsk1200 io 0x220 irq 5 dma 1 + insmod soundmodem mode="sbc:afsk1200" iobase=0x220 irq=5 dma=1 + sethdlc -i sm0 -p mode "sbc:afsk1200" io 0x220 irq 5 dma 1 Both lines configure the first port to drive a soundblaster card in 1200 baud AFSK mode. diff -u --recursive --new-file v2.2.10/linux/Documentation/networking/wavelan.txt linux/Documentation/networking/wavelan.txt --- v2.2.10/linux/Documentation/networking/wavelan.txt Fri Aug 28 10:45:29 1998 +++ linux/Documentation/networking/wavelan.txt Mon Aug 9 12:04:57 1999 @@ -1,7 +1,11 @@ Sun Jul 2 01:38:33 EST 1995 -See also: http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + As the date above certify, this ``readme'' is mostly +obsolete. Please read release notes and change list in +driver/net/wavelan.p.h, and consult my web page at : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + Jean 1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390. The version of the card that I use (NCR) supports four I/O addresses diff -u --recursive --new-file v2.2.10/linux/Documentation/networking/z8530drv.txt linux/Documentation/networking/z8530drv.txt --- v2.2.10/linux/Documentation/networking/z8530drv.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/z8530drv.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt --- v2.2.10/linux/Documentation/powerpc/sound.txt Sat Oct 10 09:53:24 1998 +++ linux/Documentation/powerpc/sound.txt Mon Aug 9 12:04:57 1999 @@ -4,7 +4,7 @@ Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions, comments or corrections. -Last Change: 3.24.98 +Last Change: 6.16.99 This just covers sound on the PReP and CHRP systems for now and later will contain information on the PowerMac's. @@ -51,7 +51,7 @@ Midi is not supported since the cs4232 driver doesn't support midi yet. -2. IBM PowerPersonal PReP machines and IBM LongTrail CHRP +2. IBM PowerPersonal PReP machines I've only tested sound on the Power Personal Series of IBM workstations so if you try it on others please let me know the result. I'm especially @@ -74,3 +74,8 @@ This setup does _NOT_ allow for recording yet. Midi is not supported since the cs4232 driver doesn't support midi yet. + +2. IBM CHRP + + I have only tested this on the 43P-150. Build the kernel with the cs4232 + set as a module and load the module with irq=9 dma=1 dma2=2 io=0x550 diff -u --recursive --new-file v2.2.10/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.2.10/linux/Documentation/sound/AWE32 Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/AWE32 Mon Aug 9 12:04:57 1999 @@ -85,7 +85,6 @@ 7) Edit /etc/conf.modules, inserting at the end of the file: -alias sound sb alias midi awe_wave post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 diff -u --recursive --new-file v2.2.10/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction --- v2.2.10/linux/Documentation/sound/Introduction Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/Introduction Mon Aug 9 12:05:45 1999 @@ -1,6 +1,6 @@ -Soundcore Notes on Modular Sound Drivers and Soundcore +Introduction Notes on Modular Sound Drivers and Soundcore Wade Hampton -11/20/1998 +6/30/1999 Purpose: ======== @@ -10,13 +10,21 @@ Note, some of this probably should be added to the Sound-HOWTO! + Copying: ======== none + History: ======== -0.1.0 11/20/1998 First version +0.1.0 11/20/1998 First version, draft +1.0.0 11/1998 Alan Cox changes, incorporation in 2.2.0 + as /usr/src/linux/Documentation/sound/Introduction +1.1.0 6/30/1999 Second version, added notes on making the drivers, + added info on multiple sound cards of similar types,] + added more diagnostics info, added info about esd. + added info on OSS and ALSA. Modular Sound Drivers: @@ -58,6 +66,53 @@ for the same or a similar feature (dma1= versus dma16=). As a last resort, inspect the code (search for MODULE_PARM). +Notes: + +1. There is a new OpenSource sound driver called ALSA which is + currently under development: http://www.alsa-project.org/ + I have not tried it nor am I aware of its status, but it is + currently under development. + +2. The commercial OSS driver may be obtained from the site: + http://www/opensound.com. This may be used for cards that + are unsupported by the kernel driver, or may be used + by other operating systems. + +3. The enlightenment sound daemon may be used for playing + multiple sounds at the same time via a single card, eliminating + some of the requirements for multiple sound card systems. For + more information, see: http://www.tux.org/~ricdude/EsounD.html + The "esd" program may be used with the real-player and mpeg + players like mpg123 and x11amp. + + +Building the Modules: +===================== + +This document does not provide full details on building the +kernel, etc. The notes below apply only to making the kernel +sound modules. If this conflicts with the kernel's README, +the README takes precedence. + +1. To make the kernel sound modules, cd to your /usr/src/linux + directory (typically) and type make config, make menuconfig, + or make xconfig (to start the command line, dialog, or x-based + configuration tool). + +2. Select the Sound option and a dialog will be displayed. + +3. Select M (module) for "Sound card support". + +4. Select your sound driver(s) as a module. For ProAudio, Sound + Blaster, etc., select M (module) for OSS sound modules. + [thanks to marvin stodolsky ]A + +5. Make the kernel (e.g., make dep ; make bzImage), and install + the kernel. + +6. Make the modules and install them (make modules; make modules_install). + + INSMOD: ======= @@ -82,6 +137,9 @@ /sbin/insmod uart401 /sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP +When using sound as a module, I typically put these commands +in a file such as /root/soundon.sh. + MODPROBE: ========= @@ -117,8 +175,8 @@ soundcore 1968 8 [sb sound] -Removing Sound: -=============== +Removing Sound: +=============== Sound may be removed by using /sbin/rmmod in the reverse order in which you load the modules. Note, if a program has a sound device @@ -134,6 +192,25 @@ /sbin/rmmod soundlow /sbin/rmmod soundcore +When using sound as a module, I typically put these commands +in a script such as /root/soundoff.sh. + + +Removing Sound for use with OSS: +================================ + +If you get really stuck or have a card that the kernel modules +will not support, you can get a commercial sound driver from +http://www.opensound.com. Before loading the commercial sound +driver, you should do the following: + +1. remove sound modules (detailed above) +2. remove the sound modules from /etc/conf.modules +3. move the sound modules from /lib/modules//misc + (for example, I make a /lib/modules//misc/tmp + directory and copy the sound module files to that + directory). + Multiple Sound Cards: ===================== @@ -154,11 +231,30 @@ first (in my case "sb") and then load the other one (in my case "cs4232"). +If you have two cards of the same type that are jumpered +cards or different PnP revisions, you may load the same +module twice. For example, I have a SoundBlaster vibra 16 +and an older SoundBlaster 16 (jumpers). To load the module +twice, you need to do the following: + +1. Copy the sound modules to a new name. For example + sb.o could be copied (or symlinked) to sb1.o for the + second SoundBlaster. + +2. Make a second entry in /etc/conf.modules, for example, + sound1 or sb1. This second entry should refer to the + new module names for example sb1, and should include + the I/O, etc. for the second sound card. + +3. Update your soundon.sh script, etc. + Warning: I have never been able to get two PnP sound cards of the same type to load at the same time. I have tried this several times with the Soundblaster Vibra 16 cards. OSS has indicated that this is a PnP problem.... If anyone has any luck doing this, please -send me an E-MAIL. PCI sound cards should not have this problem. +send me an E-MAIL. PCI sound cards should not have this problem.a +Since this was originally release, I have received a couple of +mails from people who have accomplished this! Sound Problems: @@ -175,6 +271,8 @@ write down what addresses, IRQ, and DMA channels those were using for the same hardware. You probably can use these addresses, IRQs, and DMA channels. + You should really do this BEFORE attempting to get + sound working! B) Check (cat) /proc/interrupts, /proc/ioports, and /proc/dma. Are you trying to use an address, @@ -184,22 +282,44 @@ may need a kernel patch to get this device). D) Inspect your /var/log/messages file. Often that will - indicate what IRQ or IO port could not be obtained + indicate what IRQ or IO port could not be obtained. E) Try another port or IRQ. Note this may involve using the PnP tools to move the sound card to - another location. + another location. Sometimes this is the only way + and it is more or less trial and error. -2) If you get motorboating (the same sound or part of a +2) If you get motor-boating (the same sound or part of a sound clip repeated), you probably have either an IRQ - or DMA conflict. Move the card to another address. This - has happened to me when playing long files when I had - an IRQ conflict. + or DMA conflict. Move the card to another IRQ or DMA + port. This has happened to me when playing long files + when I had an IRQ conflict. + +3. If you get dropouts or pauses when playing high sample + rate files such as using mpg123 or x11amp/xmms, you may + have too slow of a CPU and may have to use the options to + play the files at 1/2 speed. For example, you may use + the -2 or -4 option on mpg123. You may also get this + when trying to play mpeg files stored on a CD-ROM + (my Toshiba T8000 PII/366 sometimes has this problem). + +4. If you get "cannot access device" errors, your /dev/dsp + files, etc. may be set to owner root, mode 600. You + may have to use the command: + chmod 666 /dev/dsp /dev/mixer /dev/audio + +5. If you get "device busy" errors, another program has the + sound device open. For example, if using the Enlightenment + sound daemon "esd", the "esd" program has the sound device. + If using "esd", please RTFM the docs on ESD. For example, + esddsp may be used to play files via a non-esd + aware program. + -3) Ask for help on the sound list or send E-MAIL to the +6) Ask for help on the sound list or send E-MAIL to the sound driver author/maintainer. -4) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). +7) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). Configuring Sound: @@ -210,7 +330,8 @@ 1) Hardcoded in the kernel at compile time (not applicable when using sound modules). This was the OLD way! -2) On the command line when using insmod. +2) On the command line when using insmod or in a bash script + using command line calls to load sound. 3) In /etc/conf.modules when using modprobe. @@ -224,7 +345,6 @@ Anyone want to write a linuxconf module for configuring sound? - For More Information (RTFM): ============================ 1) Information on kernel modules: linux/Documentation/modules.txt @@ -242,12 +362,17 @@ 7) The sndconfig and rhsound documentation from Red Hat. -8) The Linux-sound mailing list: sound-list@redhat.com +8) The Linux-sound mailing list: sound-list@redhat.com. + +9) Enlightenment documentation (for info on esd) + http://www.tux.org/~ricdude/EsounD.html. +10) ALSA home page: http://www.alsa-project.org/ Contact Information: ==================== Wade Hampton: (whampton@staffnet.com) + diff -u --recursive --new-file v2.2.10/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.2.10/linux/Documentation/sound/OPL3-SA2 Thu Jan 14 22:53:02 1999 +++ linux/Documentation/sound/OPL3-SA2 Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/Documentation/sx.txt linux/Documentation/sx.txt --- v2.2.10/linux/Documentation/sx.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sx.txt Mon Aug 9 12:05:09 1999 @@ -0,0 +1,289 @@ + + sx.txt -- specialix SX/SI multiport serial driver readme. + + + + Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) + + Specialix pays for the development and support of this driver. + Please DO contact support@specialix.co.uk if you require + support. + + This driver was developed in the BitWizard linux device + driver service. If you require a linux device driver for your + product, please contact devices@BitWizard.nl for a quote. + + (History) + There used to be an SI driver by Simon Allan. This is a complete + rewrite from scratch. Just a few lines-of-code have been snatched. + + (Sources) + Specialix document number 6210028: SX Host Card and Download Code + Software Functional Specification. + + (Copying) + 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. + + (Addendum) + I'd appreciate it that if you have fixes, that you send them + to me first. + + +Introduction +============ + +This file contains some random information, that I like to have online +instead of in a manual that can get lost. Ever misplace your Linux +kernel sources? And the manual of one of the boards in your computer? + + +Theory of operation +=================== + +An important thing to know is that the driver itself doesn't have the +firmware for the card. This means that you need the separate package +"sx_firmware". For now you can get the source at + + ftp://ftp.bitwizard.nl/specialix/sx_firmware_.tgz + +The firmware load needs a "misc" device, so you'll need to enable the +"Support for user misc device modules" in your kernel configuration. +The misc device needs to be called "/dev/specialix_sxctl". It needs +misc major 10, and minor number 167 (assigned by HPA). The section +on creating device files below also creates this device. + +After loading the sx.o module into your kernel, the driver will report +the number of cards detected, but because it doesn't have any +firmware, it will not be able to determine the number of ports. Only +when you then run "sx_firmware" will the firmware be downloaded and +the rest of the driver initialized. At that time the sx_firmware +program will report the number of ports installed. + +In contrast with many other multi port serial cards, some of the data +structures are only allocated when the card knows the number of ports +that are connected. This means we won't waste memory for 120 port +descriptor structures when you only have 8 ports. If you experience +problems due to this, please report them: I haven't seen any. + + +Interrupts +========== + +A multi port serial card, would generate a horrendous amount of +interrupts if it would interrupt the CPU for every received +character. Even more than 10 years ago, the trick not to use +interrupts but to poll the serial cards was invented. + +The SX card allow us to do this two ways. First the card limits its +own interrupt rate to a rate that won't overwhelm the CPU. Secondly, +we could forget about the cards interrupt completely and use the +internal timer for this purpose. + +Polling the card can take up to a few percent of your CPU. Using the +interrupts would be better if you have most of the ports idle. Using +timer-based polling is better if your card almost always has work to +do. You save the separate interrupt in that case. + +In any case, it doesn't really matter all that much. + +The most common problem with interrupts is that for ISA cards in a PCI +system the BIOS has to be told to configure that interrupt as "legacy +ISA". Otherwise the card can pull on the interrupt line all it wants +but the CPU won't see this. + +If you can't get the interrupt to work, remember that polling mode is +more efficient (provided you actually use the card intensively). + + +Allowed Configurations +====================== + +Some configurations are disallowed. Even though at a glance they might +seem to work, they are known to lockup the bus between the host card +and the device concentrators. You should respect the drivers decision +not to support certain configurations. It's there for a reason. + +Warning: Seriously technical stuff ahead. Executive summary: Don't use +SX cards except configured at a 64k boundary. Skip the next paragraph. + +The SX cards can theoretically be placed at a 32k boundary. So for +instance you can put an SX card at 0xc8000-0xd7fff. This is not a +"recommended configuration". ISA cards have to tell the bus controller +how they like their timing. Due to timing issues they have to do this +based on which 64k window the address falls into. This means that the +32k window below and above the SX card have to use exactly the same +timing as the SX card. That reportedly works for other SX cards. But +you're still left with two useless 32k windows that should not be used +by anybody else. + + +Configuring the driver +====================== + +PCI cards are always detected. The driver auto-probes for ISA cards at +some sensible addresses. Please report if the auto-probe causes trouble +in your system, or when a card isn't detected. + +I'm afraid I haven't implemented "kernel command line parameters" yet. +This means that if the default doesn't work for you, you shouldn't use +the compiled-into-the-kernel version of the driver. Use a module +instead. If you convince me that you need this, I'll make it for +you. Deal? + +I'm afraid that the module parameters are a bit clumsy. If you have a +better idea, please tell me. + +You can specify several parameters: + + sx_poll: number of jiffies between timer-based polls. + + Set this to "0" to disable timer based polls. + Initialization of cards without a working interrupt + will fail. + + Set this to "1" if you want a polling driver. + (on Intel: 100 polls per second). If you don't use + fast baud rates, you might consider a value like "5". + (If you don't know how to do the math, use 1). + + sx_slowpoll: Number of jiffies between timer-based polls. + Set this to "100" to poll once a second. + This should get the card out of a stall if the driver + ever misses an interrupt. I've never seen this happen, + and if it does, that's a bug. Tell me. + + sx_maxints: Number of interrupts to request from the card. + The card normally limits interrupts to about 100 per + second to offload the host CPU. You can increase this + number to reduce latency on the card a little. + Note that if you give a very high number you can overload + your CPU as well as the CPU on the host card. This setting + is inaccurate and not recommended for SI cards (But it + works). + + sx_irqmask: The mask of allowable IRQs to use. I suggest you set + this to 0 (disable IRQs all together) and use polling if + the assignment of IRQs becomes problematic. + + sx_debug: You can enable different sorts of debug traces with this. + At "-1" all debugging traces are active. You'll get several + times more debugging output than you'll get characters + transmitted. + + +Baud rates +========== + +Theoretically new SXDCs should be capable of more than 460k +baud. However the line drivers usually give up before that. Also the +CPU on the card may not be able to handle 8 channels going at full +blast at that speed. Moreover, the buffers are not large enough to +allow operation with 100 interrupts per second. You'll have to realize +that the card has a 256 byte buffer, so you'll have to increase the +number of interrupts per second if you have more than 256*100 bytes +per second to transmit. If you do any performance testing in this +area, I'd be glad to hear from you... + +(Psst Linux users..... I think the Linux driver is more efficient than +the driver for other OSes. If you can and want to benchmark them +against each other, be my guest, and report your findings...... :-) + + +Ports and devices +================= + +Port 0 is the top connector on the module closest to the host +card. Oh, the ports on the SXDCs and TAs are labelled from 1 to 8 +instead of from 0 to 7, as they are numbered by linux. I'm stubborn in +this: I know for sure that I wouldn't be able to calculate which port +is which anymore if I would change that.... + + +Devices: + +You should make the device files as follows: + +#!/bin/sh +# (I recommend that you cut-and-paste this into a file and run that) +cd /dev +t=0 +mknod specialix_sxctl c 10 167 +while [ $t -lt 64 ] + do + echo -n "$t " + mknod ttyX$t c 32 $t + mknod cux$t c 33 $t + t=`expr $t + 1` +done +echo "" +rm /etc/psdevtab +ps > /dev/null + + +This creates 64 devices. If you have more, increase the constant on +the line with "while". The devices start at 0, as is customary on +Linux. Specialix seems to like starting the numbering at 1. + +If your system doesn't come with these devices pre-installed, bug your +linux-vendor about this. They should have these devices +"pre-installed" before the new millennium. The "ps" stuff at the end +is to "tell" ps that the new devices exist. + +Officially the maximum number of cards per computer is 4. This driver +however supports as many cards in one machine as you want. You'll run +out of interrupts after a few, but you can switch to polled operation +then. At about 256 ports (More than 8 cards), we run out of minor +device numbers. Sorry. I suggest you buy a second computer.... (Or +switch to RIO). + +------------------------------------------------------------------------ + + + Fixed bugs and restrictions: + - Hangup processing. + -- Done. + + - the write path in generic_serial (lockup / oops). + -- Done (Ugly: not the way I want it. Copied from serial.c). + + - write buffer isn't flushed at close. + -- Done. I still seem to loose a few chars at close. + Sorry. I think that this is a firmware issue. (-> Specialix) + + - drain hardware before changing termios + - Change debug on the fly. + - ISA free irq -1. (no firmware loaded). + - adding c8000 as a probe address. Added warning. + - Add a RAMtest for the RAM on the card.c + - Crash when opening a port "way" of the number of allowed ports. + (for example opening port 60 when there are only 24 ports attached) + - Sometimes the use-count strays a bit. After a few hours of + testing the use count is sometimes "3". If you are not like + me and can remember what you did to get it that way, I'd + appreciate an Email. Possibly fixed. Tell me if anyone still + sees this. + - TAs don't work right if you don't connect all the modem control + signals. SXDCs do. T225 firmware problem -> Specialix. + (Mostly fixed now, I think. Tell me if you encounter this!) + + Bugs & restrictions: + + - Arbitrary baud rates. Requires firmware update. (-> Specialix) + + - Low latency (mostly firmware, -> Specialix) + + + diff -u --recursive --new-file v2.2.10/linux/Documentation/sysctl/README linux/Documentation/sysctl/README --- v2.2.10/linux/Documentation/sysctl/README Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/README Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/ kernel version 2.2.5 +Documentation for /proc/sys/ kernel version 2.2.10 (c) 1998, 1999, Rik van Riel 'Why', I hear you ask, 'would anyone even _want_ documentation diff -u --recursive --new-file v2.2.10/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt --- v2.2.10/linux/Documentation/sysctl/fs.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/fs.txt Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/fs/* kernel version 2.2.5 +Documentation for /proc/sys/fs/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.2.10/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt --- v2.2.10/linux/Documentation/sysctl/kernel.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/kernel.txt Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/kernel/* kernel version 2.2.5 +Documentation for /proc/sys/kernel/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. @@ -76,12 +76,21 @@ domainname & hostname: -These files can be controlled to set the domainname and -hostname of your box. For the classic darkstar.frop.org -a simple: +These files can be used to set the NIS/YP domainname and the +hostname of your box in exactly the same way as the commands +domainname and hostname, i.e.: # echo "darkstar" > /proc/sys/kernel/hostname -# echo "frop.org" > /proc/sys/kernel/domainname -would suffice to set your hostname and domainname. +# echo "mydomain" > /proc/sys/kernel/domainname +has the same effect as +# hostname "darkstar" > /proc/sys/kernel/hostname +# domainname "mydomain" > /proc/sys/kernel/domainname + +Note, however, that the classic darkstar.frop.org has the +hostname "darkstar" and DNS (Internet Domain Name Server) +domainname "frop.org", not to be confused with the NIS (Network +Information Service) or YP (Yellow Pages) domainname. These two +domain names are in general different. For a detailed discussion +see the hostname(1) man page. ============================================================== diff -u --recursive --new-file v2.2.10/linux/Documentation/sysctl/sunrpc.txt linux/Documentation/sysctl/sunrpc.txt --- v2.2.10/linux/Documentation/sysctl/sunrpc.txt Mon Apr 12 10:10:27 1999 +++ linux/Documentation/sysctl/sunrpc.txt Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/sunrpc/* kernel version 2.2.5 +Documentation for /proc/sys/sunrpc/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.2.10/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt --- v2.2.10/linux/Documentation/sysctl/vm.txt Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sysctl/vm.txt Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/vm/* kernel version 2.2.5 +Documentation for /proc/sys/vm/* kernel version 2.2.10 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. diff -u --recursive --new-file v2.2.10/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt --- v2.2.10/linux/Documentation/sysrq.txt Wed Jun 24 14:30:07 1998 +++ linux/Documentation/sysrq.txt Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/MAINTAINERS linux/MAINTAINERS --- v2.2.10/linux/MAINTAINERS Thu Jun 3 08:26:38 1999 +++ linux/MAINTAINERS Mon Aug 9 12:04:57 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 @@ -170,6 +170,12 @@ W: http://www.dandelion.com/Linux/ S: Maintained +CIRRUS LOGIC GENERIC FBDEV DRIVER +P: Jeff Garzik +M: jgarzik@pobox.com +L: linux-fbdev@vuser.vu.union.edu +S: Maintained + CONFIGURE, MENUCONFIG, XCONFIG P: Michael Elizabeth Chastain M: mec@shout.net @@ -258,6 +264,18 @@ L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained +COMPAQ SMART2 RAID DRIVER +P: Charles White +M: Charles White +L: compaqandlinux@yps.org +S: Maintained + +DAC960 RAID DRIVER +P: Leonard N. Zubkoff +M: Leonard N. Zubkoff +L: linux-raid@vger.rutgers.edu +S: Maintained + EATA ISA/EISA/PCI SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com @@ -447,6 +465,12 @@ L: linux-pmac@samba.anu.edu.au S: Maintained +LOGICAL VOLUME MANAGER +P: Heinz Mauelshagen +M: linux.LVM@ez-darmstadt.telekom.de +W: http://linux.msede.com/lvm +S: Maintained + M68K P: Jes Sorensen M: Jes.Sorensen@cern.ch @@ -560,6 +584,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 +660,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 +689,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 +707,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) @@ -817,7 +847,8 @@ WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS P: Jean Tourrilhes -M: jt@hplb.hpl.hp.com +M: jt@hpl.hp.com +W: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ S: Maintained WD7000 SCSI DRIVER diff -u --recursive --new-file v2.2.10/linux/Makefile linux/Makefile --- v2.2.10/linux/Makefile Fri May 28 18:10:19 1999 +++ linux/Makefile Mon Aug 9 12:04:38 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 2 -SUBLEVEL = 10 +SUBLEVEL = 11 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -27,6 +27,7 @@ AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip +OBJCOPY =$(CROSS_COMPILE)objcopy OBJDUMP =$(CROSS_COMPILE)objdump MAKE =make GENKSYMS=/sbin/genksyms @@ -70,7 +71,7 @@ # # 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. # # @@ -88,6 +89,9 @@ CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + ifdef CONFIG_SMP CFLAGS += -D__SMP__ AFLAGS += -D__SMP__ @@ -162,6 +166,10 @@ DRIVERS := $(DRIVERS) drivers/pnp/pnp.a endif +ifdef CONFIG_SGI +DRIVERS := $(DRIVERS) drivers/sgi/sgi.a +endif + ifdef CONFIG_VT DRIVERS := $(DRIVERS) drivers/video/video.a endif @@ -174,6 +182,10 @@ DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a endif +ifeq ($(CONFIG_TC),y) +DRIVERS := $(DRIVERS) drivers/tc/tc.a +endif + ifeq ($(CONFIG_USB),y) DRIVERS := $(DRIVERS) drivers/usb/usb.a endif @@ -287,7 +299,7 @@ fs lib mm ipc kernel drivers net: dummy $(MAKE) $(subst $@, _dir_$@, $@) -MODFLAGS = -DMODULE +MODFLAGS += -DMODULE ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h @@ -323,7 +335,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 +355,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 +403,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 +413,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 --recursive --new-file v2.2.10/linux/README linux/README --- v2.2.10/linux/README Sun May 30 10:17:03 1999 +++ linux/README Mon Aug 9 12:04:38 1999 @@ -91,7 +91,7 @@ SOFTWARE REQUIREMENTS - Compiling and running the 2.2.x kernels requires up-to-date + Compiling and running the 2.2.xx kernels requires up-to-date versions of various software packages. Consult ./Documentation/Changes for the minimum version numbers required and how to get updates for these packages. Beware that using diff -u --recursive --new-file v2.2.10/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.2.10/linux/arch/alpha/Makefile Sun Jan 24 21:29:52 1999 +++ linux/arch/alpha/Makefile Mon Aug 9 12:04:57 1999 @@ -116,9 +116,11 @@ @$(MAKEBOOT) clean archmrproper: + -$(MAKE) -C arch/alpha/math-emu cleansymlinks archdep: @$(MAKEBOOT) dep + -$(MAKE) -C arch/alpha/math-emu symlinks bootpfile: @$(MAKEBOOT) bootpfile diff -u --recursive --new-file v2.2.10/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c --- v2.2.10/linux/arch/alpha/boot/bootp.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/boot/bootp.c Mon Aug 9 12:04:38 1999 @@ -200,11 +200,11 @@ load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE); load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE); - memset((char*)ZERO_PAGE, 0, PAGE_SIZE); - strcpy((char*)ZERO_PAGE, envval); + memset((char*)ZERO_PAGE(0), 0, PAGE_SIZE); + strcpy((char*)ZERO_PAGE(0), envval); #ifdef INITRD_SIZE - ((long *)(ZERO_PAGE+256))[0] = initrd_start; - ((long *)(ZERO_PAGE+256))[1] = INITRD_SIZE; + ((long *)(ZERO_PAGE(0)+256))[0] = initrd_start; + ((long *)(ZERO_PAGE(0)+256))[1] = INITRD_SIZE; #endif runkernel(); diff -u --recursive --new-file v2.2.10/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c --- v2.2.10/linux/arch/alpha/boot/main.c Thu Feb 25 10:46:51 1999 +++ linux/arch/alpha/boot/main.c Mon Aug 9 12:04:38 1999 @@ -182,7 +182,7 @@ nbytes = 0; } envval[nbytes] = '\0'; - strcpy((char*)ZERO_PAGE, envval); + strcpy((char*)ZERO_PAGE(0), envval); srm_printk(" Ok\nNow booting the kernel\n"); runkernel(); diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.2.10/linux/arch/alpha/kernel/Makefile Sun Jan 10 09:59:54 1999 +++ linux/arch/alpha/kernel/Makefile Mon Aug 9 12:04:38 1999 @@ -105,7 +105,7 @@ endif # Device support -ifdef CONFIG_ALPHA_MIATA +ifneq ($(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),) O_OBJS += es1888.o endif ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),) diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.2.10/linux/arch/alpha/kernel/core_cia.c Sat May 22 13:41:43 1999 +++ linux/arch/alpha/kernel/core_cia.c Mon Aug 9 12:05:05 1999 @@ -31,30 +31,13 @@ */ /* - * Machine check reasons. Defined according to PALcode sources - * (osf.h and platform.h). - */ -#define MCHK_K_TPERR 0x0080 -#define MCHK_K_TCPERR 0x0082 -#define MCHK_K_HERR 0x0084 -#define MCHK_K_ECC_C 0x0086 -#define MCHK_K_ECC_NC 0x0088 -#define MCHK_K_OS_BUGCHECK 0x008A -#define MCHK_K_PAL_BUGCHECK 0x0090 - -/* * BIOS32-style PCI interface: */ -#define DEBUG_MCHECK 0 +#define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = dump */ + #define DEBUG_CONFIG 0 -/* #define DEBUG_DUMP_REGS */ -#if DEBUG_MCHECK -# define DBGM(args) printk args -#else -# define DBGM(args) -#endif #if DEBUG_CONFIG # define DBGC(args) printk args #else @@ -533,19 +516,25 @@ case 0: /* * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, + * For now, windows 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. + * Window 1 goes at 2 GB and is 1 GB large. */ + *(vuip)CIA_IOC_PCI_W0_BASE = CIA_DMA_WIN0_BASE_DEFAULT | 1U; + *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN0_SIZE_DEFAULT - 1) & + 0xfff00000U; + *(vuip)CIA_IOC_PCI_T0_BASE = CIA_DMA_WIN0_TRAN_DEFAULT >> 2; + + *(vuip)CIA_IOC_PCI_W1_BASE = CIA_DMA_WIN1_BASE_DEFAULT | 1U; + *(vuip)CIA_IOC_PCI_W1_MASK = (CIA_DMA_WIN1_SIZE_DEFAULT - 1) & + 0xfff00000U; + *(vuip)CIA_IOC_PCI_T1_BASE = CIA_DMA_WIN1_TRAN_DEFAULT >> 2; - *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); - *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)CIA_IOC_PCI_T0_BASE = 0; - - *(vuip)CIA_IOC_PCI_W1_BASE = 0x0; *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; + mb(); break; } @@ -593,16 +582,6 @@ } } -static int -cia_pci_clr_err(void) -{ - CIA_jd = *(vuip)CIA_IOC_CIA_ERR; - DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd)); - *(vuip)CIA_IOC_CIA_ERR = CIA_jd; - mb(); - return 0; -} - void cia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -610,10 +589,6 @@ struct el_common *mchk_header; struct el_CIA_procdata *mchk_procdata; struct el_CIA_sysdata_mcheck *mchk_sysdata; - unsigned long * ptr; - const char * reason; - char buf[128]; - long i; mchk_header = (struct el_common *)la_ptr; @@ -623,98 +598,22 @@ mchk_sysdata = (struct el_CIA_sysdata_mcheck *) (la_ptr + mchk_header->sys_offset); - DBGM(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBGM((" pc=0x%lx size=0x%x procoffset=0x%x " - "sysoffset 0x%x\n", regs->pc, mchk_header->size, - mchk_header->proc_offset, mchk_header->sys_offset)); - DBGM(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - CIA_mcheck_expected, mchk_sysdata->epic_dcsr, - mchk_sysdata->epic_pear)); - -#if DEBUG_MCHECK - { - unsigned long *ptr; - int i; - - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), - ptr[i], ptr[i+1]); - } - } -#endif - - /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. - */ + /* Clear the error before any reporting. */ mb(); mb(); /* magic */ - if (CIA_mcheck_expected) { - DBGM(("CIA machine check expected\n")); - CIA_mcheck_expected = 0; - CIA_mcheck_taken = 1; - mb(); - mb(); /* magic */ - draina(); - cia_pci_clr_err(); - wrmces(0x7); - mb(); - return; - } + draina(); - switch ((unsigned int) mchk_header->code) { - case MCHK_K_TPERR: reason = "tag parity error"; break; - case MCHK_K_TCPERR: reason = "tag control parity error"; break; - case MCHK_K_HERR: reason = "generic hard error"; break; - case MCHK_K_ECC_C: reason = "correctable ECC error"; break; - case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; - case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; - case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; - case 0x96: reason = "i-cache read retryable error"; break; - case 0x98: reason = "processor detected hard error"; break; - - /* System specific (these are for Alcor, at least): */ - case 0x203: reason = "system detected uncorrectable ECC error"; break; - case 0x205: reason = "parity error detected by CIA"; break; - case 0x207: reason = "non-existent memory error"; break; - case 0x209: reason = "PCI SERR detected"; break; - case 0x20b: reason = "PCI data parity error detected"; break; - case 0x20d: reason = "PCI address parity error detected"; break; - case 0x20f: reason = "PCI master abort error"; break; - case 0x211: reason = "PCI target abort error"; break; - case 0x213: reason = "scatter/gather PTE invalid error"; break; - case 0x215: reason = "flash ROM write error"; break; - case 0x217: reason = "IOA timeout detected"; break; - case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; - case 0x21b: reason = "EISA fail-safe timer timeout"; break; - case 0x21d: reason = "EISA bus time-out"; break; - case 0x21f: reason = "EISA software generated NMI"; break; - case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; - default: - sprintf(buf, "reason for machine-check unknown (0x%x)", - (unsigned int) mchk_header->code); - reason = buf; - break; - } + CIA_jd = *(vuip)CIA_IOC_CIA_ERR; + *(vuip)CIA_IOC_CIA_ERR = CIA_jd; mb(); - mb(); /* magic */ - draina(); - cia_pci_clr_err(); + CIA_jd = *(vuip)CIA_IOC_CIA_ERR; /* re-read to force write */ + wrmces(rdmces()); /* reset machine check pending flag */ mb(); - printk(KERN_CRIT "CIA machine check: %s%s\n", - reason, mchk_header->retry ? " (retryable)" : ""); - printk(KERN_CRIT " vector=0x%lx la_ptr=0x%lx pc=0x%lx\n", - vector, la_ptr, regs->pc); - - /* Dump the logout area to give all info. */ - - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(KERN_CRIT " +%8lx %016lx %016lx\n", - i*sizeof(long), ptr[i], ptr[i+1]); - } + process_mcheck_info(vector, la_ptr, regs, "CIA", + DEBUG_MCHECK, CIA_mcheck_expected); + + CIA_mcheck_expected = 0; + CIA_mcheck_taken = 1; } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.2.10/linux/arch/alpha/kernel/core_mcpcia.c Sun Sep 6 10:34:33 1998 +++ linux/arch/alpha/kernel/core_mcpcia.c Mon Aug 9 12:05:05 1999 @@ -18,7 +18,6 @@ #include #include #include -#include #define __EXTERN_INLINE inline #include @@ -46,17 +45,11 @@ # define DBG_CFG(args) #endif - -#define DEBUG_MCHECK - -#ifdef DEBUG_MCHECK -# define DBG_MCK(args) printk args -#else -# define DBG_MCK(args) -#endif +#define DEBUG_MCHECK 0 /* 0 = minimal, 1 = debug, 2 = dump */ static volatile unsigned int MCPCIA_mcheck_expected[NR_CPUS]; static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS]; +static volatile unsigned int MCPCIA_mcheck_hose[NR_CPUS]; static unsigned int MCPCIA_jd[NR_CPUS]; #define MCPCIA_MAX_HOSES 2 @@ -129,6 +122,7 @@ draina(); MCPCIA_mcheck_expected[cpu] = 1; MCPCIA_mcheck_taken[cpu] = 0; + MCPCIA_mcheck_hose[cpu] = hoseno; mb(); /* Access configuration space. */ @@ -170,6 +164,7 @@ draina(); MCPCIA_mcheck_expected[cpu] = 1; + MCPCIA_mcheck_hose[cpu] = hoseno; mb(); /* Access configuration space. */ @@ -555,19 +550,12 @@ } } -static int -mcpcia_pci_clr_err(int h) +static void +mcpcia_pci_clr_err(int cpu, int hose) { - unsigned int cpu = smp_processor_id(); - - MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); -#if 0 - DBG_MCK(("MCPCIA_pci_clr_err: MCPCIA CAP_ERR(%d) after read 0x%x\n", - h, MCPCIA_jd[cpu])); -#endif - *(vuip)MCPCIA_CAP_ERR(h) = 0xffffffff; mb(); /* clear them all */ - MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h); - return 0; + MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose); + *(vuip)MCPCIA_CAP_ERR(hose) = 0xffffffff; mb(); /* clear them all */ + MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(hose); /* read to force write */ } static void @@ -643,70 +631,36 @@ } void -mcpcia_machine_check(unsigned long type, unsigned long la_ptr, +mcpcia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#if 0 - printk("mcpcia machine check ignored\n") ; -#else struct el_common *mchk_header; struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout; unsigned int cpu = smp_processor_id(); - int h = 0; mchk_header = (struct el_common *)la_ptr; mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr; -#if 0 - DBG_MCK(("mcpcia_machine_check: type=0x%lx la_ptr=0x%lx\n", - type, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); -#endif - /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. - */ mb(); mb(); /* magic */ - if (MCPCIA_mcheck_expected[cpu]) { -#if 0 - DBG_MCK(("MCPCIA machine check expected\n")); -#endif - MCPCIA_mcheck_expected[cpu] = 0; - MCPCIA_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - mcpcia_pci_clr_err(h); - wrmces(0x7); - mb(); - } -#if 1 + draina(); + if (MCPCIA_mcheck_expected[cpu]) + mcpcia_pci_clr_err(cpu, MCPCIA_mcheck_hose[cpu]); else { - printk("MCPCIA machine check NOT expected on CPU %d\n", cpu); - DBG_MCK(("mcpcia_machine_check: type=0x%lx pc=0x%lx" - " code=0x%lx\n", - type, regs->pc, mchk_header->code)); + /* FIXME: how do we figure out which hose the error was on? */ + mcpcia_pci_clr_err(cpu, 0); + mcpcia_pci_clr_err(cpu, 1); + } + wrmces(0x7); + mb(); - MCPCIA_mcheck_expected[cpu] = 0; - MCPCIA_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - mcpcia_pci_clr_err(h); - wrmces(0x7); - mb(); -#ifdef DEBUG_MCHECK_DUMP - if (type == 0x620) - printk("MCPCIA machine check: system CORRECTABLE!\n"); - else if (type == 0x630) - printk("MCPCIA machine check: processor CORRECTABLE!\n"); - else -#endif /* DEBUG_MCHECK_DUMP */ - mcpcia_print_uncorrectable(mchk_logout); + process_mcheck_info(vector, la_ptr, regs, "MCPCIA", + DEBUG_MCHECK, MCPCIA_mcheck_expected[cpu]); + + if (vector != 0x620 && vector != 0x630) { + mcpcia_print_uncorrectable(mchk_logout); } -#endif -#endif + + MCPCIA_mcheck_expected[cpu] = 0; + MCPCIA_mcheck_taken[cpu] = 1; } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.2.10/linux/arch/alpha/kernel/core_pyxis.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/kernel/core_pyxis.c Mon Aug 9 12:05:05 1999 @@ -31,8 +31,9 @@ * BIOS32-style PCI interface: */ +#define DEBUG_MCHECK 0 /* 0 = minimum, 1 = debug, 2 = dump */ + #define DEBUG_CONFIG 0 -#define DEBUG_MCHECK 0 #if DEBUG_CONFIG # define DBG_CNF(args) printk args @@ -40,14 +41,6 @@ # define DBG_CNF(args) #endif -#if DEBUG_MCHECK -# define DBG_MCK(args) printk args -# define DEBUG_MCHECK_DUMP -#else -# define DBG_MCK(args) -#endif - - static volatile unsigned int PYXIS_mcheck_expected = 0; static volatile unsigned int PYXIS_mcheck_taken = 0; static unsigned int PYXIS_jd; @@ -425,17 +418,21 @@ { /* * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, we may + * For now, windows 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. + * Window 1 goes at 2 GB and is 1 GB large. */ - *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U); - *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)PYXIS_T0_BASE = 0; + *(vuip)PYXIS_W0_BASE = PYXIS_DMA_WIN0_BASE_DEFAULT | 1U; + *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN0_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)PYXIS_T0_BASE = PYXIS_DMA_WIN0_TRAN_DEFAULT >> 2; + + *(vuip)PYXIS_W1_BASE = PYXIS_DMA_WIN1_BASE_DEFAULT | 1U; + *(vuip)PYXIS_W1_MASK = (PYXIS_DMA_WIN1_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)PYXIS_T1_BASE = PYXIS_DMA_WIN1_TRAN_DEFAULT >> 2; - *(vuip)PYXIS_W1_BASE = 0x0 ; *(vuip)PYXIS_W2_BASE = 0x0 ; *(vuip)PYXIS_W3_BASE = 0x0 ; mb(); @@ -525,16 +522,6 @@ pyxis_finish_init_arch(); } -static int -pyxis_pci_clr_err(void) -{ - PYXIS_jd = *(vuip)PYXIS_ERR; - DBG_MCK(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd)); - *(vuip)PYXIS_ERR = 0x0180; mb(); - PYXIS_jd = *(vuip)PYXIS_ERR; /* re-read to force write */ - return 0; -} - void pyxis_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) @@ -547,61 +534,26 @@ mchk_sysdata = (struct el_PYXIS_sysdata_mcheck *) (la_ptr + mchk_header->sys_offset); -#if 0 - DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr, - mchk_sysdata->epic_pear)); -#endif + /* Clear the error before reporting anything. */ + mb(); + mb(); /* magic */ + draina(); + + PYXIS_jd = *(vuip)PYXIS_ERR; + *(vuip)PYXIS_ERR = PYXIS_jd; + mb(); + PYXIS_jd = *(vuip)PYXIS_ERR; /* re-read to force write */ + + wrmces(0x7); + mb(); /* - * Check if machine check is due to a badaddr() and if so, - * ignore the machine check. + * See if the machine check is due to a badaddr() and if so, + * ignore it. */ - mb(); - mb(); /* magic */ - if (PYXIS_mcheck_expected) { - DBG_MCK(("PYXIS machine check expected\n")); - PYXIS_mcheck_expected = 0; - PYXIS_mcheck_taken = 1; - mb(); - mb(); /* magic */ - draina(); - pyxis_pci_clr_err(); - wrmces(0x7); - mb(); - } - else { - printk("PYXIS machine check NOT expected\n") ; - DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x" - " sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - PYXIS_mcheck_expected = 0; - PYXIS_mcheck_taken = 1; - mb(); - mb(); /* magic */ - draina(); - pyxis_pci_clr_err(); - wrmces(0x7); - mb(); + process_mcheck_info(vector, la_ptr, regs, "PYXIS", + DEBUG_MCHECK, PYXIS_mcheck_expected); -#ifdef DEBUG_MCHECK_DUMP - { - unsigned long *ptr = (unsigned long *)la_ptr;; - long n = mchk_header->size / (2*sizeof(long)); - - do - printk(" +%lx %lx %lx\n", i*sizeof(long), - ptr[i], ptr[i+1]); - while (--i); - } -#endif - } + PYXIS_mcheck_expected = 0; + PYXIS_mcheck_taken = 1; } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.2.10/linux/arch/alpha/kernel/core_tsunami.c Sun Jan 10 22:56:43 1999 +++ linux/arch/alpha/kernel/core_tsunami.c Mon Aug 9 12:05:05 1999 @@ -36,20 +36,16 @@ * BIOS32-style PCI interface: */ -#ifdef DEBUG_CONFIG +#define DEBUG_MCHECK 0 /* 0 = minimum, 1 = debug, 2 = dump */ + +#define DEBUG_CONFIG 0 + +#if DEBUG_CONFIG > 0 # define DBG_CFG(args) printk args #else # define DBG_CFG(args) #endif -#define DEBUG_MCHECK -#ifdef DEBUG_MCHECK -# define DBG_MCK(args) printk args -#define DEBUG_MCHECK_DUMP -#else -# define DBG_MCK(args) -#endif - static volatile unsigned int TSUNAMI_mcheck_expected[NR_CPUS]; static volatile unsigned int TSUNAMI_mcheck_taken[NR_CPUS]; static unsigned int TSUNAMI_jd[NR_CPUS]; @@ -302,20 +298,18 @@ * we may want to use them to do scatter/gather DMA. * * Window 0 goes at 1 GB and is 1 GB large, mapping to 0. + * Window 1 goes at 2 GB and is 1 GB large, mapping to 1GB. */ - pchip->wsba[0].csr = 1L | (TSUNAMI_DMA_WIN_BASE_DEFAULT & 0xfff00000U); - pchip->wsm[0].csr = (TSUNAMI_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000UL; - pchip->tba[0].csr = 0; - -#if 0 - pchip->wsba[1].csr = 0; -#else - /* make the second window at 2Gb for 1Gb mapping to 1Gb */ - pchip->wsba[1].csr = 1L | ((0x80000000U) & 0xfff00000U); - pchip->wsm[1].csr = (0x40000000UL - 1) & 0xfff00000UL; - pchip->tba[1].csr = 0x40000000; -#endif + pchip->wsba[0].csr = TSUNAMI_DMA_WIN0_BASE_DEFAULT | 1UL; + pchip->wsm[0].csr = (TSUNAMI_DMA_WIN0_SIZE_DEFAULT - 1) & + 0xfff00000UL; + pchip->tba[0].csr = TSUNAMI_DMA_WIN0_TRAN_DEFAULT; + + pchip->wsba[1].csr = TSUNAMI_DMA_WIN1_BASE_DEFAULT | 1UL; + pchip->wsm[1].csr = (TSUNAMI_DMA_WIN1_SIZE_DEFAULT - 1) & + 0xfff00000UL; + pchip->tba[1].csr = TSUNAMI_DMA_WIN1_TRAN_DEFAULT; pchip->wsba[2].csr = 0; pchip->wsba[3].csr = 0; @@ -365,8 +359,8 @@ *mem_start = (*mem_start | 31) + 1; /* Find how many hoses we have, and initialize them. */ + /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */ tsunami_init_one_pchip(TSUNAMI_pchip0, 0, mem_start); - /* must change this for TYPHOON which may have 4 */ if (TSUNAMI_cchip->csc.csr & 1L<<14) tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start); } @@ -375,8 +369,6 @@ tsunami_pci_clr_err_1(tsunami_pchip *pchip, int cpu) { TSUNAMI_jd[cpu] = pchip->perror.csr; - DBG_MCK(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n", - TSUNAMI_jd[cpu])); pchip->perror.csr = 0x040; mb(); TSUNAMI_jd[cpu] = pchip->perror.csr; @@ -386,10 +378,13 @@ tsunami_pci_clr_err(void) { int cpu = smp_processor_id(); + tsunami_pci_clr_err_1(TSUNAMI_pchip0, cpu); - /* must change this for TYPHOON which may have 4 */ + + /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */ if (TSUNAMI_cchip->csc.csr & 1L<<14) tsunami_pci_clr_err_1(TSUNAMI_pchip1, cpu); + return 0; } @@ -397,9 +392,6 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { -#if 0 - printk("TSUNAMI machine check ignored\n") ; -#else struct el_common *mchk_header; struct el_TSUNAMI_sysdata_mcheck *mchk_sysdata; unsigned int cpu = smp_processor_id(); @@ -410,61 +402,21 @@ mchk_sysdata = (struct el_TSUNAMI_sysdata_mcheck *) (la_ptr + mchk_header->sys_offset); -#if 0 - DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - DBG_MCK(("tsunami_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - TSUNAMI_mcheck_expected[cpu], mchk_sysdata->epic_dcsr, - mchk_sysdata->epic_pear)); -#endif -#ifdef DEBUG_MCHECK_DUMP - { - unsigned long *ptr; - int i; + /* Clear error before any reporting. */ + mb(); + mb(); /* magic */ + draina(); + tsunami_pci_clr_err(); + wrmces(0x7); + mb(); - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { - printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); - } - } -#endif /* DEBUG_MCHECK_DUMP */ /* * Check if machine check is due to a badaddr() and if so, * ignore the machine check. */ - mb(); - mb(); /* magic */ - if (TSUNAMI_mcheck_expected[cpu]) { - DBG_MCK(("TSUNAMI machine check expected\n")); - TSUNAMI_mcheck_expected[cpu] = 0; - TSUNAMI_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - tsunami_pci_clr_err(); - wrmces(0x7); - mb(); - } -#if 1 - else { - printk("TSUNAMI machine check NOT expected\n") ; - DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n", - vector, la_ptr)); - DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, - mchk_header->sys_offset)); - TSUNAMI_mcheck_expected[cpu] = 0; - TSUNAMI_mcheck_taken[cpu] = 1; - mb(); - mb(); /* magic */ - draina(); - tsunami_pci_clr_err(); - wrmces(0x7); - mb(); - } -#endif -#endif + process_mcheck_info(vector, la_ptr, regs, "TSUNAMI", + DEBUG_MCHECK, TSUNAMI_mcheck_expected[cpu]); + + TSUNAMI_mcheck_expected[cpu] = 0; + TSUNAMI_mcheck_taken[cpu] = 1; } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/es1888.c linux/arch/alpha/kernel/es1888.c --- v2.2.10/linux/arch/alpha/kernel/es1888.c Sun Aug 9 12:09:05 1998 +++ linux/arch/alpha/kernel/es1888.c Mon Aug 9 12:04:38 1999 @@ -32,6 +32,7 @@ continue; inb(0x022a); /* pause */ outb(0xc6, 0x022c); /* enable extended mode */ + inb(0x022a); /* pause, also forces the write */ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ continue; outb(0xb1, 0x022c); /* setup for write to Interrupt CR */ @@ -44,4 +45,5 @@ while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */ continue; outb(0x18, 0x022c); /* set DMA channel 1 */ + inb(0x022c); /* force the write */ } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c --- v2.2.10/linux/arch/alpha/kernel/fpreg.c Sat May 22 13:41:47 1999 +++ linux/arch/alpha/kernel/fpreg.c Mon Aug 9 12:04:57 1999 @@ -96,3 +96,96 @@ case 31: LDT(31, val); break; } } + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define STS(reg,val) asm volatile ("ftois $f"#reg",%0" : "=r"(val)); +#else +#define STS(reg,val) asm volatile ("sts $f"#reg",%0" : "=m"(val)); +#endif + +unsigned long +alpha_read_fp_reg_s (unsigned long reg) +{ + unsigned long val; + + switch (reg) { + case 0: STS( 0, val); break; + case 1: STS( 1, val); break; + case 2: STS( 2, val); break; + case 3: STS( 3, val); break; + case 4: STS( 4, val); break; + case 5: STS( 5, val); break; + case 6: STS( 6, val); break; + case 7: STS( 7, val); break; + case 8: STS( 8, val); break; + case 9: STS( 9, val); break; + case 10: STS(10, val); break; + case 11: STS(11, val); break; + case 12: STS(12, val); break; + case 13: STS(13, val); break; + case 14: STS(14, val); break; + case 15: STS(15, val); break; + case 16: STS(16, val); break; + case 17: STS(17, val); break; + case 18: STS(18, val); break; + case 19: STS(19, val); break; + case 20: STS(20, val); break; + case 21: STS(21, val); break; + case 22: STS(22, val); break; + case 23: STS(23, val); break; + case 24: STS(24, val); break; + case 25: STS(25, val); break; + case 26: STS(26, val); break; + case 27: STS(27, val); break; + case 28: STS(28, val); break; + case 29: STS(29, val); break; + case 30: STS(30, val); break; + case 31: STS(31, val); break; + } + return val; +} + +#if defined(__alpha_cix__) || defined(__alpha_fix__) +#define LDS(reg,val) asm volatile ("itofs %0,$f"#reg : : "r"(val)); +#else +#define LDS(reg,val) asm volatile ("lds $f"#reg",%0" : : "m"(val)); +#endif + +void +alpha_write_fp_reg_s (unsigned long reg, unsigned long val) +{ + switch (reg) { + case 0: LDS( 0, val); break; + case 1: LDS( 1, val); break; + case 2: LDS( 2, val); break; + case 3: LDS( 3, val); break; + case 4: LDS( 4, val); break; + case 5: LDS( 5, val); break; + case 6: LDS( 6, val); break; + case 7: LDS( 7, val); break; + case 8: LDS( 8, val); break; + case 9: LDS( 9, val); break; + case 10: LDS(10, val); break; + case 11: LDS(11, val); break; + case 12: LDS(12, val); break; + case 13: LDS(13, val); break; + case 14: LDS(14, val); break; + case 15: LDS(15, val); break; + case 16: LDS(16, val); break; + case 17: LDS(17, val); break; + case 18: LDS(18, val); break; + case 19: LDS(19, val); break; + case 20: LDS(20, val); break; + case 21: LDS(21, val); break; + case 22: LDS(22, val); break; + case 23: LDS(23, val); break; + case 24: LDS(24, val); break; + case 25: LDS(25, val); break; + case 26: LDS(26, val); break; + case 27: LDS(27, val); break; + case 28: LDS(28, val); break; + case 29: LDS(29, val); break; + case 30: LDS(30, val); break; + case 31: LDS(31, val); break; + } +} diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.2.10/linux/arch/alpha/kernel/irq.c Sat May 22 13:42:26 1999 +++ linux/arch/alpha/kernel/irq.c Mon Aug 9 12:05:05 1999 @@ -868,31 +868,23 @@ unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - unsigned long flags; - switch (type) { case 0: #ifdef __SMP__ - __save_and_cli(flags); handle_ipi(®s); - __restore_flags(flags); return; #else printk("Interprocessor interrupt? You must be kidding\n"); #endif break; case 1: - __save_and_cli(flags); handle_irq(RTC_IRQ, -1, ®s); - __restore_flags(flags); return; case 2: alpha_mv.machine_check(vector, la_ptr, ®s); return; case 3: - __save_and_cli(flags); alpha_mv.device_interrupt(vector, ®s); - __restore_flags(flags); return; case 4: perf_irq(vector, ®s); @@ -908,4 +900,85 @@ { wrent(entInt, 0); alpha_mv.init_irq(); +} + +/* + * Machine check reasons. Defined according to PALcode sources + * (osf.h and platform.h). + */ +#define MCHK_K_TPERR 0x0080 +#define MCHK_K_TCPERR 0x0082 +#define MCHK_K_HERR 0x0084 +#define MCHK_K_ECC_C 0x0086 +#define MCHK_K_ECC_NC 0x0088 +#define MCHK_K_OS_BUGCHECK 0x008A +#define MCHK_K_PAL_BUGCHECK 0x0090 + +void +process_mcheck_info(unsigned long vector, unsigned long la_ptr, + struct pt_regs *regs, char *machine, + unsigned int debug, unsigned int expected) +{ + struct el_common *mchk_header; + unsigned long *ptr; + char *reason; + int i; + + /* + * See if the machine check is due to a badaddr() and if so, + * ignore it. + */ + if (debug) + printk(KERN_CRIT "%s machine check %s\n", machine, + (expected?"expected.":"NOT expected!!!")); + if (expected) + return; + + mchk_header = (struct el_common *)la_ptr; + + printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n", + machine, vector, regs->pc, mchk_header->code); + + switch ((unsigned int) mchk_header->code) { + case MCHK_K_TPERR: reason = "tag parity error"; break; + case MCHK_K_TCPERR: reason = "tag control parity error"; break; + case MCHK_K_HERR: reason = "generic hard error"; break; + case MCHK_K_ECC_C: reason = "correctable ECC error"; break; + case MCHK_K_ECC_NC: reason = "uncorrectable ECC error"; break; + case MCHK_K_OS_BUGCHECK: reason = "OS-specific PAL bugcheck"; break; + case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break; + case 0x96: reason = "i-cache read retryable error"; break; + case 0x98: reason = "processor detected hard error"; break; + + /* System specific (these are for Alcor, at least): */ + case 0x203: reason = "system detected uncorrectable ECC error"; break; + case 0x205: reason = "parity error detected by CIA"; break; + case 0x207: reason = "non-existent memory error"; break; + case 0x209: reason = "PCI SERR detected"; break; + case 0x20b: reason = "PCI data parity error detected"; break; + case 0x20d: reason = "PCI address parity error detected"; break; + case 0x20f: reason = "PCI master abort error"; break; + case 0x211: reason = "PCI target abort error"; break; + case 0x213: reason = "scatter/gather PTE invalid error"; break; + case 0x215: reason = "flash ROM write error"; break; + case 0x217: reason = "IOA timeout detected"; break; + case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break; + case 0x21b: reason = "EISA fail-safe timer timeout"; break; + case 0x21d: reason = "EISA bus time-out"; break; + case 0x21f: reason = "EISA software generated NMI"; break; + case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break; + default: reason = "unknown"; break; + } + printk(KERN_CRIT "machine check type: %s%s\n", + reason, mchk_header->retry ? " (retryable)" : ""); + + if (debug > 1) { + + /* Dump the logout area to give all info. */ + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(KERN_CRIT " +%8lx %016lx %016lx\n", + i*sizeof(long), ptr[i], ptr[i+1]); + } + } } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h --- v2.2.10/linux/arch/alpha/kernel/irq.h Wed Dec 30 15:06:22 1998 +++ linux/arch/alpha/kernel/irq.h Mon Aug 9 12:04:38 1999 @@ -24,6 +24,23 @@ extern void handle_irq(int irq, int ack, struct pt_regs * regs); +extern char _stext; +static inline void alpha_do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len - 1) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } +} + #define RTC_IRQ 8 #ifdef CONFIG_RTC #define TIMER_IRQ 0 /* timer is the pit */ diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/machvec.h linux/arch/alpha/kernel/machvec.h --- v2.2.10/linux/arch/alpha/kernel/machvec.h Sun Jan 10 09:59:54 1999 +++ linux/arch/alpha/kernel/machvec.h Mon Aug 9 12:04:38 1999 @@ -36,7 +36,6 @@ #define DO_EV4_MMU \ max_asn: EV4_MAX_ASN, \ - mmu_context_mask: ~0UL, \ mv_get_mmu_context: ev4_get_mmu_context, \ mv_flush_tlb_current: ev4_flush_tlb_current, \ mv_flush_tlb_other: ev4_flush_tlb_other, \ @@ -44,7 +43,6 @@ #define DO_EV5_MMU \ max_asn: EV5_MAX_ASN, \ - mmu_context_mask: ~0UL, \ mv_get_mmu_context: ev5_get_mmu_context, \ mv_flush_tlb_current: ev5_flush_tlb_current, \ mv_flush_tlb_other: ev5_flush_tlb_other, \ @@ -52,7 +50,6 @@ #define DO_EV6_MMU \ max_asn: EV6_MAX_ASN, \ - mmu_context_mask: 0xfffffffffful, \ mv_get_mmu_context: ev5_get_mmu_context, \ mv_flush_tlb_current: ev5_flush_tlb_current, \ mv_flush_tlb_other: ev5_flush_tlb_other, \ diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.2.10/linux/arch/alpha/kernel/osf_sys.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/kernel/osf_sys.c Mon Aug 9 12:04:57 1999 @@ -925,6 +925,7 @@ return -EINVAL; cpu = (struct percpu_struct*) ((char*)hwrpb + hwrpb->processor_offset); + w = cpu->type; if (put_user(w, (unsigned long *)buffer)) return -EFAULT; return 1; @@ -949,7 +950,7 @@ { switch (op) { case SSI_IEEE_FP_CONTROL: { - unsigned long swcr, fpcr, undz; + unsigned long swcr, fpcr, undz, ev6; /* * Alpha Architecture Handbook 4.7.7.3: @@ -958,6 +959,8 @@ * set in the trap shadow of a software-complete insn. */ + ev6 = (implver() == IMPLVER_EV6); + /* Update softare trap enable bits. */ if (get_user(swcr, (unsigned long *)buffer)) return -EFAULT; @@ -966,10 +969,17 @@ /* Update the real fpcr. Keep UNFD off if not UNDZ. */ fpcr = rdfpcr(); - undz = (fpcr & FPCR_UNDZ); - fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ); + if(ev6) { + undz = (fpcr & FPCR_UNDZ); + fpcr &= (~(FPCR_MASK | FPCR_UNDZ)) | FPCR_DYN_MASK; + } + else { + fpcr &= (~FPCR_MASK) | FPCR_DYN_MASK; + } fpcr |= ieee_swcr_to_fpcr(swcr); - fpcr &= ~(undz << 1); + if(ev6 && !undz) { + fpcr &= ~FPCR_UNFD; + } wrfpcr(fpcr); return 0; diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.2.10/linux/arch/alpha/kernel/process.c Sat May 22 13:42:29 1999 +++ linux/arch/alpha/kernel/process.c Mon Aug 9 12:04:38 1999 @@ -76,7 +76,7 @@ } #ifdef __SMP__ -void +int cpu_idle(void *unused) { /* An endless idle loop with no priority at all. */ @@ -329,7 +329,6 @@ p->tss.ksp = (unsigned long) childstack; p->tss.pal_flags = 1; /* set FEN, clear everything else */ p->tss.flags = current->tss.flags; - p->mm->context = 0; return 0; } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.2.10/linux/arch/alpha/kernel/proto.h Sat Jun 12 11:52:52 1999 +++ linux/arch/alpha/kernel/proto.h Mon Aug 9 12:05:05 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); @@ -201,3 +201,9 @@ /* ../mm/init.c */ void srm_paging_stop(void); + +/* irq.c */ +extern void process_mcheck_info(unsigned long vector, unsigned long la_ptr, + struct pt_regs *regs, char *machine, + unsigned int debug, unsigned int expected); + diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.2.10/linux/arch/alpha/kernel/setup.c Sat May 22 13:42:31 1999 +++ linux/arch/alpha/kernel/setup.c Mon Aug 9 12:05:13 1999 @@ -66,7 +66,7 @@ * initialized, we need to copy things out into a more permanent * place. */ -#define PARAM ZERO_PAGE +#define PARAM ZERO_PAGE(0) #define COMMAND_LINE ((char*)(PARAM + 0x0000)) #define COMMAND_LINE_SIZE 256 #define INITRD_START (*(unsigned long *) (PARAM+0x100)) @@ -224,9 +224,16 @@ alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; #endif - printk("Booting on %s%s%s using machine vector %s\n", + printk("%s on %s%s%s using machine vector %s from %s\n", +#ifdef CONFIG_ALPHA_GENERIC + "Booting GENERIC", +#else + "Booting", +#endif type_name, (*var_name ? " variation " : ""), - var_name, alpha_mv.vector_name); + var_name, alpha_mv.vector_name, + (alpha_using_srm ? "SRM" : "MILO")); + printk("Command line: %s\n", command_line); /* @@ -727,7 +734,8 @@ "BogoMIPS\t\t: %lu.%02lu\n" "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "platform string\t\t: %s\n", + "platform string\t\t: %s\n" + "cpus detected\t\t: %ld\n", cpu_name, cpu->variation, cpu->revision, (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, @@ -742,7 +750,7 @@ loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va, - platform_string()); + platform_string(), hwrpb->nr_processors); #ifdef __SMP__ len += smp_info(buffer+len); diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.2.10/linux/arch/alpha/kernel/signal.c Sat Jun 12 11:52:52 1999 +++ linux/arch/alpha/kernel/signal.c Mon Aug 9 12:04:38 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.2.10/linux/arch/alpha/kernel/smp.c Sat Jun 12 11:52:52 1999 +++ linux/arch/alpha/kernel/smp.c Mon Aug 9 12:04:38 1999 @@ -95,6 +95,8 @@ smp_store_cpu_info(int cpuid) { cpu_data[cpuid].loops_per_sec = loops_per_sec; + cpu_data[cpuid].last_asn + = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION; } /* @@ -105,12 +107,6 @@ { cpu_data[cpuid].prof_counter = 1; cpu_data[cpuid].prof_multiplier = 1; - -#ifdef NOT_YET_PROFILING - load_profile_irq(mid_xlate[cpu], lvl14_resolution); - if (cpu == smp_boot_cpuid) - enable_pil_irq(14); -#endif } /* @@ -587,11 +583,9 @@ int user = user_mode(regs); struct cpuinfo_alpha *data = &cpu_data[cpu]; -#ifdef NOT_YET_PROFILING - clear_profile_irq(mid_xlate[cpu]); + /* Record kernel PC */ if (!user) alpha_do_profile(regs->pc); -#endif if (!--data->prof_counter) { /* We need to make like a normal interrupt -- otherwise @@ -628,28 +622,7 @@ int __init setup_profiling_timer(unsigned int multiplier) { -#ifdef NOT_YET_PROFILING - int i; - unsigned long flags; - - /* Prevent level14 ticker IRQ flooding. */ - if((!multiplier) || (lvl14_resolution / multiplier) < 500) - return -EINVAL; - - save_and_cli(flags); - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_mask & (1L << i)) { - load_profile_irq(mid_xlate[i], - lvl14_resolution / multiplier); - prof_multiplier[i] = multiplier; - } - } - restore_flags(flags); - - return 0; -#else return -EINVAL; -#endif } @@ -891,9 +864,11 @@ void flush_tlb_mm(struct mm_struct *mm) { - if (mm == current->mm) + if (mm == current->mm) { flush_tlb_current(mm); - else + if (atomic_read(&mm->count) == 1) + return; + } else flush_tlb_other(mm); if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { @@ -921,15 +896,17 @@ struct flush_tlb_page_struct data; struct mm_struct *mm = vma->vm_mm; + if (mm == current->mm) { + flush_tlb_current_page(mm, vma, addr); + if (atomic_read(¤t->mm->count) == 1) + return; + } else + flush_tlb_other(mm); + data.vma = vma; data.mm = mm; data.addr = addr; - if (mm == current->mm) - flush_tlb_current_page(mm, vma, addr); - else - flush_tlb_other(mm); - if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) { printk(KERN_CRIT "flush_tlb_page: timed out\n"); } diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.2.10/linux/arch/alpha/kernel/sys_dp264.c Sat Jun 12 11:52:52 1999 +++ linux/arch/alpha/kernel/sys_dp264.c Mon Aug 9 12:04:38 1999 @@ -393,8 +393,8 @@ { layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); common_pci_fixup(monet_map_irq, monet_swizzle); - /* es1888_init(); */ /* later? */ SMC669_Init(1); + es1888_init(); } static void __init diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- v2.2.10/linux/arch/alpha/kernel/sys_miata.c Sun Feb 21 19:06:36 1999 +++ linux/arch/alpha/kernel/sys_miata.c Mon Aug 9 12:05:05 1999 @@ -271,6 +271,17 @@ es1888_init(); } +static void +miata_kill_arch (int mode, char *reboot_cmd) +{ + /* Who said DEC engineers have no sense of humor? ;-) */ + if (alpha_using_srm) { + *(vuip) PYXIS_RESET = 0x0000dead; + mb(); + } + generic_kill_arch(mode, reboot_cmd); +} + /* * The System Vector @@ -295,6 +306,6 @@ init_irq: miata_init_irq, init_pit: generic_init_pit, pci_fixup: miata_pci_fixup, - kill_arch: generic_kill_arch, + kill_arch: miata_kill_arch, }; ALIAS_MV(miata) diff -u --recursive --new-file v2.2.10/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.2.10/linux/arch/alpha/kernel/time.c Sat Jun 12 11:52:52 1999 +++ linux/arch/alpha/kernel/time.c Mon Aug 9 12:04:38 1999 @@ -94,6 +94,11 @@ smp_percpu_timer_interrupt(regs); if (smp_processor_id() != smp_boot_cpuid) return; +#else + /* Not SMP, do kernel PC profiling here */ + if (!user_mode(regs)) { + alpha_do_profile(regs->pc); + } #endif write_lock(&xtime_lock); diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile --- v2.2.10/linux/arch/alpha/math-emu/Makefile Thu Feb 12 13:31:28 1998 +++ linux/arch/alpha/math-emu/Makefile Mon Aug 9 12:04:57 1999 @@ -3,10 +3,27 @@ # O_TARGET := math-emu.o -O_OBJS := fp-emul.o ieee-math.o +O_OBJS := fp-emul.o faddd.o fadds.o fdivd.o fdivs.o fdtoi.o \ + fdtos.o fdtox.o fmuld.o fmuls.o fsmuld.o fsqrtd.o \ + fsqrts.o fstod.o fstoi.o fstox.o fsubd.o fsubs.o \ + cmptxx.o fxtos.o fxtod.o udivmodti4.o div128.o + +LINKS := double.h faddd.c fadds.c fdivd.c fdivs.c fdtoi.c \ + fdtos.c fdtox.c fmuld.c fmuls.c fsmuld.c fsqrtd.c \ + fsqrts.c fstod.c fstoi.c fstox.c fsubd.c fsubs.c \ + op-common.h op-1.h op-2.h op-4.h single.h soft-fp.h \ + udivmodti4.c + + ifeq ($(CONFIG_MATHEMU),m) M_OBJS := $(O_TARGET) endif include $(TOPDIR)/Rules.make + +symlinks: + ln -sf $(patsubst %,../../sparc64/math-emu/%,$(LINKS)) . + +cleansymlinks: + rm -f $(LINKS) diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/cmptxx.c linux/arch/alpha/math-emu/cmptxx.c --- v2.2.10/linux/arch/alpha/math-emu/cmptxx.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/cmptxx.c Mon Aug 9 12:04:57 1999 @@ -0,0 +1,23 @@ +#include "soft-fp.h" +#include "double.h" + +int CMPTXX(void *rc, void *rb, void *ra, int type) +{ + FP_DECL_D(A); FP_DECL_D(B); + long ret; + + __FP_UNPACK_D(A, ra); + __FP_UNPACK_D(B, rb); + FP_CMP_D(ret, A, B, 3); + if(ret == type) { + *(unsigned long *)rc = 0x4000000000000000; + } + else if((type == CMPTXX_LE) && + ((ret == CMPTXX_LT) || (ret == CMPTXX_EQ))) { + *(unsigned long *)rc = 0x4000000000000000; + } + else { + *(unsigned long *)rc = 0; + } + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/div128.c linux/arch/alpha/math-emu/div128.c --- v2.2.10/linux/arch/alpha/math-emu/div128.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/div128.c Mon Aug 9 12:04:57 1999 @@ -0,0 +1,125 @@ +/* + Copyright stuff + + Use of this program, for any purpose, is granted the author, + Ian Kaplan, as long as this copyright notice is included in + the source code or any source code derived from this program. + The user assumes all responsibility for using this code. + + Ian Kaplan, October 1996 + +*/ + +#define HI 0 +#define LO 1 + +void set128(unsigned long *n, unsigned long hi, unsigned long lo) +{ + n[HI] = hi; + n[LO] = lo; +} + +int eq128(unsigned long *n1, unsigned long *n2) +{ + return((n1[HI] == n2[HI]) && (n1[LO] == n2[LO])); +} + +int gt128(unsigned long *n1, unsigned long *n2) +{ + return((n1[HI] > n2[HI]) || + ((n1[HI] == n2[HI]) && (n1[LO] > n2[LO]))); +} + +int lt128(unsigned long *n1, unsigned long *n2) +{ + return((n1[HI] < n2[HI]) || + ((n1[HI] == n2[HI]) && (n1[LO] < n2[LO]))); +} + + +void copy128(unsigned long *dest, unsigned long *src) +{ + dest[HI] = src[HI]; + dest[LO] = src[LO]; +} + +/* Shift the given bit into the octaword from the right + * (i.e. left-shift-1, or in low bit). If "bit" is zero, + * then this is a simple left shift. + */ +void shiftin128(unsigned long *n, unsigned long bit) +{ + n[HI] <<= 1; + if(n[LO] & 0x8000000000000000) { + n[HI] |= 1; + } + n[LO] = (n[LO] << 1) | bit; +} + +void sub128(unsigned long *n1, unsigned long *n2, unsigned long *result) +{ + if(n1[LO] < n2[LO]) { + result[LO] = n1[LO] - n2[LO]; + result[HI] = n1[HI] - n2[HI] - 1; + } + else { + result[LO] = n1[LO] - n2[LO]; + result[HI] = n1[HI] - n2[HI]; + } +} + + +void udiv128(unsigned long *dividend, + unsigned long *divisor, + unsigned long *quotient, + unsigned long *remainder ) +{ + unsigned long zero[2]; + unsigned long t[2], num_bits; + unsigned long q, bit; + unsigned long rem[2]; + int i; + + set128(remainder, 0, 0); + set128(quotient, 0, 0); + set128(zero, 0, 0); + + if (eq128(divisor, zero)) { + return; + } + + if(gt128(divisor, dividend)) { + copy128(remainder, dividend); + return; + } + + if (eq128(divisor, dividend)) { + set128(quotient, 0, 1); + return; + } + + num_bits = 128; + + while(1) { + bit = (dividend[HI] & 0x8000000000000000) >> 63; + copy128(rem, remainder); + shiftin128(rem, bit); + if(lt128(rem, divisor)) break; + copy128(remainder, rem); + shiftin128(dividend, 0); + num_bits--; + } + + for (i = 0; i < num_bits; i++) { + bit = (dividend[HI] & 0x8000000000000000) >> 63; + shiftin128(remainder, bit); + sub128(remainder, divisor, t); + q = !((t[HI] & 0x8000000000000000) >> 63); + shiftin128(dividend, 0); + shiftin128(quotient, q); + if (q) { + copy128(remainder, t); + } + } +} /* unsigned_divide128 */ + diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c --- v2.2.10/linux/arch/alpha/math-emu/fp-emul.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/math-emu/fp-emul.c Mon Aug 9 12:04:57 1999 @@ -5,7 +5,24 @@ #include -#include "ieee-math.h" +#include "soft-fp.h" + +extern int CMPTXX(void *, void *, void *, int); +extern int FXTOS(void *, void *); +extern int FXTOD(void *, void *); +extern int FDTOS(void *, void *); +extern int FSTOD(void *, void *); +extern int FDIVS(void *, void *, void *); +extern int FDIVD(void *, void *, void *); +extern int FMULS(void *, void *, void *); +extern int FMULD(void *, void *, void *); +extern int FSUBS(void *, void *, void *); +extern int FSUBD(void *, void *, void *); +extern int FADDS(void *, void *, void *); +extern int FADDD(void *, void *, void *); +extern int FDTOX(void *, void *); +extern int FSQRTS(void *, void *); +extern int FSQRTD(void *, void *); #define OPC_PAL 0x00 @@ -59,6 +76,8 @@ extern unsigned long alpha_read_fp_reg (unsigned long reg); extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); +extern unsigned long alpha_read_fp_reg_s (unsigned long reg); +extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val); #ifdef MODULE @@ -118,43 +137,58 @@ fb = (insn >> 16) & 0x1f; fa = (insn >> 21) & 0x1f; func = (insn >> 5) & 0x7ff; - mode = (insn >> 5) & 0xc0; + mode = (insn >> 11) & 0x3; op_fun = insn & OP_FUN(0x3f, 0x3f); - va = alpha_read_fp_reg(fa); - vb = alpha_read_fp_reg(fb); fpcr = rdfpcr(); /* * Try the operation in software. First, obtain the rounding - * mode... + * mode and set it in the task struct */ - if (mode == 0xc0) { + current->tss.flags &= ~IEEE_CURRENT_RM_MASK; + if (mode == 3) { /* dynamic---get rounding mode from fpcr: */ - mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT; + current->tss.flags |= + (((fpcr&FPCR_DYN_MASK)>>FPCR_DYN_SHIFT)<tss.flags |= (mode << IEEE_CURRENT_RM_SHIFT); } - mode |= (fpcw & IEEE_TRAP_ENABLE_MASK); - if ((IEEE_TRAP_ENABLE_MASK & 0xc0)) { + /* JRP - What is this test supposed to check for? */ + if ((IEEE_TRAP_ENABLE_MASK & 0x80 /* was 0xc0 */)) { extern int something_is_wrong (void); something_is_wrong(); } switch (op_fun) { case FLTI_FUNC_CMPTEQ: - res = ieee_CMPTEQ(va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = CMPTXX(&vc, &vb, &va, CMPTXX_EQ); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CMPTLT: - res = ieee_CMPTLT(va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = CMPTXX(&vc, &vb, &va, CMPTXX_LT); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CMPTLE: - res = ieee_CMPTLE(va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = CMPTXX(&vc, &vb, &va, CMPTXX_LE); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CMPTUN: - res = ieee_CMPTUN(va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = CMPTXX(&vc, &vb, &va, CMPTXX_UN); + alpha_write_fp_reg(fc, vc); break; case FLTL_FUNC_CVTQL: @@ -164,17 +198,23 @@ * ops. We return the result the hw would have * computed. */ + vb = alpha_read_fp_reg(fb); vc = ((vb & 0xc0000000) << 32 | /* sign and msb */ (vb & 0x3fffffff) << 29); /* rest of the integer */ - res = FPCR_INV; + res = EFLAG_INVALID; + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CVTQS: - res = ieee_CVTQS(mode, vb, &vc); + vb = alpha_read_fp_reg(fb); + res = FXTOS(&vc, &vb); + alpha_write_fp_reg_s(fc, vc); break; case FLTI_FUNC_CVTQT: - res = ieee_CVTQT(mode, vb, &vc); + vb = alpha_read_fp_reg(fb); + res = FXTOD(&vc, &vb); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CVTTS_or_CVTST: @@ -184,54 +224,88 @@ * qualifier isn't set, we wouldn't be here in * the first place... */ - res = ieee_CVTST(mode, vb, &vc); + vb = alpha_read_fp_reg_s(fb); + res = FSTOD(&vc, &vb); + alpha_write_fp_reg(fc, vc); } else { - res = ieee_CVTTS(mode, vb, &vc); + vb = alpha_read_fp_reg(fb); + res = FDTOS(&vc, &vb); + alpha_write_fp_reg_s(fc, vc); } break; case FLTI_FUNC_DIVS: - res = ieee_DIVS(mode, va, vb, &vc); + va = alpha_read_fp_reg_s(fa); + vb = alpha_read_fp_reg_s(fb); + res = FDIVS(&vc, &vb, &va); + alpha_write_fp_reg_s(fc, vc); break; case FLTI_FUNC_DIVT: - res = ieee_DIVT(mode, va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = FDIVD(&vc, &vb, &va); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_MULS: - res = ieee_MULS(mode, va, vb, &vc); + va = alpha_read_fp_reg_s(fa); + vb = alpha_read_fp_reg_s(fb); + res = FMULS(&vc, &vb, &va); + alpha_write_fp_reg_s(fc, vc); break; case FLTI_FUNC_MULT: - res = ieee_MULT(mode, va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = FMULD(&vc, &vb, &va); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_SUBS: - res = ieee_SUBS(mode, va, vb, &vc); + va = alpha_read_fp_reg_s(fa); + vb = alpha_read_fp_reg_s(fb); + res = FSUBS(&vc, &vb, &va); + alpha_write_fp_reg_s(fc, vc); break; case FLTI_FUNC_SUBT: - res = ieee_SUBT(mode, va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = FSUBD(&vc, &vb, &va); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_ADDS: - res = ieee_ADDS(mode, va, vb, &vc); + va = alpha_read_fp_reg_s(fa); + vb = alpha_read_fp_reg_s(fb); + res = FADDS(&vc, &vb, &va); + alpha_write_fp_reg_s(fc, vc); break; case FLTI_FUNC_ADDT: - res = ieee_ADDT(mode, va, vb, &vc); + va = alpha_read_fp_reg(fa); + vb = alpha_read_fp_reg(fb); + res = FADDD(&vc, &vb, &va); + alpha_write_fp_reg(fc, vc); break; case FLTI_FUNC_CVTTQ: - res = ieee_CVTTQ(mode, vb, &vc); + vb = alpha_read_fp_reg(fb); + res = FDTOX(&vc, &vb); + alpha_write_fp_reg(fc, vc); break; case FLTC_FUNC_SQRTS: - res = ieee_SQRTS(mode, vb, &vc); + vb = alpha_read_fp_reg_s(fb); + res = FSQRTS(&vc, &vb); + alpha_write_fp_reg_s(fc, vc); break; case FLTC_FUNC_SQRTT: - res = ieee_SQRTT(mode, vb, &vc); + vb = alpha_read_fp_reg(fb); + res = FSQRTD(&vc, &vb); + alpha_write_fp_reg(fc, vc); break; default: @@ -255,7 +329,7 @@ */ if (res) { /* Record exceptions in software control word. */ - current->tss.flags = fpcw |= res >> 35; + current->tss.flags = fpcw |= (res << IEEE_STATUS_TO_EXCSUM_SHIFT); /* Update hardware control register */ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); @@ -263,18 +337,17 @@ wrfpcr(fpcr); /* Do we generate a signal? */ - if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) { + if (res & fpcw & IEEE_TRAP_ENABLE_MASK) { MOD_DEC_USE_COUNT; return 0; } } - /* - * Whoo-kay... we got this far, and we're not generating a signal - * to the translated program. All that remains is to write the - * result: + /* We used to write the destination register here, but + * DEC FORTRAN requires that the result *always* be + * written... so we do the write immediately after + * the operations above. */ - alpha_write_fp_reg(fc, vc); MOD_DEC_USE_COUNT; return 1; diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/fxtod.c linux/arch/alpha/math-emu/fxtod.c --- v2.2.10/linux/arch/alpha/math-emu/fxtod.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/fxtod.c Mon Aug 9 12:04:57 1999 @@ -0,0 +1,11 @@ +#include "soft-fp.h" +#include "double.h" + +int FXTOD(void *rd, void *rs2) +{ + FP_DECL_D(R); + long a = *(long *)rs2; + + FP_FROM_INT_D(R, a, 64, long); + return __FP_PACK_D(rd, R); +} diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/fxtos.c linux/arch/alpha/math-emu/fxtos.c --- v2.2.10/linux/arch/alpha/math-emu/fxtos.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/fxtos.c Mon Aug 9 12:04:57 1999 @@ -0,0 +1,11 @@ +#include "soft-fp.h" +#include "single.h" + +int FXTOS(void *rd, void *rs2) +{ + FP_DECL_S(R); + long a = *(long *)rs2; + + FP_FROM_INT_S(R, a, 64, long); + return __FP_PACK_S(rd, R); +} diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c --- v2.2.10/linux/arch/alpha/math-emu/ieee-math.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/math-emu/ieee-math.c Wed Dec 31 16:00:00 1969 @@ -1,1381 +0,0 @@ -/* - * ieee-math.c - IEEE floating point emulation code - * Copyright (C) 1989,1990,1991,1995 by - * Digital Equipment Corporation, Maynard, Massachusetts. - * - * Heavily modified for Linux/Alpha. Changes are Copyright (c) 1995 - * by David Mosberger (davidm@azstarnet.com). - * - * This file may be redistributed according to the terms of the - * GNU General Public License. - */ -/* - * The original code did not have any comments. I have created many - * comments as I fix the bugs in the code. My comments are based on - * my observation and interpretation of the code. If the original - * author would have spend a few minutes to comment the code, we would - * never had a problem of misinterpretation. -HA - * - * This code could probably be a lot more optimized (especially the - * division routine). However, my foremost concern was to get the - * IEEE behavior right. Performance is less critical as these - * functions are used on exceptional numbers only (well, assuming you - * don't turn on the "trap on inexact"...). - */ -#include -#include "ieee-math.h" - -#define STICKY_S 0x20000000 /* both in longword 0 of fraction */ -#define STICKY_T 1 - -/* - * Careful: order matters here! - */ -enum { - NaN, QNaN, INFTY, ZERO, DENORM, NORMAL -}; - -enum { - SINGLE, DOUBLE -}; - -typedef unsigned long fpclass_t; - -#define IEEE_TMAX 0x7fefffffffffffff -#define IEEE_SMAX 0x47efffffe0000000 -#define IEEE_SNaN 0xfff00000000f0000 -#define IEEE_QNaN 0xfff8000000000000 -#define IEEE_PINF 0x7ff0000000000000 -#define IEEE_NINF 0xfff0000000000000 - - -/* - * The memory format of S floating point numbers differs from the - * register format. In the following, the bitnumbers above the - * diagram below give the memory format while the numbers below give - * the register format. - * - * 31 30 23 22 0 - * +-----------------------------------------------+ - * S | s | exp | fraction | - * +-----------------------------------------------+ - * 63 62 52 51 29 - * - * For T floating point numbers, the register and memory formats - * match: - * - * +-------------------------------------------------------------------+ - * T | s | exp | frac | tion | - * +-------------------------------------------------------------------+ - * 63 62 52 51 32 31 0 - */ -typedef struct { - unsigned long f[2]; /* bit 55 in f[0] is the factor of 2^0*/ - int s; /* 1 bit sign (0 for +, 1 for -) */ - int e; /* 16 bit signed exponent */ -} EXTENDED; - - -/* - * Return the sign of a Q integer, S or T fp number in the register - * format. - */ -static inline int -sign (unsigned long a) -{ - if ((long) a < 0) - return -1; - else - return 1; -} - - -static inline long -cmp128 (const long a[2], const long b[2]) -{ - if (a[1] < b[1]) return -1; - if (a[1] > b[1]) return 1; - return a[0] - b[0]; -} - - -static inline void -sll128 (unsigned long a[2]) -{ - a[1] = (a[1] << 1) | (a[0] >> 63); - a[0] <<= 1; -} - - -static inline void -srl128 (unsigned long a[2]) -{ - a[0] = (a[0] >> 1) | (a[1] << 63); - a[1] >>= 1; -} - - -static inline void -add128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2]) -{ - unsigned long carry = a[0] > (0xffffffffffffffff - b[0]); - - c[0] = a[0] + b[0]; - c[1] = a[1] + b[1] + carry; -} - - -static inline void -sub128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2]) -{ - unsigned long borrow = a[0] < b[0]; - - c[0] = a[0] - b[0]; - c[1] = a[1] - b[1] - borrow; -} - - -static inline void -mul64 (const unsigned long a, const unsigned long b, unsigned long c[2]) -{ - c[0] = a * b; - asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b)); -} - - -static void -div128 (unsigned long a[2], unsigned long b[2], unsigned long c[2]) -{ - unsigned long mask[2] = {1, 0}; - - /* - * Shift b until either the sign bit is set or until it is at - * least as big as the dividend: - */ - while (cmp128(b, a) < 0 && sign(b[1]) >= 0) { - sll128(b); - sll128(mask); - } - c[0] = c[1] = 0; - do { - if (cmp128(a, b) >= 0) { - sub128(a, b, a); - add128(mask, c, c); - } - srl128(mask); - srl128(b); - } while (mask[0] || mask[1]); -} - - -static void -normalize (EXTENDED *a) -{ - if (!a->f[0] && !a->f[1]) - return; /* zero fraction, unnormalizable... */ - /* - * In "extended" format, the "1" in "1.f" is explicit; it is - * in bit 55 of f[0], and the decimal point is understood to - * be between bit 55 and bit 54. To normalize, shift the - * fraction until we have a "1" in bit 55. - */ - if ((a->f[0] & 0xff00000000000000) != 0 || a->f[1] != 0) { - /* - * Mantissa is greater than 1.0: - */ - while ((a->f[0] & 0xff80000000000000) != 0x0080000000000000 || - a->f[1] != 0) - { - unsigned long sticky; - - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - a->f[0] |= sticky; - } - return; - } - - if (!(a->f[0] & 0x0080000000000000)) { - /* - * Mantissa is less than 1.0: - */ - while (!(a->f[0] & 0x0080000000000000)) { - --a->e; - a->f[0] <<= 1; - } - return; - } -} - - -static inline fpclass_t -ieee_fpclass (unsigned long a) -{ - unsigned long exp, fract; - - exp = (a >> 52) & 0x7ff; /* 11 bits of exponent */ - fract = a & 0x000fffffffffffff; /* 52 bits of fraction */ - if (exp == 0) { - if (fract == 0) - return ZERO; - return DENORM; - } - if (exp == 0x7ff) { - if (fract == 0) - return INFTY; - if (((fract >> 51) & 1) != 0) - return QNaN; - return NaN; - } - return NORMAL; -} - - -/* - * Translate S/T fp number in register format into extended format. - */ -static fpclass_t -extend_ieee (unsigned long a, EXTENDED *b, int prec) -{ - fpclass_t result_kind; - - b->s = a >> 63; - b->e = ((a >> 52) & 0x7ff) - 0x3ff; /* remove bias */ - b->f[1] = 0; - /* - * We shift f[1] left three bits so that the higher order bits - * of the fraction will reside in bits 55 through 0 of f[0]. - */ - b->f[0] = (a & 0x000fffffffffffff) << 3; - result_kind = ieee_fpclass(a); - if (result_kind == NORMAL) { - /* set implied 1. bit: */ - b->f[0] |= 1UL << 55; - } else if (result_kind == DENORM) { - if (prec == SINGLE) - b->e = -126; - else - b->e = -1022; - } - return result_kind; -} - - -/* - * INPUT PARAMETERS: - * a a number in EXTENDED format to be converted to - * s-floating format. - * f rounding mode and exception enable bits. - * OUTPUT PARAMETERS: - * b will contain the s-floating number that "a" was - * converted to (in register format). - */ -static unsigned long -make_s_ieee (long f, EXTENDED *a, unsigned long *b) -{ - unsigned long res, sticky; - - if (!a->e && !a->f[0] && !a->f[1]) { - *b = (unsigned long) a->s << 63; /* return +/-0 */ - return 0; - } - - normalize(a); - res = 0; - - if (a->e < -0x7e) { - res = FPCR_INE; - if (f & IEEE_TRAP_ENABLE_UNF) { - res |= FPCR_UNF; - a->e += 0xc0; /* scale up result by 2^alpha */ - } else { - /* try making denormalized number: */ - while (a->e < -0x7e) { - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - if (!a->f[0] && !a->f[0]) { - /* underflow: replace with exact 0 */ - res |= FPCR_UNF; - break; - } - a->f[0] |= sticky; - } - a->e = -0x3ff; - } - } - if (a->e >= 0x80) { - res = FPCR_OVF | FPCR_INE; - if (f & IEEE_TRAP_ENABLE_OVF) { - a->e -= 0xc0; /* scale down result by 2^alpha */ - } else { - /* - * Overflow without trap enabled, substitute - * result according to rounding mode: - */ - switch (RM(f)) { - case ROUND_NEAR: - *b = IEEE_PINF; - break; - - case ROUND_CHOP: - *b = IEEE_SMAX; - break; - - case ROUND_NINF: - if (a->s) { - *b = IEEE_PINF; - } else { - *b = IEEE_SMAX; - } - break; - - case ROUND_PINF: - if (a->s) { - *b = IEEE_SMAX; - } else { - *b = IEEE_PINF; - } - break; - } - *b |= ((unsigned long) a->s << 63); - return res; - } - } - - *b = (((unsigned long) a->s << 63) | - (((unsigned long) a->e + 0x3ff) << 52) | - ((a->f[0] >> 3) & 0x000fffffe0000000)); - return res; -} - - -static unsigned long -make_t_ieee (long f, EXTENDED *a, unsigned long *b) -{ - unsigned long res, sticky; - - if (!a->e && !a->f[0] && !a->f[1]) { - *b = (unsigned long) a->s << 63; /* return +/-0 */ - return 0; - } - - normalize(a); - res = 0; - if (a->e < -0x3fe) { - res = FPCR_INE; - if (f & IEEE_TRAP_ENABLE_UNF) { - res |= FPCR_UNF; - a->e += 0x600; - } else { - /* try making denormalized number: */ - while (a->e < -0x3fe) { - ++a->e; - sticky = a->f[0] & 1; - srl128(a->f); - if (!a->f[0] && !a->f[0]) { - /* underflow: replace with exact 0 */ - res |= FPCR_UNF; - break; - } - a->f[0] |= sticky; - } - a->e = -0x3ff; - } - } - if (a->e >= 0x3ff) { - res = FPCR_OVF | FPCR_INE; - if (f & IEEE_TRAP_ENABLE_OVF) { - a->e -= 0x600; /* scale down result by 2^alpha */ - } else { - /* - * Overflow without trap enabled, substitute - * result according to rounding mode: - */ - switch (RM(f)) { - case ROUND_NEAR: - *b = IEEE_PINF; - break; - - case ROUND_CHOP: - *b = IEEE_TMAX; - break; - - case ROUND_NINF: - if (a->s) { - *b = IEEE_PINF; - } else { - *b = IEEE_TMAX; - } - break; - - case ROUND_PINF: - if (a->s) { - *b = IEEE_TMAX; - } else { - *b = IEEE_PINF; - } - break; - } - *b |= ((unsigned long) a->s << 63); - return res; - } - } - *b = (((unsigned long) a->s << 63) | - (((unsigned long) a->e + 0x3ff) << 52) | - ((a->f[0] >> 3) & 0x000fffffffffffff)); - return res; -} - - -/* - * INPUT PARAMETERS: - * a EXTENDED format number to be rounded. - * rm integer with value ROUND_NEAR, ROUND_CHOP, etc. - * indicates how "a" should be rounded to produce "b". - * OUTPUT PARAMETERS: - * b s-floating number produced by rounding "a". - * RETURN VALUE: - * if no errors occurred, will be zero. Else will contain flags - * like FPCR_INE_OP, etc. - */ -static unsigned long -round_s_ieee (int f, EXTENDED *a, unsigned long *b) -{ - unsigned long diff1, diff2, res = 0; - EXTENDED z1, z2; - - if (!(a->f[0] & 0xffffffff)) { - return make_s_ieee(f, a, b); /* no rounding error */ - } - - /* - * z1 and z2 are the S-floating numbers with the next smaller/greater - * magnitude than a, respectively. - */ - z1.s = z2.s = a->s; - z1.e = z2.e = a->e; - z1.f[0] = z2.f[0] = a->f[0] & 0xffffffff00000000; - z1.f[1] = z2.f[1] = 0; - z2.f[0] += 0x100000000; /* next bigger S float number */ - - switch (RM(f)) { - case ROUND_NEAR: - diff1 = a->f[0] - z1.f[0]; - diff2 = z2.f[0] - a->f[0]; - if (diff1 > diff2) - res = make_s_ieee(f, &z2, b); - else if (diff2 > diff1) - res = make_s_ieee(f, &z1, b); - else - /* equal distance: round towards even */ - if (z1.f[0] & 0x100000000) - res = make_s_ieee(f, &z2, b); - else - res = make_s_ieee(f, &z1, b); - break; - - case ROUND_CHOP: - res = make_s_ieee(f, &z1, b); - break; - - case ROUND_PINF: - if (a->s) { - res = make_s_ieee(f, &z1, b); - } else { - res = make_s_ieee(f, &z2, b); - } - break; - - case ROUND_NINF: - if (a->s) { - res = make_s_ieee(f, &z2, b); - } else { - res = make_s_ieee(f, &z1, b); - } - break; - } - return FPCR_INE | res; -} - - -static unsigned long -round_t_ieee (int f, EXTENDED *a, unsigned long *b) -{ - unsigned long diff1, diff2, res; - EXTENDED z1, z2; - - if (!(a->f[0] & 0x7)) { - /* no rounding error */ - return make_t_ieee(f, a, b); - } - - z1.s = z2.s = a->s; - z1.e = z2.e = a->e; - z1.f[0] = z2.f[0] = a->f[0] & ~0x7; - z1.f[1] = z2.f[1] = 0; - z2.f[0] += (1 << 3); - - res = 0; - switch (RM(f)) { - case ROUND_NEAR: - diff1 = a->f[0] - z1.f[0]; - diff2 = z2.f[0] - a->f[0]; - if (diff1 > diff2) - res = make_t_ieee(f, &z2, b); - else if (diff2 > diff1) - res = make_t_ieee(f, &z1, b); - else - /* equal distance: round towards even */ - if (z1.f[0] & (1 << 3)) - res = make_t_ieee(f, &z2, b); - else - res = make_t_ieee(f, &z1, b); - break; - - case ROUND_CHOP: - res = make_t_ieee(f, &z1, b); - break; - - case ROUND_PINF: - if (a->s) { - res = make_t_ieee(f, &z1, b); - } else { - res = make_t_ieee(f, &z2, b); - } - break; - - case ROUND_NINF: - if (a->s) { - res = make_t_ieee(f, &z2, b); - } else { - res = make_t_ieee(f, &z1, b); - } - break; - } - return FPCR_INE | res; -} - - -static fpclass_t -add_kernel_ieee (EXTENDED *op_a, EXTENDED *op_b, EXTENDED *op_c) -{ - unsigned long mask, fa, fb, fc; - int diff; - - diff = op_a->e - op_b->e; - fa = op_a->f[0]; - fb = op_b->f[0]; - if (diff < 0) { - diff = -diff; - op_c->e = op_b->e; - mask = (1UL << diff) - 1; - fa >>= diff; - if (op_a->f[0] & mask) { - fa |= 1; /* set sticky bit */ - } - } else { - op_c->e = op_a->e; - mask = (1UL << diff) - 1; - fb >>= diff; - if (op_b->f[0] & mask) { - fb |= 1; /* set sticky bit */ - } - } - if (op_a->s) - fa = -fa; - if (op_b->s) - fb = -fb; - fc = fa + fb; - op_c->f[1] = 0; - op_c->s = fc >> 63; - if (op_c->s) { - fc = -fc; - } - op_c->f[0] = fc; - normalize(op_c); - return 0; -} - - -/* - * converts s-floating "a" to t-floating "b". - * - * INPUT PARAMETERS: - * a a s-floating number to be converted - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the t-floating number that "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTST (int f, unsigned long a, unsigned long *b) -{ - EXTENDED temp; - fpclass_t a_type; - - a_type = extend_ieee(a, &temp, SINGLE); - if (a_type >= NaN && a_type <= INFTY) { - *b = a; - if (a_type == NaN) { - *b |= (1UL << 51); /* turn SNaN into QNaN */ - return FPCR_INV; - } - return 0; - } - return round_t_ieee(f, &temp, b); -} - - -/* - * converts t-floating "a" to s-floating "b". - * - * INPUT PARAMETERS: - * a a t-floating number to be converted - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the s-floating number that "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTTS (int f, unsigned long a, unsigned long *b) -{ - EXTENDED temp; - fpclass_t a_type; - - a_type = extend_ieee(a, &temp, DOUBLE); - if (a_type >= NaN && a_type <= INFTY) { - *b = a; - if (a_type == NaN) { - *b |= (1UL << 51); /* turn SNaN into QNaN */ - return FPCR_INV; - } - return 0; - } - return round_s_ieee(f, &temp, b); -} - - -/* - * converts q-format (64-bit integer) "a" to s-floating "b". - * - * INPUT PARAMETERS: - * a an 64-bit integer to be converted. - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the s-floating number "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTQS (int f, unsigned long a, unsigned long *b) -{ - EXTENDED op_b; - - op_b.s = 0; - op_b.f[0] = a; - op_b.f[1] = 0; - if (sign(a) < 0) { - op_b.s = 1; - op_b.f[0] = -a; - } - op_b.e = 55; - normalize(&op_b); - return round_s_ieee(f, &op_b, b); -} - - -/* - * converts 64-bit integer "a" to t-floating "b". - * - * INPUT PARAMETERS: - * a a 64-bit integer to be converted. - * f the rounding mode (ROUND_NEAR, etc.) - * OUTPUT PARAMETERS: - * b the t-floating number "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTQT (int f, unsigned long a, unsigned long *b) -{ - EXTENDED op_b; - - op_b.s = 0; - op_b.f[0] = a; - op_b.f[1] = 0; - if (sign(a) < 0) { - op_b.s = 1; - op_b.f[0] = -a; - } - op_b.e = 55; - normalize(&op_b); - return round_t_ieee(f, &op_b, b); -} - - -/* - * converts t-floating "a" to 64-bit integer (q-format) "b". - * - * INPUT PARAMETERS: - * a a t-floating number to be converted. - * f the rounding mode (ROUND_NEAR, etc. ) - * OUTPUT PARAMETERS: - * b the 64-bit integer "a" is converted to. - * RETURN VALUE: - * error flags - i.e., zero if no errors occurred, - * FPCR_INV if invalid operation occurred, etc. - */ -unsigned long -ieee_CVTTQ (int f, unsigned long a, unsigned long *pb) -{ - unsigned int midway; - unsigned long ov, uv, res, b; - fpclass_t a_type; - EXTENDED temp; - - a_type = extend_ieee(a, &temp, DOUBLE); - - b = 0x7fffffffffffffff; - res = FPCR_INV; - if (a_type == NaN || a_type == INFTY) - goto out; - - res = 0; - if (a_type == QNaN) - goto out; - - if (temp.e > 0) { - ov = 0; - while (temp.e > 0) { - --temp.e; - ov |= temp.f[1] >> 63; - sll128(temp.f); - } - if (ov || (temp.f[1] & 0xffc0000000000000)) - res |= FPCR_IOV | FPCR_INE; - } - else if (temp.e < 0) { - while (temp.e < 0) { - ++temp.e; - uv = temp.f[0] & 1; /* save sticky bit */ - srl128(temp.f); - temp.f[0] |= uv; - } - } - b = (temp.f[1] << 9) | (temp.f[0] >> 55); - - /* - * Notice: the fraction is only 52 bits long. Thus, rounding - * cannot possibly result in an integer overflow. - */ - switch (RM(f)) { - case ROUND_NEAR: - if (temp.f[0] & 0x0040000000000000) { - midway = (temp.f[0] & 0x003fffffffffffff) == 0; - if ((midway && (temp.f[0] & 0x0080000000000000)) || - !midway) - ++b; - } - break; - - case ROUND_PINF: - b += ((temp.f[0] & 0x007fffffffffffff) != 0 && !temp.s); - break; - - case ROUND_NINF: - b += ((temp.f[0] & 0x007fffffffffffff) != 0 && temp.s); - break; - - case ROUND_CHOP: - /* no action needed */ - break; - } - if ((temp.f[0] & 0x007fffffffffffff) != 0) - res |= FPCR_INE; - - if (temp.s) { - b = -b; - } - -out: - *pb = b; - return res; -} - - -unsigned long -ieee_CMPTEQ (unsigned long a, unsigned long b, unsigned long *c) -{ - EXTENDED op_a, op_b; - fpclass_t a_type, b_type; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((op_a.e == op_b.e && op_a.s == op_b.s && - op_a.f[0] == op_b.f[0] && op_a.f[1] == op_b.f[1]) || - (a_type == ZERO && b_type == ZERO)) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTLT (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((op_a.s == 1 && op_b.s == 0 && - (a_type != ZERO || b_type != ZERO)) || - (op_a.s == 1 && op_b.s == 1 && - (op_a.e > op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f, op_b.f) > 0))) || - (op_a.s == 0 && op_b.s == 0 && - (op_a.e < op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) < 0)))) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTLE (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == ZERO && b_type == ZERO) || - (op_a.s == 1 && op_b.s == 0) || - (op_a.s == 1 && op_b.s == 1 && - (op_a.e > op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) >= 0))) || - (op_a.s == 0 && op_b.s == 0 && - (op_a.e < op_b.e || (op_a.e == op_b.e && - cmp128(op_a.f,op_b.f) <= 0)))) - *c = 0x4000000000000000; - return 0; -} - - -unsigned long -ieee_CMPTUN (unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b; - - *c = 0x4000000000000000; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - *c = 0; - return 0; -} - - -/* - * Add a + b = c, where a, b, and c are ieee s-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_ADDS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b; - return 0; - } - - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 + -0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - return round_s_ieee(f, &op_c, c); -} - - -/* - * Add a + b = c, where a, b, and c are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_ADDT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b; - return 0; - } - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 + -0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Subtract a - b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_SUBS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b ^ (1UL << 63); - return 0; - } - op_b.s = !op_b.s; - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 - +0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_s_ieee(f, &op_c, c); -} - - -/* - * Subtract a - b = c, where a, b, and c are ieee t-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_SUBT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) { - *c = IEEE_QNaN; - return FPCR_INV; - } - if (a_type == INFTY) - *c = a; - else - *c = b ^ (1UL << 63); - return 0; - } - op_b.s = !op_b.s; - add_kernel_ieee(&op_a, &op_b, &op_c); - /* special case for -0 - +0 ==> -0 */ - if (a_type == ZERO && b_type == ZERO) - op_c.s = op_a.s && op_b.s; - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Multiply a x b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode. - */ -unsigned long -ieee_MULS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= INFTY) || - (b_type >= NaN && b_type <= INFTY)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == INFTY && b_type == ZERO) || - (b_type == INFTY && a_type == ZERO)) - { - *c = IEEE_QNaN; /* return canonical QNaN */ - return FPCR_INV; - } - if (a_type == INFTY) - *c = a ^ ((b >> 63) << 63); - else if (b_type == INFTY) - *c = b ^ ((a >> 63) << 63); - else - /* either of a and b are +/-0 */ - *c = ((unsigned long) op_a.s ^ op_b.s) << 63; - return 0; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e - 55; - mul64(op_a.f[0], op_b.f[0], op_c.f); - - return round_s_ieee(f, &op_c, c); -} - - -/* - * Multiply a x b = c, where a, b, and c are ieee t-floating numbers. - * "f" contains the rounding mode. - */ -unsigned long -ieee_MULT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - *c = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - if ((a_type == INFTY && b_type == ZERO) || - (b_type == INFTY && a_type == ZERO)) - { - *c = IEEE_QNaN; /* return canonical QNaN */ - return FPCR_INV; - } - if (a_type == INFTY) - *c = a ^ ((b >> 63) << 63); - else if (b_type == INFTY) - *c = b ^ ((a >> 63) << 63); - else - /* either of a and b are +/-0 */ - *c = ((unsigned long) op_a.s ^ op_b.s) << 63; - return 0; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e - 55; - mul64(op_a.f[0], op_b.f[0], op_c.f); - - return round_t_ieee(f, &op_c, c); -} - - -/* - * Divide a / b = c, where a, b, and c are ieee s-floating numbers. - * "f" contains the rounding mode etc. - */ -unsigned long -ieee_DIVS (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - a_type = extend_ieee(a, &op_a, SINGLE); - b_type = extend_ieee(b, &op_b, SINGLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - unsigned long res; - - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - res = 0; - *c = IEEE_PINF; - if (a_type == INFTY) { - if (b_type == INFTY) { - *c = IEEE_QNaN; - return FPCR_INV; - } - } else if (b_type == ZERO) { - if (a_type == ZERO) { - *c = IEEE_QNaN; - return FPCR_INV; - } - res = FPCR_DZE; - } else - /* a_type == ZERO || b_type == INFTY */ - *c = 0; - *c |= (unsigned long) (op_a.s ^ op_b.s) << 63; - return res; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e - op_b.e; - - op_a.f[1] = op_a.f[0]; - op_a.f[0] = 0; - div128(op_a.f, op_b.f, op_c.f); - if (a_type != ZERO) - /* force a sticky bit because DIVs never hit exact .5: */ - op_c.f[0] |= STICKY_S; - normalize(&op_c); - op_c.e -= 9; /* remove excess exp from original shift */ - return round_s_ieee(f, &op_c, c); -} - - -/* - * Divide a/b = c, where a, b, and c are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c) -{ - fpclass_t a_type, b_type; - EXTENDED op_a, op_b, op_c; - - *c = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - b_type = extend_ieee(b, &op_b, DOUBLE); - if ((a_type >= NaN && a_type <= ZERO) || - (b_type >= NaN && b_type <= ZERO)) - { - unsigned long res; - - /* propagate NaNs according to arch. ref. handbook: */ - if (b_type == QNaN) - *c = b; - else if (b_type == NaN) - *c = b | (1UL << 51); - else if (a_type == QNaN) - *c = a; - else if (a_type == NaN) - *c = a | (1UL << 51); - - if (a_type == NaN || b_type == NaN) - return FPCR_INV; - if (a_type == QNaN || b_type == QNaN) - return 0; - - res = 0; - *c = IEEE_PINF; - if (a_type == INFTY) { - if (b_type == INFTY) { - *c = IEEE_QNaN; - return FPCR_INV; - } - } else if (b_type == ZERO) { - if (a_type == ZERO) { - *c = IEEE_QNaN; - return FPCR_INV; - } - res = FPCR_DZE; - } else - /* a_type == ZERO || b_type == INFTY */ - *c = 0; - *c |= (unsigned long) (op_a.s ^ op_b.s) << 63; - return res; - } - op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e - op_b.e; - - op_a.f[1] = op_a.f[0]; - op_a.f[0] = 0; - div128(op_a.f, op_b.f, op_c.f); - if (a_type != ZERO) - /* force a sticky bit because DIVs never hit exact .5 */ - op_c.f[0] |= STICKY_T; - normalize(&op_c); - op_c.e -= 9; /* remove excess exp from original shift */ - return round_t_ieee(f, &op_c, c); -} - -/* - * Sqrt a = b, where a and b are ieee s-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_SQRTS (int f, unsigned long a, unsigned long *b) -{ - fpclass_t a_type; - EXTENDED op_a, op_b; - - *b = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, SINGLE); - if (op_a.s == 0) { - /* FIXME -- handle positive denormals. */ - send_sig(SIGFPE, current, 1); - } - return FPCR_INV; -} - -/* - * Sqrt a = b, where a and b are ieee t-floating numbers. "f" - * contains the rounding mode etc. - */ -unsigned long -ieee_SQRTT (int f, unsigned long a, unsigned long *b) -{ - fpclass_t a_type; - EXTENDED op_a, op_b; - - *b = IEEE_QNaN; - a_type = extend_ieee(a, &op_a, DOUBLE); - if (op_a.s == 0) { - /* FIXME -- handle positive denormals. */ - send_sig(SIGFPE, current, 1); - } - return FPCR_INV; -} diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/ieee-math.h linux/arch/alpha/math-emu/ieee-math.h --- v2.2.10/linux/arch/alpha/math-emu/ieee-math.h Mon May 10 09:55:21 1999 +++ linux/arch/alpha/math-emu/ieee-math.h Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ -/* - * Copyright (C) 1992,1995 by - * Digital Equipment Corporation, Maynard, Massachusetts. - * This file may be redistributed according to the terms of the - * GNU General Public License. - */ -#ifndef __ieee_math_h__ -#define __ieee_math_h__ - -#include - -#define ROUND_SHIFT 6 /* make space for trap-enable bits */ -#define RM(f) (((f) >> ROUND_SHIFT) & 0x3) - -#define ROUND_CHOP (FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT) -#define ROUND_NINF (FPCR_DYN_MINUS >> FPCR_DYN_SHIFT) -#define ROUND_NEAR (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT) -#define ROUND_PINF (FPCR_DYN_PLUS >> FPCR_DYN_SHIFT) - -extern unsigned long ieee_CVTST (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTTS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTQS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTQT (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_CVTTQ (int rm, unsigned long a, unsigned long *b); - -extern unsigned long ieee_CMPTEQ (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTLT (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTLE (unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_CMPTUN (unsigned long a, unsigned long b, - unsigned long *c); - -extern unsigned long ieee_ADDS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_ADDT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SUBS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SUBT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_MULS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_MULT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_DIVS (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b, - unsigned long *c); -extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b); -extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b); - -#endif /* __ieee_math_h__ */ diff -u --recursive --new-file v2.2.10/linux/arch/alpha/math-emu/sfp-machine.h linux/arch/alpha/math-emu/sfp-machine.h --- v2.2.10/linux/arch/alpha/math-emu/sfp-machine.h Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/sfp-machine.h Mon Aug 9 12:04:57 1999 @@ -0,0 +1,625 @@ +/* Machine-dependent software floating-point definitions. Sparc64 version. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include + +#define _FP_W_TYPE_SIZE 64 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y) +#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) +#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y) + +#define _FP_NANFRAC_S _FP_QNANBIT_S +#define _FP_NANFRAC_D _FP_QNANBIT_D +#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0 + +/* On some architectures float-to-int conversions return a result + * code. On others (e.g. Sparc) they return 0 + */ +#define _FTOI_RESULT A_r + +#define _FP_KEEPNANFRACP 1 + +/* Alpha Architecture Manual Section 4.7.10.4: Propagating NaN Values, + * summary: + * + * The first of the following rules that is applicable governs the + * value returned: + * 1: If X is a quiet NaN, copy X to the result. + * 2: If X is a signaling NaN, the result is the canonical quiet NaN + * with the same sign as X + * 3: If Y is a quiet NaN, copy Y to the result. + * 4: If Y is a signaling NaN, the result is the canonical quiet NaN + * with the same sign as Y + * 5: The result is the canonical quiet NaN with a sign bit of 1 + * + * In addition, in cases (2) and (4) above we set EFLAG_INVALID. + */ + +#define _FP_IS_NAN(fs, Z) (Z##_c == FP_CLS_NAN) +#define _FP_IS_QNAN(fs, Z) (Z##_f & _FP_QNANBIT_##fs) + +#define _FP_CHOOSENAN(fs, wc, R, X, Y) \ + do { \ + R##_r |= (X##_r | Y##_r); \ + if(_FP_IS_NAN(fs, Y)) { \ + R##_s = Y##_s; \ + R##_c = FP_CLS_NAN; \ + if(_FP_IS_QNAN(fs, Y)) { /* Rule 1 */ \ + _FP_FRAC_COPY_##wc(R,Y); \ + } \ + else { /* Rule 2 */ \ + _FP_FRAC_SET_##wc(R,Y##_f | _FP_QNANBIT_##fs); \ + R##_r = EFLAG_INVALID; \ + } \ + } \ + else if(_FP_IS_NAN(fs, X)) { \ + R##_s = X##_s; \ + R##_c = FP_CLS_NAN; \ + if(_FP_IS_QNAN(fs, X)) { /* Rule 3 */ \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + else { /* Rule 4 */ \ + _FP_FRAC_SET_##wc(R,X##_f | _FP_QNANBIT_##fs); \ + R##_r |= EFLAG_INVALID; \ + } \ + } \ + else { /* Rule 5 */ \ + R##_s = 1; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R,_FP_QNANBIT_##fs | EFLAG_MASK); \ + } \ + } while(0) + +/* Rules 3 and 4 don't apply to functions of only one argument */ +#define _FP_CHOOSENAN_1(fs, wc, R, X) \ + do { \ + if(_FP_IS_NAN(fs, X)) { \ + R##_s = X##_s; \ + R##_c = FP_CLS_NAN; \ + if(_FP_IS_QNAN(fs, X)) { /* Rule 1 */ \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + else { /* Rule 2 */ \ + _FP_FRAC_SET_##wc(R,X##_f | _FP_QNANBIT_##fs); \ + R##_r |= EFLAG_INVALID; \ + } \ + } \ + else { /* Rule 5 */ \ + R##_s = 1; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R,_FP_QNANBIT_##fs | EFLAG_MASK); \ + } \ + } while(0) + +#define _FP_CHOOSENAN_SQRT _FP_CHOOSENAN_1 + + +#define __FP_UNPACK_DENORM(fs, wc, X) \ + { \ + _FP_I_TYPE _shift; \ + X##_r |= EFLAG_DENORM; \ + if(_FP_DENORM_TO_ZERO) { \ + /* Crunching a nonzero denorm to zero necessarily makes */ \ + /* the result inexact */ \ + X##_r |= EFLAG_INEXACT; \ + _FP_FRAC_SET_##wc(X, 0); \ + X##_c = FP_CLS_ZERO; \ + } \ + else { \ + _FP_FRAC_CLZ_##wc(_shift, X); \ + _shift -= _FP_FRACXBITS_##fs; \ + _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ + X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ + X##_c = FP_CLS_NORMAL; \ + } \ + } + +#define __FP_UNPACK_RAW_1(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f = _flo->bits.frac; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_UNPACK_RAW_2(fs, X, val) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + X##_f0 = _flo->bits.frac0; \ + X##_f1 = _flo->bits.frac1; \ + X##_e = _flo->bits.exp; \ + X##_s = _flo->bits.sign; \ + } while (0) + +#define __FP_UNPACK_S(X,val) \ + do { \ + __FP_UNPACK_RAW_1(S,X,val); \ + _FP_UNPACK_CANONICAL(S,1,X); \ + } while (0) + +#define __FP_UNPACK_D(X,val) \ + do { \ + __FP_UNPACK_RAW_1(D,X,val); \ + _FP_UNPACK_CANONICAL(D,1,X); \ + } while (0) + +#define __FP_UNPACK_Q(X,val) \ + do { \ + __FP_UNPACK_RAW_2(Q,X,val); \ + _FP_UNPACK_CANONICAL(Q,2,X); \ + } while (0) + +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + + +/* Alpha rules for handling certain exceptional cases are different + * enough that we simply define our own versions here to override + * the ones in op-common.h + */ + +#define _FP_ADD(fs, wc, R, X, Y) \ +do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + { \ + /* shift the smaller number so that its exponent matches the larger */ \ + _FP_I_TYPE diff = X##_e - Y##_e; \ + \ + if (diff < 0) \ + { \ + diff = -diff; \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(X)) { \ + _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ + R_r |= EFLAG_INEXACT; \ + } \ + else \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + R##_e = Y##_e; \ + } \ + else \ + { \ + if (diff > 0) \ + { \ + if (diff <= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ + else if (!_FP_FRAC_ZEROP_##wc(Y)) { \ + _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ + R_r |= EFLAG_INEXACT; \ + } \ + else \ + _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \ + } \ + R##_e = X##_e; \ + } \ + \ + R##_c = FP_CLS_NORMAL; \ + \ + if (X##_s == Y##_s) \ + { \ + R##_s = X##_s; \ + _FP_FRAC_ADD_##wc(R, X, Y); \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + { \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + R##_e++; \ + } \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_SUB_##wc(R, X, Y); \ + if (_FP_FRAC_ZEROP_##wc(R)) \ + { \ + /* return an exact zero */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s |= Y##_s; \ + else \ + R##_s &= Y##_s; \ + R##_c = FP_CLS_ZERO; \ + } \ + else \ + { \ + if (_FP_FRAC_NEGP_##wc(R)) \ + { \ + _FP_FRAC_SUB_##wc(R, Y, X); \ + R##_s = Y##_s; \ + } \ + \ + /* renormalize after subtraction */ \ + _FP_FRAC_CLZ_##wc(diff, R); \ + diff -= _FP_WFRACXBITS_##fs; \ + if (diff) \ + { \ + R##_e -= diff; \ + _FP_FRAC_SLL_##wc(R, diff); \ + } \ + } \ + } \ + break; \ + } \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + R##_e = X##_e; \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_s = X##_s; \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_e = Y##_e; \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_s = Y##_s; \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + if (X##_s != Y##_s) \ + { \ + /* +INF + -INF => NAN */ \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + R##_s = X##_s ^ Y##_s; \ + R##_c = FP_CLS_NAN; \ + R##_r |= EFLAG_INVALID; \ + break; \ + } \ + /* FALLTHRU */ \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + R##_s = X##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_s = Y##_s; \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + /* make sure the sign is correct */ \ + if (FP_ROUNDMODE == FP_RND_MINF) \ + R##_s = X##_s | Y##_s; \ + else \ + R##_s = X##_s & Y##_s; \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +#define _FP_MUL(fs, wc, R, X, Y) \ +do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e + Y##_e + 1; \ + \ + _FP_MUL_MEAT_##fs(R,X,Y); \ + \ + if (_FP_FRAC_OVERP_##wc(fs, R)) \ + _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ + else \ + R##_e--; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, X); \ + R##_c = X##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + _FP_FRAC_COPY_##wc(R, Y); \ + R##_c = Y##_c; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + R##_s = 1; /* Alpha SRM rule */ \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +#define _FP_DIV(fs, wc, R, X, Y) \ +do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ + R##_s = X##_s ^ Y##_s; \ + switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ + { \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ + R##_c = FP_CLS_NORMAL; \ + R##_e = X##_e - Y##_e; \ + \ + _FP_DIV_MEAT_##fs(R,X,Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ + _FP_CHOOSENAN(fs, wc, R, X, Y); \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ + R##_c = FP_CLS_ZERO; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ + R##_c = FP_CLS_INF; \ + break; \ + \ + case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ + case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ + R##_s = 1; /* Alpha SRM rule */ \ + break; \ + \ + default: \ + abort(); \ + } \ +} while (0) + + +#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ + ({ \ + switch (X##_c) \ + { \ + case FP_CLS_ZERO: \ + r = 0; \ + break; \ + case FP_CLS_NAN: \ + r = 0; \ + X##_r |= EFLAG_INVALID; \ + break; \ + case FP_CLS_INF: \ + r = 0; \ + X##_r |= (EFLAG_INVALID | EFLAG_INEXACT); \ + break; \ + case FP_CLS_NORMAL: \ + if (X##_e < 0) \ + { \ + r = 0; \ + X##_r |= EFLAG_INEXACT; \ + } \ + else \ + { \ + if (X##_e >= rsize - (rsigned != 0)) { \ + /* Overflow. On alpha, set the INV bit and proceed */ \ + /* JRP - I *believe* the proper behavior is to set */ \ + /* INV and write a true zero... need to check */ \ + X##_r |= EFLAG_INVALID; \ + r = 0; \ + break; \ + } \ + if (_FP_W_TYPE_SIZE*wc < rsize) \ + { \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + r <<= X##_e - _FP_WFRACBITS_##fs; \ + } \ + else \ + { \ + if (X##_e >= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ + else \ + _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + } \ + if (rsigned && X##_s) \ + r = -r; \ + } \ + break; \ + } \ + X##_r; \ + }) + + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#define __FPU_TEM ((current->tss.flags)& IEEE_TRAP_ENABLE_MASK) + +#define __FPU_TRAP_P(bits) \ + ((__FPU_TEM & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(D,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(D,val,X); \ + __exc; \ +}) + +#define __FP_PACK_Q(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(Q,2,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_2(Q,val,X); \ + __exc; \ +}) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE \ + (((current->tss.flags)&IEEE_CURRENT_RM_MASK)>>IEEE_CURRENT_RM_SHIFT) + +#define FP_RND_NEAREST (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT) +#define FP_RND_ZERO (FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT) +#define FP_RND_PINF (FPCR_DYN_PLUS >> FPCR_DYN_SHIFT) +#define FP_RND_MINF (FPCR_DYN_MINUS >> FPCR_DYN_SHIFT) + + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addq %4,%5,%1; cmpult %1,%4,$28; addq %2,%3,%0; addq %0,$28,%0" \ + : "=r" ((UDItype)(sh)), \ + "=r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl))) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subq %4,%5,%1; cmpult %4,%5,$28; subq %2,%3,%0; subq %0,$28,%0"\ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "r" ((UDItype)(ah)), \ + "r" ((UDItype)(bh)), \ + "r" ((UDItype)(al)), \ + "r" ((UDItype)(bl))) + +#define umul_ppmm(wh, wl, u, v) \ + do { \ + __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v))); \ + } while (0) + + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + unsigned long __n[2]; \ + unsigned long __d[2]; \ + unsigned long __q[2]; \ + unsigned long __r[2]; \ + __n[0]=n1; __n[1]=n0; __d[0]=0; __d[1]=d; \ + udiv128(__n, __d, __q, __r); \ + q=__q[1]; r=__r[1]; \ + } while (0) + +#define UDIV_NEEDS_NORMALIZATION 1 + +#define abort() \ + return 0 + +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN -1 +#endif +#define __BYTE_ORDER __LITTLE_ENDIAN + +/* Exception flags. */ +#define EFLAG_INVALID IEEE_TRAP_ENABLE_INV +#define EFLAG_OVERFLOW IEEE_TRAP_ENABLE_OVF +#define EFLAG_UNDERFLOW IEEE_TRAP_ENABLE_UNF +#define EFLAG_DIVZERO IEEE_TRAP_ENABLE_DZE +#define EFLAG_INEXACT IEEE_TRAP_ENABLE_INE +#define EFLAG_DENORM IEEE_TRAP_ENABLE_DNO +#define EFLAG_MASK IEEE_TRAP_ENABLE_MASK + +#ifdef FP_TEST_XXX +#define _FP_DENORM_TO_ZERO \ + (tss_flags&IEEE_MAP_DMZ) +#else +#define _FP_DENORM_TO_ZERO \ + ((current->tss.flags)&IEEE_MAP_DMZ) +#endif + +/* Comparison operations */ +#define CMPTXX_EQ 0 +#define CMPTXX_LT -1 +#define CMPTXX_GT 1 +#define CMPTXX_LE 2 +#define CMPTXX_UN 3 diff -u --recursive --new-file v2.2.10/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.2.10/linux/arch/alpha/mm/fault.c Wed Sep 9 08:56:58 1998 +++ linux/arch/alpha/mm/fault.c Mon Aug 9 12:04:38 1999 @@ -7,6 +7,7 @@ #include #include #include +#include #define __EXTERN_INLINE inline #include @@ -28,64 +29,20 @@ extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *); -#ifdef __SMP__ -unsigned long last_asn[NR_CPUS] = { /* gag */ - ASN_FIRST_VERSION + (0 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (1 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (2 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (3 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (4 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (5 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (6 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (7 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (8 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (9 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (10 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (11 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (12 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (13 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (14 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (15 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (16 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (17 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (18 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (19 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (20 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (21 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (22 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (23 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (24 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (25 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (26 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (27 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (28 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (29 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (30 << WIDTH_HARDWARE_ASN), - ASN_FIRST_VERSION + (31 << WIDTH_HARDWARE_ASN) -}; -#else -unsigned long asn_cache = ASN_FIRST_VERSION; -#endif /* __SMP__ */ - /* - * Select a new ASN for a task. + * Force a new ASN for a task. */ +#ifndef __SMP__ +unsigned long last_asn = ASN_FIRST_VERSION; +#endif + void get_new_mmu_context(struct task_struct *p, struct mm_struct *mm) { - unsigned long asn = asn_cache; - - if ((asn & HARDWARE_ASN_MASK) < MAX_ASN) - ++asn; - else { - tbiap(); - imb(); - asn = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION; - } - asn_cache = asn; - mm->context = asn; /* full version + asn */ - p->tss.asn = asn & HARDWARE_ASN_MASK; /* just asn */ + unsigned long new = __get_new_mmu_context(); + mm->context = new; + p->tss.asn = new & HARDWARE_ASN_MASK; } /* diff -u --recursive --new-file v2.2.10/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.2.10/linux/arch/alpha/mm/init.c Sat May 22 13:42:53 1999 +++ linux/arch/alpha/mm/init.c Mon Aug 9 12:04:38 1999 @@ -174,7 +174,7 @@ extern unsigned long free_area_init(unsigned long, unsigned long); -static struct thread_struct * +static inline struct thread_struct * load_PCB(struct thread_struct * pcb) { register unsigned long sp __asm__("$30"); @@ -219,7 +219,7 @@ /* Initialize the kernel's page tables. Linux puts the vptb in the last slot of the L1 page table. */ - memset((void *) ZERO_PAGE, 0, PAGE_SIZE); + memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = diff -u --recursive --new-file v2.2.10/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.2.10/linux/arch/arm/kernel/process.c Sun Sep 6 10:44:47 1998 +++ linux/arch/arm/kernel/process.c Mon Aug 9 12:04:38 1999 @@ -27,9 +27,7 @@ #include #include #include -#include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.2.10/linux/arch/arm/kernel/time.c Thu Mar 11 23:24:55 1999 +++ linux/arch/arm/kernel/time.c Mon Aug 9 12:04:38 1999 @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.2.10/linux/arch/i386/Makefile Wed Dec 30 14:17:25 1998 +++ linux/arch/i386/Makefile Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.2.10/linux/arch/i386/boot/setup.S Mon Jun 7 16:13:07 1999 +++ linux/arch/i386/boot/setup.S Mon Aug 9 12:04:38 1999 @@ -757,11 +757,11 @@ ! with no keyboard attached... empty_8042: - push cx - mov cx,#0xFFFF + push ecx + mov ecx,#0xFFFFFF empty_8042_loop: - dec cx + dec ecx jz empty_8042_end_loop call delay @@ -775,7 +775,7 @@ test al,#2 ! is input buffer full? jnz empty_8042_loop ! yes - loop empty_8042_end_loop: - pop cx + pop ecx ret ! diff -u --recursive --new-file v2.2.10/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.2.10/linux/arch/i386/config.in Mon Apr 26 13:49:17 1999 +++ linux/arch/i386/config.in Mon Aug 9 12:04:38 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 diff -u --recursive --new-file v2.2.10/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.2.10/linux/arch/i386/defconfig Mon Apr 12 13:12:57 1999 +++ linux/arch/i386/defconfig Mon Aug 9 12:04:38 1999 @@ -21,6 +21,8 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y +CONFIG_1GB=y +# CONFIG_2GB is not set # CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y diff -u --recursive --new-file v2.2.10/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.2.10/linux/arch/i386/kernel/i386_ksyms.c Mon May 10 10:32:45 1999 +++ linux/arch/i386/kernel/i386_ksyms.c Mon Aug 9 12:05:05 1999 @@ -42,6 +42,8 @@ EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(init_mm); + EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); @@ -110,6 +112,7 @@ EXPORT_SYMBOL(mca_mark_as_used); EXPORT_SYMBOL(mca_mark_as_unused); EXPORT_SYMBOL(mca_find_unused_adapter); +EXPORT_SYMBOL(mca_is_adapter_used); #endif #ifdef CONFIG_VT diff -u --recursive --new-file v2.2.10/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.2.10/linux/arch/i386/kernel/irq.c Mon May 10 10:32:45 1999 +++ linux/arch/i386/kernel/irq.c Mon Aug 9 12:04:38 1999 @@ -139,7 +139,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; /* @@ -927,6 +927,17 @@ return; spin_lock_irqsave(&irq_controller_lock,flags); + +#ifdef __SMP__ + /* Make sure no interrupt handler is in progress when we + manipulate the action list and free the structure */ + while (irq_desc[irq].status & IRQ_INPROGRESS) { + spin_unlock_irqrestore(&irq_controller_lock,flags); + udelay(1000); + spin_lock_irqsave(&irq_controller_lock,flags); + } +#endif + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { if (action->dev_id != dev_id) continue; diff -u --recursive --new-file v2.2.10/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.2.10/linux/arch/i386/kernel/irq.h Tue May 11 10:37:06 1999 +++ linux/arch/i386/kernel/irq.h Mon Aug 9 12:04:38 1999 @@ -40,6 +40,7 @@ struct hw_interrupt_type *handler; /* handle/enable/disable functions */ struct irqaction *action; /* IRQ action list */ unsigned int depth; /* Disable depth for nested irq disables */ + unsigned int unused[4]; } irq_desc_t; /* @@ -214,8 +215,8 @@ "\n" __ALIGN_STR"\n" \ "common_interrupt:\n\t" \ SAVE_ALL \ - "pushl $ret_from_intr\n\t" \ - "jmp "SYMBOL_NAME_STR(do_IRQ)); + "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ + "jmp ret_from_intr\n"); /* * subtle. orig_eax is used by the signal code to distinct between diff -u --recursive --new-file v2.2.10/linux/arch/i386/math-emu/fpu_emu.h linux/arch/i386/math-emu/fpu_emu.h --- v2.2.10/linux/arch/i386/math-emu/fpu_emu.h Sun Sep 13 12:58:05 1998 +++ linux/arch/i386/math-emu/fpu_emu.h Mon Aug 9 12:04:38 1999 @@ -165,8 +165,6 @@ #define signpositive(a) ( (signbyte(a) & 0x80) == 0 ) #define signnegative(a) (signbyte(a) & 0x80) -#include "fpu_proto.h" - static inline void reg_copy(FPU_REG const *x, FPU_REG *y) { *(short *)&(y->exp) = *(const short *)&(x->exp); diff -u --recursive --new-file v2.2.10/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.2.10/linux/arch/i386/mm/init.c Thu Jan 21 11:28:40 1999 +++ linux/arch/i386/mm/init.c Mon Aug 9 12:04:38 1999 @@ -168,6 +168,8 @@ printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); + printk("%ld pages in file cache\n",page_cache_size-cached); + printk("%ld pages in page cache\n",page_cache_size); printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); #ifdef CONFIG_NET diff -u --recursive --new-file v2.2.10/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.2.10/linux/arch/i386/mm/ioremap.c Fri Nov 27 15:03:14 1998 +++ linux/arch/i386/mm/ioremap.c Mon Aug 9 12:04:38 1999 @@ -93,12 +93,17 @@ { void * addr; struct vm_struct * area; - unsigned long offset; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; /* * Don't remap the low PCI/ISA area, it's always mapped.. */ - if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000) + if (phys_addr >= 0xA0000 && last_addr < 0x100000) return phys_to_virt(phys_addr); /* @@ -112,13 +117,7 @@ */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(size + offset); - - /* - * Don't allow mappings that wrap.. - */ - if (!size || size > phys_addr + size) - return NULL; + size = PAGE_ALIGN(last_addr) - phys_addr; /* * Ok, go for it.. diff -u --recursive --new-file v2.2.10/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds --- v2.2.10/linux/arch/i386/vmlinux.lds Sun Dec 27 22:45:13 1998 +++ linux/arch/i386/vmlinux.lds Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S --- v2.2.10/linux/arch/i386/vmlinux.lds.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/vmlinux.lds.S Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/mips/Makefile linux/arch/mips/Makefile --- v2.2.10/linux/arch/mips/Makefile Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/Makefile Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.13 1998/08/17 10:16:23 ralf Exp $ +# $Id: Makefile,v 1.17 1999/05/02 20:56:18 harald Exp $ # # 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 @@ -36,7 +36,7 @@ CROSS_COMPILE = $(tool-prefix) endif -LINKFLAGS = -static #-N +LINKFLAGS = -static -N MODFLAGS += -mlong-calls # @@ -97,22 +97,37 @@ SUBDIRS += arch/mips/algor #LOADADDR += 0x80000000 endif + +# +# DECstation family +# +ifdef CONFIG_DECSTATION +CORE_FILES += arch/mips/dec/dec.o +SUBDIRS += arch/mips/dec arch/mips/dec/prom +LIBS += arch/mips/dec/prom/rexlib.a +LOADADDR += 0x80040000 +endif + # # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. # ifdef CONFIG_MIPS_JAZZ CORE_FILES += arch/mips/jazz/jazz.o -SUBDIRS += arch/mips/jazz -LOADADDR += 0x80000000 +SUBDIRS += arch/mips/jazz arch/mips/arc +LIBS += arch/mips/arc/arclib.a +LOADADDR += 0x80080000 endif + ifdef CONFIG_SNI_RM200_PCI CORE_FILES += arch/mips/sni/sni.o -SUBDIRS += arch/mips/sni -LOADADDR += 0x80000000 +SUBDIRS += arch/mips/sni arch/mips/arc +LIBS += arch/mips/arc/arclib.a +LOADADDR += 0x80080000 endif + ifdef CONFIG_SGI -LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/sgi/prom/promlib.a -SUBDIRS += arch/mips/sgi/kernel arch/mips/sgi/prom +LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a +SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, # 0x88002000 for production kernels. Note that the value must be @@ -123,6 +138,14 @@ endif # +# Baget/MIPS +# +ifdef CONFIG_BAGET_MIPS +SUBDIRS += arch/mips/baget arch/mips/baget/prom +LIBS += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a +endif + +# # Choosing incompatible machines durings configuration will result in # error messages during linking. Select a default linkscript if # none has been choosen above. @@ -150,7 +173,16 @@ SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools) CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES) -LIBS := arch/mips/lib/lib.a $(LIBS) arch/mips/lib/lib.a +LIBS := arch/mips/lib/lib.a $(LIBS) + +ifdef CONFIG_BAGET_MIPS + +BAGETBOOT = $(MAKE) -C arch/$(ARCH)/baget + +balo: vmlinux + $(BAGETBOOT) balo + +endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -u --recursive --new-file v2.2.10/linux/arch/mips/algor/README linux/arch/mips/algor/README --- v2.2.10/linux/arch/mips/algor/README Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/algor/README Mon Aug 9 12:04:38 1999 @@ -0,0 +1,5 @@ +The code for the Algorithmics P4032 evaluation board is currently under +development. I'll release it when it's up to the same strength as +the other ports. + + Ralf diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/Makefile linux/arch/mips/arc/Makefile --- v2.2.10/linux/arch/mips/arc/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,23 @@ +# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ +# Makefile for the SGI arcs prom monitor library routines +# under Linux. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +OBJS = console.o init.o printf.o memory.o tree.o env.o \ + cmdline.o misc.o time.o file.o identify.o + +all: arclib.a + +arclib.a: $(OBJS) + $(AR) rcs arclib.a $(OBJS) + sync + +dep: + $(CPP) -M *.c > .depend + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c --- v2.2.10/linux/arch/mips/arc/cmdline.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/cmdline.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,64 @@ +/* + * cmdline.c: Kernel command line creation using ARCS argc/argv. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + */ +#include +#include +#include + +#include +#include + +/* #define DEBUG_CMDLINE */ + +char arcs_cmdline[CL_SIZE]; + +__initfunc(char *prom_getcmdline(void)) +{ + return &(arcs_cmdline[0]); +} + +static char *ignored[] = { + "ConsoleIn=", + "ConsoleOut=", + "SystemPartition=", + "OSLoader=", + "OSLoadPartition=", + "OSLoadFilename=" +}; +#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) + +__initfunc(void prom_init_cmdline(void)) +{ + char *cp; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + for(i = 0; i < NENTS(ignored); i++) { + int len = strlen(ignored[i]); + + if(!strncmp(prom_argv[actr], ignored[i], len)) + goto pic_cont; + } + /* Ok, we want it. */ + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + + pic_cont: + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; + +#ifdef DEBUG_CMDLINE + prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0])); +#endif +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c --- v2.2.10/linux/arch/mips/arc/console.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/console.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,50 @@ +/* + * console.c: SGI arcs console code. + * + * Copyright (C) 1996 David S. Miller (dm@sgi.com) + * Compability with board caches, Ulf Carlsson + * + * $Id: console.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + */ +#include +#include +#include +#include + +/* The romvec is not compatible with board caches. Thus we disable it during + * romvec action. Since r4xx0.c is always compiled and linked with your kernel, + * this shouldn't cause any harm regardless what MIPS processor you have. + * + * The romvec write and read functions seem to interfere with the serial lines + * in some way. You should be careful with them. + */ +extern struct bcache_ops *bcops; + +#ifdef CONFIG_SGI_PROM_CONSOLE +void prom_putchar(char c) +#else +__initfunc(void prom_putchar(char c)) +#endif +{ + long cnt; + char it = c; + + bcops->bc_disable(); + romvec->write(1, &it, 1, &cnt); + bcops->bc_enable(); +} + +#ifdef CONFIG_SGI_PROM_CONSOLE +char prom_getchar(void) +#else +__initfunc(char prom_getchar(void)) +#endif +{ + long cnt; + char c; + + bcops->bc_disable(); + romvec->read(0, &c, 1, &cnt); + bcops->bc_enable(); + return c; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/env.c linux/arch/mips/arc/env.c --- v2.2.10/linux/arch/mips/arc/env.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/env.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,22 @@ +/* + * env.c: ARCS environment variable routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: env.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + */ +#include +#include +#include + +#include + +__initfunc(char *prom_getenv(char *name)) +{ + return romvec->get_evar(name); +} + +__initfunc(long prom_setenv(char *name, char *value)) +{ + return romvec->set_evar(name, value); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/file.c linux/arch/mips/arc/file.c --- v2.2.10/linux/arch/mips/arc/file.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/file.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,59 @@ +/* + * file.c: ARCS firmware interface to files. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: file.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + */ +#include +#include + +__initfunc(long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt)) +{ + return romvec->get_vdirent(fd, ent, num, cnt); +} + +__initfunc(long prom_open(char *name, enum linux_omode md, unsigned long *fd)) +{ + return romvec->open(name, md, fd); +} + +__initfunc(long prom_close(unsigned long fd)) +{ + return romvec->close(fd); +} + +__initfunc(long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) +{ + return romvec->read(fd, buf, num, cnt); +} + +__initfunc(long prom_getrstatus(unsigned long fd)) +{ + return romvec->get_rstatus(fd); +} + +__initfunc(long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) +{ + return romvec->write(fd, buf, num, cnt); +} + +__initfunc(long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm)) +{ + return romvec->seek(fd, off, sm); +} + +__initfunc(long prom_mount(char *name, enum linux_mountops op)) +{ + return romvec->mount(name, op); +} + +__initfunc(long prom_getfinfo(unsigned long fd, struct linux_finfo *buf)) +{ + return romvec->get_finfo(fd, buf); +} + +__initfunc(long prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk)) +{ + return romvec->set_finfo(fd, flags, msk); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/identify.c linux/arch/mips/arc/identify.c --- v2.2.10/linux/arch/mips/arc/identify.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/identify.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,68 @@ +/* + * identify.c: identify machine by looking up system identifier + * + * Copyright (C) 1998 Thomas Bogendoerfer + * + * This code is based on arch/mips/sgi/kernel/system.c, which is + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $ + */ +#include +#include +#include +#include + +#include +#include +#include + +struct smatch { + char *name; + int group; + int type; + int flags; +}; + +static struct smatch mach_table[] = { + { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS }, + { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 }, + { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 }, + { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 } +}; + +int prom_flags; + +static struct smatch * __init string_to_mach(char *s) +{ + int i; + + for (i = 0; i < sizeof (mach_table); i++) { + if(!strcmp(s, mach_table[i].name)) + return &mach_table[i]; + } + prom_printf("\nYeee, could not determine architecture type <%s>\n", s); + prom_printf("press a key to reboot\n"); + prom_getchar(); + romvec->imode(); + return NULL; +} + +void __init prom_identify_arch(void) +{ + pcomponent *p; + struct smatch *mach; + + /* The root component tells us what machine architecture we + * have here. + */ + p = prom_getchild(PROM_NULL_COMPONENT); + printk("ARCH: %s\n", p->iname); + mach = string_to_mach(p->iname); + + mips_machgroup = mach->group; + mips_machtype = mach->type; + prom_flags = mach->flags; +} + diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c --- v2.2.10/linux/arch/mips/arc/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/init.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,67 @@ +/* + * init.c: PROM library initialisation code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: init.c,v 1.2 1999/02/25 21:22:49 tsbogend Exp $ + */ +#include +#include +#include + +#include + +/* #define DEBUG_PROM_INIT */ + +/* Master romvec interface. */ +struct linux_romvec *romvec; +struct linux_promblock *sgi_pblock; +int prom_argc; +char **prom_argv, **prom_envp; +unsigned short prom_vers, prom_rev; + +extern void prom_testtree(void); + +__initfunc(int prom_init(int argc, char **argv, char **envp)) +{ + struct linux_promblock *pb; + + romvec = ROMVECTOR; + pb = sgi_pblock = PROMBLOCK; + prom_argc = argc; + prom_argv = argv; + prom_envp = envp; + + if(pb->magic != 0x53435241) { + prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); + while(1) + ; + } + + prom_init_cmdline(); + + prom_vers = pb->ver; + prom_rev = pb->rev; + prom_identify_arch(); +#ifdef CONFIG_SGI + printk("PROMLIB: SGI ARCS firmware Version %d Revision %d\n", + prom_vers, prom_rev); +#else + printk("PROMLIB: ARC firmware Version %d Revision %d\n", + prom_vers, prom_rev); +#endif + prom_meminit(); + +#if 0 + prom_testtree(); +#endif + +#ifdef DEBUG_PROM_INIT + { + prom_printf("Press a key to reboot\n"); + (void) prom_getchar(); + romvec->imode(); + } +#endif + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c --- v2.2.10/linux/arch/mips/arc/memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/memory.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,208 @@ +/* + * memory.c: PROM library functions for acquiring/using memory descriptors + * given to us from the ARCS firmware. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: memory.c,v 1.5 1999/04/14 21:25:02 tsbogend Exp $ + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* #define DEBUG */ + +__initfunc(struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr)) +{ + return romvec->get_mdesc(curr); +} + +#ifdef DEBUG /* convenient for debugging */ +static char *arcs_mtypes[8] = { + "Exception Block", + "ARCS Romvec Page", + "Free/Contig RAM", + "Generic Free RAM", + "Bad Memory", + "Standlong Program Pages", + "ARCS Temp Storage Area", + "ARCS Permanent Storage Area" +}; + +static char *arc_mtypes[8] = { + "Exception Block", + "SystemParameterBlock", + "FreeMemory", + "Bad Memory", + "LoadedProgram", + "FirmwareTemporary", + "FirmwarePermanent", + "FreeContigiuous" +}; +#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] +#endif + +static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS]; + +__initfunc(struct prom_pmemblock *prom_getpblock_array(void)) +{ + return &prom_pblocks[0]; +} + +#define MEMTYPE_DONTUSE 0 +#define MEMTYPE_PROM 1 +#define MEMTYPE_FREE 2 + +static int __init prom_memtype_classify (union linux_memtypes type) +{ + if (prom_flags & PROM_FLAG_ARCS) { + switch (type.arcs) { + case arcs_free: + case arcs_fcontig: + return MEMTYPE_FREE; + case arcs_atmp: + case arcs_aperm: + return MEMTYPE_PROM; + default: + return MEMTYPE_DONTUSE; + } + } else { + switch (type.arc) { + case arc_free: + case arc_fcontig: + return MEMTYPE_FREE; + case arc_rvpage: + case arc_atmp: + case arc_aperm: + return MEMTYPE_PROM; + default: + return MEMTYPE_DONTUSE; + } + } +} + +__initfunc(static void prom_setup_memupper(void)) +{ + struct prom_pmemblock *p, *highest; + + for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) { + if(p->base == 0xdeadbeef) + prom_printf("WHEEE, bogus pmemblock\n"); + if(!highest || p->base > highest->base) + highest = p; + } + mips_memory_upper = highest->base + highest->size; +#ifdef DEBUG + prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n", + mips_memory_upper); +#endif +} + +__initfunc(void prom_meminit(void)) +{ + struct linux_mdesc *p; + int totram; + int i = 0; + + p = prom_getmdesc(PROM_NULL_MDESC); +#ifdef DEBUG + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); + while(p) { + prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", + i, p, p->base, p->pages, mtypes(p->type)); + p = prom_getmdesc(p); + i++; + } +#endif + p = prom_getmdesc(PROM_NULL_MDESC); + totram = 0; + i = 0; + while(p) { + prom_pblocks[i].type = prom_memtype_classify (p->type); + prom_pblocks[i].base = ((p->base<pages << PAGE_SHIFT; + switch (prom_pblocks[i].type) { + case MEMTYPE_FREE: + totram += prom_pblocks[i].size; +#ifdef DEBUG + prom_printf("free_chunk[%d]: base=%08lx size=%d\n", + i, prom_pblocks[i].base, + prom_pblocks[i].size); +#endif + i++; + break; + case MEMTYPE_PROM: +#ifdef DEBUG + prom_printf("prom_chunk[%d]: base=%08lx size=%d\n", + i, prom_pblocks[i].base, + prom_pblocks[i].size); +#endif + i++; + break; + default: + break; + } + p = prom_getmdesc(p); + } + prom_pblocks[i].base = 0xdeadbeef; + prom_pblocks[i].size = 0; /* indicates last elem. of array */ + printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n", + totram, (totram/1024), (totram/1024/1024)); + + /* Setup upper physical memory bound. */ + prom_setup_memupper(); +} + +/* Called from mem_init() to fixup the mem_map page settings. */ +__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end)) +{ + struct prom_pmemblock *p; + int i, nents; + + /* Determine number of pblockarray entries. */ + p = prom_getpblock_array(); + for(i = 0; p[i].size; i++) + ; + nents = i; +restart: + while(start < end) { + for(i = 0; i < nents; i++) { + if((p[i].type == MEMTYPE_FREE) && + (start >= (p[i].base)) && + (start < (p[i].base + p[i].size))) { + start = p[i].base + p[i].size; + start &= PAGE_MASK; + goto restart; + } + } + set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags); + start += PAGE_SIZE; + } +} + +void prom_free_prom_memory (void) +{ + struct prom_pmemblock *p; + unsigned long addr; + unsigned long num_pages = 0; + + for(p = prom_getpblock_array(); p->size != 0; p++) { + if (p->type == MEMTYPE_PROM) { + for (addr = p->base; addr < p->base + p->size; addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + atomic_set(&mem_map[MAP_NR(addr)].count, 1); + free_page(addr); + num_pages++; + } + } + } + printk ("Freeing prom memory: %dk freed\n",num_pages << (PAGE_SHIFT - 10)); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c --- v2.2.10/linux/arch/mips/arc/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/misc.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,84 @@ +/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ + * + * misc.c: Miscellaneous ARCS PROM routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include + +#include +#include +#include +#include + +extern unsigned long mips_cputype; +extern void *sgiwd93_host; +extern void reset_wd33c93(void *instance); + +void prom_halt(void) +{ + bcops->bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + romvec->halt(); +} + +void prom_powerdown(void) +{ + bcops->bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + romvec->pdown(); +} + +/* XXX is this a soft reset basically? XXX */ +void prom_restart(void) +{ + bcops->bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + romvec->restart(); +} + +void prom_reboot(void) +{ + bcops->bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + romvec->reboot(); +} + +void prom_imode(void) +{ + bcops->bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + romvec->imode(); +} + +long prom_cfgsave(void) +{ + return romvec->cfg_save(); +} + +struct linux_sysid *prom_getsysid(void) +{ + return romvec->get_sysid(); +} + +__initfunc(void prom_cacheflush(void)) +{ + romvec->cache_flush(); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c --- v2.2.10/linux/arch/mips/arc/printf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/printf.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,40 @@ +/* + * printf.c: Putting things on the screen using SGI arcs + * PROM facilities. + * + * Copyright (C) 1996 David S. Miller (dm@sgi.com) + * + * $Id: printf.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + */ +#include +#include +#include + +#include + +static char ppbuf[1024]; + +#ifdef CONFIG_SGI_PROM_CONSOLE +void prom_printf(char *fmt, ...) +#else +__initfunc(void prom_printf(char *fmt, ...)) +#endif +{ + va_list args; + char ch, *bptr; + int i; + + va_start(args, fmt); + i = vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while((ch = *(bptr++)) != 0) { + if(ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); + } + va_end(args); + return; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/salone.c linux/arch/mips/arc/salone.c --- v2.2.10/linux/arch/mips/arc/salone.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/salone.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,25 @@ +/* + * salone.c: Routines to load into memory and execute stand-along + * program images using ARCS PROM firmware. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: salone.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ + */ +#include +#include + +__initfunc(long prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr)) +{ + return romvec->load(name, end, pc, eaddr); +} + +__initfunc(long prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp)) +{ + return romvec->invoke(pc, sp, argc, argv, envp); +} + +__initfunc(long prom_exec(char *name, long argc, char **argv, char **envp)) +{ + return romvec->exec(name, argc, argv, envp); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/time.c linux/arch/mips/arc/time.c --- v2.2.10/linux/arch/mips/arc/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/time.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,19 @@ +/* + * time.c: Extracting time information from ARCS prom. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: time.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + */ +#include +#include + +__initfunc(struct linux_tinfo *prom_gettinfo(void)) +{ + return romvec->get_tinfo(); +} + +__initfunc(unsigned long prom_getrtime(void)) +{ + return romvec->get_rtime(); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/arc/tree.c linux/arch/mips/arc/tree.c --- v2.2.10/linux/arch/mips/arc/tree.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/arc/tree.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,109 @@ +/* + * tree.c: PROM component device tree code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * $Id: tree.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + */ +#include +#include + +#define DEBUG_PROM_TREE + +__initfunc(pcomponent *prom_getsibling(pcomponent *this)) +{ + if(this == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + return romvec->next_component(this); +} + +__initfunc(pcomponent *prom_getchild(pcomponent *this)) +{ + return romvec->child_component(this); +} + +__initfunc(pcomponent *prom_getparent(pcomponent *child)) +{ + if(child == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + return romvec->parent_component(child); +} + +__initfunc(long prom_getcdata(void *buffer, pcomponent *this)) +{ + return romvec->component_data(buffer, this); +} + +__initfunc(pcomponent *prom_childadd(pcomponent *this, pcomponent *tmp, void *data)) +{ + return romvec->child_add(this, tmp, data); +} + +__initfunc(long prom_delcomponent(pcomponent *this)) +{ + return romvec->comp_del(this); +} + +__initfunc(pcomponent *prom_componentbypath(char *path)) +{ + return romvec->component_by_path(path); +} + +#ifdef DEBUG_PROM_TREE +static char *classes[] = { + "system", "processor", "cache", "adapter", "controller", "peripheral", + "memory" +}; + +static char *types[] = { + "arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", "sccache", + "memdev", "eisa adapter", "tc adapter", "scsi adapter", "dti adapter", + "multi-func adapter", "disk controller", "tp controller", + "cdrom controller", "worm controller", "serial controller", + "net controller", "display controller", "parallel controller", + "pointer controller", "keyboard controller", "audio controller", + "misc controller", "disk peripheral", "floppy peripheral", + "tp peripheral", "modem peripheral", "monitor peripheral", + "printer peripheral", "pointer peripheral", "keyboard peripheral", + "terminal peripheral", "line peripheral", "net peripheral", + "misc peripheral", "anonymous" +}; + +static char *iflags[] = { + "bogus", "read only", "removable", "console in", "console out", + "input", "output" +}; + +__initfunc(static void dump_component(pcomponent *p)) +{ + prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>", + p, classes[p->class], types[p->type], + iflags[p->iflags], p->vers, p->rev); + prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n", + p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); +} + +__initfunc(static void traverse(pcomponent *p, int op)) +{ + dump_component(p); + if(prom_getchild(p)) + traverse(prom_getchild(p), 1); + if(prom_getsibling(p) && op) + traverse(prom_getsibling(p), 1); +} + +__initfunc(void prom_testtree(void)) +{ + pcomponent *p; + + p = prom_getchild(PROM_NULL_COMPONENT); + dump_component(p); + p = prom_getchild(p); + while(p) { + dump_component(p); + p = prom_getsibling(p); + } + prom_printf("press a key\n"); + prom_getchar(); +} +#endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/Makefile linux/arch/mips/baget/Makefile --- v2.2.10/linux/arch/mips/baget/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,75 @@ +# $Id$ +# +# Makefile for the Baget specific kernel interface routines +# under Linux. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +all: baget.a + +image: ../../../vmlinux + cp -f $< $@ + +O_TARGET := baget.a +O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o + +ifeq ($(CONFIG_SERIAL),y) + OX_OBJS += vacserial.o +else + ifeq ($(CONFIG_SERIAL),m) + MX_OBJS += vacserial.o + endif +endif +ifeq ($(CONFIG_VAC_RTC),y) + OX_OBJS += vacrtc.o +else + ifeq ($(CONFIG_VAC_RTC),m) + MX_OBJS += vacrtc.o + endif +endif + +bagetIRQ.o : bagetIRQ.S + $(CC) $(CFLAGS) -c -o $@ $< + + +##################### Baget Loader stuff ######################## + +dummy.c: + touch $@ + +image.bin: image + $(OBJCOPY) -O binary $< $@ + +ramdisk.bin: + echo "Dummy ramdisk used. Provide your own if needed !" > $@ + +dummy.o: dummy.c image.bin ramdisk.bin + $(CC) $(CFLAGS) -c -o $@ $< + $(OBJCOPY) --add-section=.vmlinux=image.bin \ + --add-section=.ramdisk=ramdisk.bin $@ + +balo.h: image + $(NM) $< | awk ' \ + BEGIN { printf "/* DO NOT EDIT THIS FILE */\n" } \ + /kernel_entry/ { printf "#define START 0x%s\n", $$1 } \ + /balo_ramdisk_base/ { printf "#define RAMDISK_BASE 0x%s\n", $$1 } \ + /balo_ramdisk_size/ { printf "#define RAMDISK_SIZE 0x%s\n", $$1 } \ + ' > $@ +balo.o: balo.c balo.h + $(CC) $(CFLAGS) -c $< + +balo_supp.o: balo_supp.S + $(CC) $(CFLAGS) -c $< + +balo: balo.o dummy.o balo_supp.o print.o + $(LD) $(LDFLAGS) -T ld.script.balo -o $@ $^ + +clean: + rm -f balo.o balo.h dummy.o dummy.c hello.o image.bin image balo_supp.o + rm -f $(O_OBJS) $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/baget.c linux/arch/mips/baget/baget.c --- v2.2.10/linux/arch/mips/baget/baget.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/baget.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,104 @@ +/* $Id$ + * + * baget.c: Baget low level stuff + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + */ +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* + * Following values are set by BALO into RAM disk buffer parameters + */ +unsigned long balo_ramdisk_base = 0xBA; /* Signature for BALO ! */ +unsigned long balo_ramdisk_size = 0; + + +/* + * Following code is based on routines from 'mm/vmalloc.c' + * Additional parameters ioaddr is needed to iterate across real I/O address. + */ +static inline int alloc_area_pte(pte_t * pte, unsigned long address, + unsigned long size, unsigned long ioaddr) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + while (address < end) { + unsigned long page; + if (!pte_none(*pte)) + printk("kseg2_alloc_io: page already exists\n"); + /* + * For MIPS looks pretty to have transparent mapping + * for KSEG2 areas -- user can't access one, and no + * problems with virtual <--> physical translation. + */ + page = ioaddr & PAGE_MASK; + + set_pte(pte, __pte(page | pgprot_val(PAGE_USERIO) | + _PAGE_GLOBAL | __READABLE | __WRITEABLE)); + address += PAGE_SIZE; + ioaddr += PAGE_SIZE; + pte++; + } + return 0; +} + +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, + unsigned long size, unsigned long ioaddr) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + while (address < end) { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + if (alloc_area_pte(pte, address, end - address, ioaddr)) + return -ENOMEM; + address = (address + PMD_SIZE) & PMD_MASK; + ioaddr += PMD_SIZE; + pmd++; + } + return 0; +} + +int kseg2_alloc_io (unsigned long address, unsigned long size) +{ + pgd_t * dir; + unsigned long end = address + size; + + dir = pgd_offset_k(address); + flush_cache_all(); + while (address < end) { + pmd_t *pmd; + pgd_t olddir = *dir; + + pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (alloc_area_pmd(pmd, address, end - address, address)) + return -ENOMEM; + if (pgd_val(olddir) != pgd_val(*dir)) + set_pgdir(address, *dir); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_all(); + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/bagetIRQ.S linux/arch/mips/baget/bagetIRQ.S --- v2.2.10/linux/arch/mips/baget/bagetIRQ.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/bagetIRQ.S Mon Aug 9 12:04:38 1999 @@ -0,0 +1,98 @@ +/* $Id$ + * bagetIRQ.S: Interrupt exception dispatch code for Baget/MIPS + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +#include +#include +#include +#include +#include +#include + + .text + .set mips1 + .set reorder + .set macro + .set noat + .align 5 + +NESTED(bagetIRQ, PT_SIZE, sp) + SAVE_ALL + CLI # Important: mark KERNEL mode ! + + la a1, baget_interrupt + .set push + .set noreorder + jal a1 + .set pop + move a0, sp + + la a1, ret_from_irq + jr a1 +END(bagetIRQ) + +#define DBE_HANDLER 0x1C + +NESTED(try_read, PT_SIZE, sp) + mfc0 t3, CP0_STATUS # save flags and + CLI # disable interrupts + + li t0, KSEG2 + sltu t1, t0, a0 # Is it KSEG2 address ? + beqz t1, mapped # No - already mapped ! + + move t0, a0 + ori t0, 0xfff + xori t0, 0xfff # round address to page + + ori t1, t0, 0xf00 # prepare EntryLo (N,V,D,G) + + mfc0 t2, CP0_ENTRYHI # save ASID value + mtc0 zero, CP0_INDEX + mtc0 t0, CP0_ENTRYHI # Load MMU values ... + mtc0 t1, CP0_ENTRYLO0 + nop # let it understand + nop + tlbwi # ... and write ones + nop + nop + mtc0 t2, CP0_ENTRYHI + +mapped: + la t0, exception_handlers + lw t1, DBE_HANDLER(t0) # save real handler + la t2, dbe_handler + sw t2, DBE_HANDLER(t0) # set temporary local handler + li v0, -1 # default (failure) value + + li t2, 1 + beq t2, a1, 1f + li t2, 2 + beq t2, a1, 2f + li t2, 4 + beq t2, a1, 4f + b out + +1: lbu v0, (a0) # byte + b out + +2: lhu v0, (a0) # short + b out + +4: lw v0, (a0) # word + +out: + sw t1, DBE_HANDLER(t0) # restore real handler + mtc0 t3, CP0_STATUS # restore CPU flags + jr ra + +dbe_handler: + li v0, -1 # mark our failure + .set push + .set noreorder + b out # "no problems !" + rfe # return from trap + .set pop +END(try_read) diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/balo.c linux/arch/mips/baget/balo.c --- v2.2.10/linux/arch/mips/baget/balo.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/balo.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,190 @@ +/* $Id$ + * + * balo.c: BAget LOader + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + */ +#include +#include +#include +#include + +#include + +#include "balo.h" /* Includes some kernel symbol values */ + +static char *banner = "\nBaget Linux Loader v0.2\n"; + +static void mem_move (long *to, long *from, long size) +{ + while (size > 0) { + *to++ = *from++; + size -= sizeof(long); + } +} + +static volatile int *mem_limit = (volatile int*)KSEG1; +static volatile int *mem_limit_dbe = (volatile int*)KSEG1; + +static int can_write (volatile int* p) { + return p < (int*)(KSEG1+BALO_OFFSET) || + p >= (int*)(KSEG1+BALO_OFFSET+BALO_SIZE); +} + +static volatile enum balo_state_enum { + BALO_INIT, + MEM_INIT, + MEM_PROBE, + START_KERNEL +} balo_state = BALO_INIT; + + +static __inline__ void reset_and_jump(int start, int mem_upper) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "mfc0\t$1,$12\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "ori\t$1,$1,0xff00\n\t" + "xori\t$1,$1,0xff00\n\t" + "mtc0\t$1,$12\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "move\t$4,%1\n\t" + "jr\t%0\n\t" + "nop\n\t" + ".set\tat\n\t" + ".set\treorder" + : /* no outputs */ + :"Ir" (start), "Ir" (mem_upper) + :"$1", "$4", "memory"); +} + +static void start_kernel(void) +{ + extern char _vmlinux_start, _vmlinux_end; + extern char _ramdisk_start, _ramdisk_end; + + outs( "Relocating Linux... " ); + mem_move((long*)KSEG0, (long*)&_vmlinux_start, + &_vmlinux_end-&_vmlinux_start); + outs("done.\n"); + + if (&_ramdisk_start != &_ramdisk_end) { + outs("Setting up RAMDISK... "); + if (*(unsigned long*)RAMDISK_BASE != 0xBA) { + outs("Bad RAMDISK_BASE signature in system image.\n"); + balo_hungup(); + } + *(unsigned long*)RAMDISK_BASE = (unsigned long)&_ramdisk_start; + *(unsigned long*)RAMDISK_SIZE = &_ramdisk_end -&_ramdisk_start; + outs("done.\n"); + } + + { + extern void flush_cache_low(int isize, int dsize); + flush_cache_low(256*1024,256*1024); + } + + balo_printf( "Kernel entry: %x\n\n", START); + balo_state = START_KERNEL; + reset_and_jump(START, (int)mem_limit-KSEG1+KSEG0); +} + + +static void mem_probe(void) +{ + balo_state = MEM_PROBE; + outs("RAM: <"); + while(mem_limit < mem_limit_dbe) { + if (can_write(mem_limit) && *mem_limit != 0) + break; /* cycle found */ + outc('.'); + if (can_write(mem_limit)) + *mem_limit = -1; /* mark */ + mem_limit += 0x40000; + } + outs(">\n"); + start_kernel(); +} + +volatile unsigned int int_cause; +volatile unsigned int epc; +volatile unsigned int badvaddr; + +static void print_regs(void) +{ + balo_printf("CAUSE=%x EPC=%x BADVADDR=%x\n", + int_cause, epc, badvaddr); +} + +void int_handler(struct pt_regs *regs) +{ + switch (balo_state) { + case BALO_INIT: + balo_printf("\nBALO: trap in balo itself.\n"); + print_regs(); + balo_hungup(); + break; + case MEM_INIT: + if ((int_cause & CAUSE_MASK) != CAUSE_DBE) { + balo_printf("\nBALO: unexpected trap during memory init.\n"); + print_regs(); + balo_hungup(); + } else { + mem_probe(); + } + break; + case MEM_PROBE: + balo_printf("\nBALO: unexpected trap during memory probe.\n"); + print_regs(); + balo_hungup(); + break; + case START_KERNEL: + balo_printf("\nBALO: unexpected kernel trap.\n"); + print_regs(); + balo_hungup(); + break; + } + balo_printf("\nBALO: unexpected return from handler.\n"); + print_regs(); + balo_hungup(); +} + +static void mem_init(void) +{ + balo_state = MEM_INIT; + + while(1) { + *mem_limit_dbe; + if (can_write(mem_limit_dbe)) + *mem_limit_dbe = 0; + + mem_limit_dbe += 0x40000; /* +1M */ + } + /* no return: must go to int_handler */ +} + +void balo_entry(void) +{ + extern void except_vec3_generic(void); + + cli(); + outs(banner); + memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80); + mem_init(); +} + +/* Needed for linking */ + +int vsprintf(char *buf, const char *fmt, va_list arg) +{ + outs("BALO: vsprintf called.\n"); + balo_hungup(); + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/balo_supp.S linux/arch/mips/baget/balo_supp.S --- v2.2.10/linux/arch/mips/baget/balo_supp.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/balo_supp.S Mon Aug 9 12:04:38 1999 @@ -0,0 +1,143 @@ +/* $Id$ + * balo_supp.S: BAget Loader supplement + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +#include +#include +#include +#include +#include + + .text + .set mips1 + + /* General exception vector. */ +NESTED(except_vec3_generic, 0, sp) + .set noat + la k0, except_vec3_generic_code + jr k0 +END(except_vec3_generic) + +NESTED(except_vec3_generic_code, 0, sp) + SAVE_ALL + mfc0 k1, CP0_CAUSE + la k0, int_cause + sw k1, (k0) + + mfc0 k1, CP0_EPC + la k0, epc + sw k1, (k0) + + mfc0 k1, CP0_BADVADDR + la k0, badvaddr + sw k1, (k0) + + la k0, int_handler + .set noreorder + jal k0 + .set reorder + move a0, sp + + RESTORE_ALL_AND_RET +END(except_vec3_generic_code) + + .align 5 +NESTED(flush_cache_low, PT_SIZE, sp) + .set at + .set macro + .set noreorder + + move t1, a0 # ISIZE + move t2, a1 # DSIZE + + mfc0 t3, CP0_STATUS # Save the status register. + mtc0 zero, CP0_STATUS # Disable interrupts. + la v0, 1f + or v0, KSEG1 # Run uncached. + j v0 + nop +/* + * Flush the instruction cache. + */ +1: + li v0, ST0_DE | ST0_CE + mtc0 v0, CP0_STATUS # Isolate and swap caches. + li t0, KSEG1 + subu t0, t0, t1 + li t1, KSEG1 + la v0, 1f # Run cached + j v0 + nop +1: + addu t0, t0, 64 + sb zero, -64(t0) + sb zero, -60(t0) + sb zero, -56(t0) + sb zero, -52(t0) + sb zero, -48(t0) + sb zero, -44(t0) + sb zero, -40(t0) + sb zero, -36(t0) + sb zero, -32(t0) + sb zero, -28(t0) + sb zero, -24(t0) + sb zero, -20(t0) + sb zero, -16(t0) + sb zero, -12(t0) + sb zero, -8(t0) + bne t0, t1, 1b + sb zero, -4(t0) + + la v0, 1f + or v0, KSEG1 + j v0 # Run uncached + nop +/* + * Flush the data cache. + */ +1: + li v0, ST0_DE + mtc0 v0, CP0_STATUS # Isolate and swap back caches + li t0, KSEG1 + subu t0, t0, t2 + la v0, 1f + j v0 # Back to cached mode + nop +1: + addu t0, t0, 64 + sb zero, -64(t0) + sb zero, -60(t0) + sb zero, -56(t0) + sb zero, -52(t0) + sb zero, -48(t0) + sb zero, -44(t0) + sb zero, -40(t0) + sb zero, -36(t0) + sb zero, -32(t0) + sb zero, -28(t0) + sb zero, -24(t0) + sb zero, -20(t0) + sb zero, -16(t0) + sb zero, -12(t0) + sb zero, -8(t0) + bne t0, t1, 1b + sb zero, -4(t0) + + nop # Insure isolated stores + nop # out of pipe. + nop + nop + mtc0 t3, CP0_STATUS # Restore status reg. + nop # Insure cache unisolated. + nop + nop + nop + j ra + nop +END(flush_cache_low) + +/* To satisfy macros only */ +EXPORT(kernelsp) + PTR 0x80001000 diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c --- v2.2.10/linux/arch/mips/baget/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/irq.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,438 @@ +/* + * Code to handle Baget/MIPS IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1998 Vladimir Roganov & Gleb Raiko + * Code (mostly sleleton and comments) derived from DECstation IRQ + * handling. + * + * $Id$ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; + +atomic_t __mips_bh_counter; + +/* + * This table is a correspondence between IRQ numbers and CPU PILs + */ + +static int irq_to_pil_map[BAGET_IRQ_NR] = { + 7/*fixme: dma_err -1*/,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x00 - 0x0f */ + -1,-1,-1,-1, 3,-1,-1,-1, 2, 2, 2,-1, 3,-1,-1,3/*fixme: lance*/, /* 0x10 - 0x1f */ + -1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1, 7,-1,-1,-1, /* 0x20 - 0x2f */ + -1, 3, 2/*fixme systimer:3*/, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 /* 0x30 - 0x3f */ +}; + +static inline int irq_to_pil(int irq_nr) +{ + int pil = -1; + + if (irq_nr >= BAGET_IRQ_NR) + baget_printk("irq_to_pil: too large irq_nr = 0x%x\n", irq_nr); + else { + pil = irq_to_pil_map[irq_nr]; + if (pil == -1) + baget_printk("irq_to_pil: unknown irq = 0x%x\n", irq_nr); + } + + return pil; +} + +/* Function for careful CP0 interrupt mask access */ + +static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) +{ + unsigned long status = read_32bit_cp0_register(CP0_STATUS); + status &= ~((clr_mask & 0xFF) << 8); + status |= (set_mask & 0xFF) << 8; + write_32bit_cp0_register(CP0_STATUS, status); +} + +/* + * These two functions may be used for unconditional IRQ + * masking via their PIL protection. + */ + +static inline void mask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(irq_to_pil(irq_nr), 0); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + modify_cp0_intmask(0, irq_to_pil(irq_nr)); +} + +/* + * The following section is introduced for masking/unasking IRQ + * only while no more IRQs uses same CPU PIL. + * + * These functions are used in request_irq, free_irq, but it looks + * they cannot change something: CP0_STATUS is private for any + * process, and their action is invisible for system. + */ + +static volatile unsigned int pil_in_use[BAGET_PIL_NR] = { 0, }; + +void mask_irq_count(int irq_nr) +{ + unsigned long flags; + int pil = irq_to_pil(irq_nr); + + save_and_cli(flags); + if (!--pil_in_use[pil]) + mask_irq(irq_nr); + restore_flags(flags); +} + +void unmask_irq_count(int irq_nr) +{ + unsigned long flags; + int pil = irq_to_pil(irq_nr); + + save_and_cli(flags); + if (!pil_in_use[pil]++) + unmask_irq(irq_nr); + restore_flags(flags); +} + +/* + * Two functions below are exported versions of mask/unmask IRQ + */ + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + +/* + * Data definition for static irqaction allocation. + * It is used while SLAB module is not initialized. + */ + +#define MAX_STATIC_ALLOC 4 +struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +int static_irq_count = 0; + +/* + * Pointers to the low-level handlers: first the general ones, then the + * fast ones, then the bad ones. + */ +static struct irqaction *irq_action[BAGET_IRQ_NR] = { NULL, }; + +int get_irq_list(char *buf) +{ + int i, len = 0; + struct irqaction * action; + + for (i = 0 ; i < BAGET_IRQ_NR ; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %8d %c %s", + i, kstat.irqs[0][i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf+len, "\n"); + } + return len; +} + + +/* + * do_IRQ handles IRQ's that have been installed without the + * SA_INTERRUPT flag: it uses the full signal-handling return + * and runs with other interrupts enabled. All relatively slow + * IRQ's should use this format: notably the keyboard/timer + * routines. + */ +static void do_IRQ(int irq, struct pt_regs * regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + hardirq_enter(cpu); + kstat.irqs[cpu][irq]++; + + mask_irq(irq); + action = *(irq + irq_action); + if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + } else { + printk("do_IRQ: Unregistered IRQ (0x%X) occured\n", irq); + } + unmask_irq(irq); + hardirq_exit(cpu); + + /* unmasking and bottom half handling is done magically for us. */ +} + +/* + * What to do in case of 'no VIC register available' for current interrupt + */ +static void vic_reg_error(unsigned long address, unsigned char active_pils) +{ + printk("\nNo VIC register found: reg=%08lx active_pils=%02x\n" + "Current interrupt mask from CP0_CAUSE: %02x\n", + address, 0xff & active_pils, + 0xff & (read_32bit_cp0_register(CP0_CAUSE)>>8)); + { int i; for (i=0; i<10000; i++) udelay(1000); } +} + +static char baget_fpu_irq = BAGET_FPU_IRQ; +#define BAGET_INT_FPU {(unsigned long)&baget_fpu_irq, 1} + +/* + * Main interrupt handler: interrupt demultiplexer + */ +asmlinkage void baget_interrupt(struct pt_regs *regs) +{ + static struct baget_int_reg int_reg[BAGET_PIL_NR] = { + BAGET_INT_NONE, BAGET_INT_NONE, BAGET_INT0_ACK, BAGET_INT1_ACK, + BAGET_INT_NONE, BAGET_INT_FPU, BAGET_INT_NONE, BAGET_INT5_ACK + }; + unsigned char active_pils; + while ((active_pils = read_32bit_cp0_register(CP0_CAUSE)>>8)) { + int pil; + struct baget_int_reg* reg; + + for (pil = 0; pil < BAGET_PIL_NR; pil++) { + if (!(active_pils & (1<address) { + extern int try_read(unsigned long,int); + int irq = try_read(reg->address, reg->size); + + if (irq != -1) + do_IRQ(BAGET_IRQ_MASK(irq), regs); + else + vic_reg_error(reg->address, active_pils); + } else { + printk("baget_interrupt: unknown interrupt " + "(pil = %d)\n", pil); + } + } + } +} + +/* + * Idea is to put all interrupts + * in a single table and differenciate them just by number. + */ +int setup_baget_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_and_cli(flags); + *p = new; + restore_flags(flags); + + if (!shared) { + unmask_irq_count(irq); + } + + return 0; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action = NULL; + + if (irq >= BAGET_IRQ_NR) + return -EINVAL; + if (!handler) + return -EINVAL; + if (irq_to_pil_map[irq] < 0) + return -EINVAL; + + if (irqflags & SA_STATIC_ALLOC) { + unsigned long flags; + + save_and_cli(flags); + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " + "using kmalloc\n", irq, devname); + restore_flags(flags); + } + + if (action == NULL) + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_baget_irq(irq, action); + + if (retval) + kfree(action); + + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction * action, **p; + unsigned long flags; + + if (irq >= BAGET_IRQ_NR) + printk("Trying to free IRQ%d\n",irq); + + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_and_cli(flags); + *p = action->next; + if (!irq[irq_action]) + unmask_irq_count(irq); + restore_flags(flags); + + if (action->flags & SA_STATIC_ALLOC) + { + /* This interrupt is marked as specially allocated + * so it is a bad idea to free it. + */ + printk("Attempt to free statically allocated " + "IRQ%d (%s)\n", irq, action->name); + return; + } + + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); +} + +static int baget_irq_canonicalize(int irq) +{ + return irq; +} + +int (*irq_cannonicalize)(int irq) = baget_irq_canonicalize; + +unsigned long probe_irq_on (void) +{ + /* TODO */ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + /* TODO */ + return 0; +} + + +static void write_err_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + *(volatile char*) BAGET_WRERR_ACK = 0; +} + +__initfunc(void init_IRQ(void)) +{ + irq_setup(); + + /* Enable access to VIC interrupt registers */ + vac_outw(0xacef | 0x8200, VAC_PIO_FUNC); + + /* Enable interrupts for pils 2 and 3 (lines 0 and 1) */ + modify_cp0_intmask(0, (1<<2)|(1<<3)); + + if (request_irq(0/*fixme*/, write_err_interrupt, + SA_INTERRUPT|SA_STATIC_ALLOC, "write_err", NULL) < 0) + printk("init_IRQ: unable to register write_err irq\n"); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/ld.script.balo linux/arch/mips/baget/ld.script.balo --- v2.2.10/linux/arch/mips/baget/ld.script.balo Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/ld.script.balo Mon Aug 9 12:04:38 1999 @@ -0,0 +1,124 @@ +OUTPUT_FORMAT("elf32-bigmips") +OUTPUT_ARCH(mips) +ENTRY(balo_entry) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x80400000; + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + + _etext = .; + PROVIDE (etext = .); + + /* Startup code */ + . = ALIGN(4096); + __init_begin = .; + *(.text.init) + *(.data.init) + . = ALIGN(4096); /* Align double page for init_task_union */ + __init_end = .; + + *(.fini) + *(.reginfo) + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = .; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + . = .; + _fdata = . ; + *(.data) + CONSTRUCTORS + + *(.data1) + _gp = . + 0x8000; + *(.lit8) + *(.lit4) + *(.ctors) + *(.dtors) + *(.got.plt) *(.got) + *(.dynamic) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata) + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + _fbss = .; + + *(.dynbss) + *(.bss) + *(COMMON) + _end = . ; + PROVIDE (end = .); + *(.sbss) + *(.scommon) + + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + *(.stab) + *(.stabstr) + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + *(.debug) + *(.debug_srcinfo) + *(.debug_aranges) + *(.debug_pubnames) + *(.debug_sfnames) + *(.line) + /* These must appear regardless of . */ + *(.gptab.data) *(.gptab.sdata) + *(.gptab.bss) *(.gptab.sbss) + + _vmlinux_start = .; + *(.vmlinux) + _vmlinux_end = .; + + _ramdisk_start = .; + *(.ramdisk) + _ramdisk_end = .; + +} =0 + +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/print.c linux/arch/mips/baget/print.c --- v2.2.10/linux/arch/mips/baget/print.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/print.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,118 @@ +/* $Id$ + * + * print.c: Simple print fascility + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + */ +#include +#include +#include + +#include + +/* + * Define this to see 'baget_printk' (debug) messages + */ +// #define BAGET_PRINTK + +/* + * This function is same for BALO and Linux baget_printk, + * and normally prints characted to second (UART A) console. + */ + +static void delay(void) {} + +static void outc_low(char c) +{ + int i; + vac_outb(c, VAC_UART_B_TX); + for (i=0; i<10000; i++) + delay(); +} + +void outc(char c) +{ + if (c == '\n') + outc_low('\r'); + outc_low(c); +} + +void outs(char *s) +{ + while(*s) outc(*s++); +} + +void baget_write(char *s, int l) +{ + while(l--) + outc(*s++); +} + +int baget_printk(const char *fmt, ...) +{ +#ifdef BAGET_PRINTK + va_list args; + int i; + static char buf[1024]; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf)-4 */ + va_end(args); + baget_write(buf, i); + return i; +#else + return 0; +#endif +} + +static __inline__ void puthex( int a ) +{ + static char s[9]; + static char e[] = "0123456789ABCDEF"; + int i; + for( i = 7; i >= 0; i--, a >>= 4 ) s[i] = e[a & 0x0F]; + s[8] = '\0'; + outs( s ); +} + +__initfunc(void balo_printf( char *f, ... )) +{ + int *arg = (int*)&f + 1; + char c; + int format = 0; + + while((c = *f++) != 0) { + switch(c) { + default: + if(format) { + outc('%'); + format = 0; + } + outc( c ); + break; + case '%': + if( format ){ + format = 0; + outc(c); + } else format = 1; + break; + case 'x': + if(format) puthex( *arg++ ); + else outc(c); + format = 0; + break; + case 's': + if( format ) outs((char *)*arg++); + else outc(c); + format = 0; + break; + } + } +} + +__initfunc(void balo_hungup(void)) +{ + outs("Hunging up.\n"); + while(1); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/prom/Makefile linux/arch/mips/baget/prom/Makefile --- v2.2.10/linux/arch/mips/baget/prom/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/prom/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,15 @@ +# $Id$ +# Makefile for the Baget/MIPS prom emulator library routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := bagetlib.a +O_OBJS := init.o + +all: $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/prom/init.c linux/arch/mips/baget/prom/init.c --- v2.2.10/linux/arch/mips/baget/prom/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/prom/init.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,20 @@ +/* + * init.c: PROM library initialisation code. + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + * $Id$ + */ +#include +#include + +char arcs_cmdline[CL_SIZE]; + +__initfunc(int prom_init(unsigned int mem_upper)) +{ + mips_memory_upper = mem_upper; + mips_machgroup = MACH_GROUP_UNKNOWN; + mips_machtype = MACH_UNKNOWN; + arcs_cmdline[0] = 0; + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/reset.c linux/arch/mips/baget/reset.c --- v2.2.10/linux/arch/mips/baget/reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/reset.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,32 @@ +#include +#include +#include + + +#define R3000_RESET_VEC 0xbfc00000 +typedef void vector(void); + + +static void baget_reboot(char *from_fun) +{ + cli(); + baget_printk("\n%s: jumping to RESET code...\n", from_fun); + (*(vector*)R3000_RESET_VEC)(); +} + +/* fixme: proper functionality */ + +void baget_machine_restart(char *command) +{ + baget_reboot("restart"); +} + +void baget_machine_halt(void) +{ + baget_reboot("halt"); +} + +void baget_machine_power_off(void) +{ + baget_reboot("power off"); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/setup.c linux/arch/mips/baget/setup.c --- v2.2.10/linux/arch/mips/baget/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/setup.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,494 @@ +/* $Id$ + * + * setup.c: Baget/MIPS specific setup, including init of the feature struct. + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + */ +#include +#include +#include +#include +#include +#include + +#include + +extern long mips_memory_upper; + +extern void wbflush_setup(void); + +#define CACHEABLE_STR(val) ((val) ? "not cached" : "cached") +#define MIN(a,b) (((a)<(b)) ? (a):(b)) + +__initfunc(static void vac_show(void)) +{ + int i; + unsigned short val, decode = vac_inw(VAC_DECODE_CTRL); + unsigned short a24_base = vac_inw(VAC_A24_BASE); + unsigned long a24_addr = ((unsigned long) + (a24_base & VAC_A24_MASK)) << 16; + char *decode_mode[] = { "eprom", "vsb", "shared", "dram" }; + char *address_mode[] = { "", ", A16", ", A32/A24", ", A32/A24/A16" }; + char *state[] = { "", " on write", " on read", " on read/write", }; + char *region_mode[] = { "inactive", "shared", "vsb", "vme" }; + char *asiz[] = { "user", "A32", "A16", "A24" }; + unsigned short regs[] = { VAC_REG1, VAC_REG2, VAC_REG3 }; + unsigned short bndr[] = { VAC_DRAM_MASK,VAC_BNDR2,VAC_BNDR3 }; + unsigned short io_sels[] = { VAC_IOSEL0_CTRL, + VAC_IOSEL1_CTRL, + VAC_IOSEL2_CTRL, + VAC_IOSEL3_CTRL, + VAC_IOSEL4_CTRL, + VAC_IOSEL5_CTRL }; + + printk("[DSACKi %s, DRAMCS%s qualified, boundary%s qualified%s]\n", + (decode & VAC_DECODE_DSACKI) ? "on" : "off", + (decode & VAC_DECODE_QFY_DRAMCS) ? "" : " not", + (decode & VAC_DECODE_QFY_BNDR) ? "" : " not", + (decode & VAC_DECODE_FPUCS) ? ", fpu" : ""); + + printk("slave0 "); + if (decode & VAC_DECODE_RDR_SLSEL0) + printk("at %08lx (%d MB)\t[dram %s]\n", + ((unsigned long)vac_inw(VAC_SLSEL0_BASE))<<16, + ((0xffff ^ vac_inw(VAC_SLSEL0_MASK)) + 1) >> 4, + (decode & VAC_DECODE_QFY_SLSEL0) ? "qualified" : ""); + else + printk("off\n"); + + printk("slave1 "); + if (decode & VAC_DECODE_RDR_SLSEL1) + printk("at %08lx (%d MB)\t[%s%s, %s]\n", + ((unsigned long)vac_inw(VAC_SLSEL1_BASE))<<16, + ((0xffff ^ vac_inw(VAC_SLSEL1_MASK)) + 1) >> 4, + decode_mode[VAC_DECODE_MODE_VAL(decode)], + address_mode[VAC_DECODE_CMP_SLSEL1_VAL(decode)], + (decode & VAC_DECODE_QFY_SLSEL1) ? "qualified" : ""); + else + printk("off\n"); + + printk("icf global at %04x, module at %04x [%s]\n", + ((unsigned int) + VAC_ICFSEL_GLOBAL_VAL(vac_inw(VAC_ICFSEL_BASE)))<<4, + ((unsigned int) + VAC_ICFSEL_MODULE_VAL(vac_inw(VAC_ICFSEL_BASE)))<<4, + (decode & VAC_DECODE_QFY_ICFSEL) ? "qualified" : ""); + + + printk("region0 at 00000000 (%dMB)\t[dram, %s, delay %d cpuclk" + ", cached]\n", + (vac_inw(VAC_DRAM_MASK)+1)>>4, + (decode & VAC_DECODE_DSACK) ? "D32" : "3state", + VAC_DECODE_CPUCLK_VAL(decode)); + + for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) { + unsigned long from = + ((unsigned long)vac_inw(bndr[i]))<<16; + unsigned long to = + ((unsigned long) + ((i+1 == sizeof(bndr)/sizeof(bndr[0])) ? + 0xff00 : vac_inw(bndr[i+1])))<<16; + + + val = vac_inw(regs[i]); + printk("region%d at %08lx (%dMB)\t[%s %s/%s, %s]\n", + i+1, + from, + (unsigned int)((to - from) >> 20), + region_mode[VAC_REG_MODE(val)], + asiz[VAC_REG_ASIZ_VAL(val)], + ((val & VAC_REG_WORD) ? "D16" : "D32"), + CACHEABLE_STR(val&VAC_A24_A24_CACHINH)); + + if (a24_addr >= from && a24_addr < to) + printk("\ta24 at %08lx (%dMB)\t[vme, A24/%s, %s]\n", + a24_addr, + MIN((unsigned int)(a24_addr - from)>>20, 32), + (a24_base & VAC_A24_DATAPATH) ? "user" : + ((a24_base & VAC_A24_D32_ENABLE) ? + "D32" : "D16"), + CACHEABLE_STR(a24_base & VAC_A24_A24_CACHINH)); + } + + printk("region4 at ff000000 (15MB)\t[eprom]\n"); + val = vac_inw(VAC_EPROMCS_CTRL); + printk("\t[ack %d cpuclk%s, %s%srecovery %d cpuclk, " + "read %d%s, write %d%s, assert %d%s]\n", + VAC_CTRL_DELAY_DSACKI_VAL(val), + state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)], + (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "", + (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "", + VAC_CTRL_RECOVERY_IOSELI_VAL(val), + VAC_CTRL_DELAY_IORD_VAL(val)/2, + (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOWR_VAL(val)/2, + (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOSELI_VAL(val)/2, + (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : ""); + + printk("region5 at fff00000 (896KB)\t[local io, %s]\n", + CACHEABLE_STR(vac_inw(VAC_A24_BASE) & VAC_A24_IO_CACHINH)); + + for (i = 0; i < sizeof(io_sels)/sizeof(io_sels[0]); i++) { + val = vac_inw(io_sels[i]); + printk("\tio%d[ack %d cpuclk%s, %s%srecovery %d cpuclk, " + "\n\t read %d%s cpuclk, write %d%s cpuclk, " + "assert %d%s%s cpuclk]\n", + i, + VAC_CTRL_DELAY_DSACKI_VAL(val), + state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)], + (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "", + (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "", + VAC_CTRL_RECOVERY_IOSELI_VAL(val), + VAC_CTRL_DELAY_IORD_VAL(val)/2, + (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOWR_VAL(val)/2, + (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOSELI_VAL(val)/2, + (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : "", + (vac_inw(VAC_DEV_LOC) & VAC_DEV_LOC_IOSEL(i)) ? + ", id" : ""); + } + + printk("region6 at fffe0000 (128KB)\t[vme, A16/%s, " + "not cached]\n", + (a24_base & VAC_A24_A16D32_ENABLE) ? + ((a24_base & VAC_A24_A16D32) ? "D32" : "D16") : "user"); + + val = vac_inw(VAC_SHRCS_CTRL); + printk("shared[ack %d cpuclk%s, %s%srecovery %d cpuclk, " + "read %d%s, write %d%s, assert %d%s]\n", + VAC_CTRL_DELAY_DSACKI_VAL(val), + state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)], + (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "", + (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "", + VAC_CTRL_RECOVERY_IOSELI_VAL(val), + VAC_CTRL_DELAY_IORD_VAL(val)/2, + (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOWR_VAL(val)/2, + (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "", + VAC_CTRL_DELAY_IOSELI_VAL(val)/2, + (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : ""); +} + +__initfunc(static void vac_init(void)) +{ + unsigned short mem_limit = ((mips_memory_upper-KSEG0) >> 16); + + switch(vac_inw(VAC_ID)) { + case 0x1AC0: + printk("VAC068-F5: "); + break; + case 0x1AC1: + printk("VAC068A: "); + break; + default: + panic("Unknown VAC revision number"); + } + + vac_outw(mem_limit-1, VAC_DRAM_MASK); + vac_outw(mem_limit, VAC_BNDR2); + vac_outw(mem_limit, VAC_BNDR3); + vac_outw(((BAGET_A24M_BASE>>16)&~VAC_A24_D32_ENABLE)|VAC_A24_DATAPATH, + VAC_A24_BASE); + vac_outw(VAC_REG_INACTIVE|VAC_REG_ASIZ0,VAC_REG1); + vac_outw(VAC_REG_INACTIVE|VAC_REG_ASIZ0,VAC_REG2); + vac_outw(VAC_REG_MWB|VAC_REG_ASIZ1,VAC_REG3); + vac_outw(BAGET_A24S_BASE>>16,VAC_SLSEL0_BASE); + vac_outw(BAGET_A24S_MASK>>16,VAC_SLSEL0_MASK); + vac_outw(BAGET_A24S_BASE>>16,VAC_SLSEL1_BASE); + vac_outw(BAGET_A24S_MASK>>16,VAC_SLSEL1_MASK); + vac_outw(BAGET_GSW_BASE|BAGET_MSW_BASE(0),VAC_ICFSEL_BASE); + vac_outw(VAC_DECODE_FPUCS| + VAC_DECODE_CPUCLK(3)| + VAC_DECODE_RDR_SLSEL0|VAC_DECODE_RDR_SLSEL1| + VAC_DECODE_DSACK| + VAC_DECODE_QFY_BNDR| + VAC_DECODE_QFY_ICFSEL| + VAC_DECODE_QFY_SLSEL1|VAC_DECODE_QFY_SLSEL0| + VAC_DECODE_CMP_SLSEL1_HI| + VAC_DECODE_DRAMCS| + VAC_DECODE_QFY_DRAMCS| + VAC_DECODE_DSACKI,VAC_DECODE_CTRL); + vac_outw(VAC_PIO_FUNC_UART_A_TX|VAC_PIO_FUNC_UART_A_RX| + VAC_PIO_FUNC_UART_B_TX|VAC_PIO_FUNC_UART_B_RX| + VAC_PIO_FUNC_IOWR| + VAC_PIO_FUNC_IOSEL3| + VAC_PIO_FUNC_IRQ7|VAC_PIO_FUNC_IRQ10|VAC_PIO_FUNC_IRQ11| + VAC_PIO_FUNC_IOSEL2| + VAC_PIO_FUNC_FCIACK,VAC_PIO_FUNC); + vac_outw(VAC_PIO_DIR_FCIACK | + VAC_PIO_DIR_OUT(0) | + VAC_PIO_DIR_OUT(1) | + VAC_PIO_DIR_OUT(2) | + VAC_PIO_DIR_OUT(3) | + VAC_PIO_DIR_IN(4) | + VAC_PIO_DIR_OUT(5) | + VAC_PIO_DIR_OUT(6) | + VAC_PIO_DIR_OUT(7) | + VAC_PIO_DIR_OUT(8) | + VAC_PIO_DIR_IN(9) | + VAC_PIO_DIR_OUT(10)| + VAC_PIO_DIR_OUT(11)| + VAC_PIO_DIR_OUT(12)| + VAC_PIO_DIR_OUT(13),VAC_PIO_DIRECTION); + vac_outw(VAC_DEV_LOC_IOSEL(2),VAC_DEV_LOC); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(1)| + VAC_CTRL_DELAY_DSACKI(8),VAC_SHRCS_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(1)| + VAC_CTRL_DSACK0|VAC_CTRL_DSACK1| + VAC_CTRL_DELAY_DSACKI(8),VAC_EPROMCS_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DSACK0|VAC_CTRL_DSACK1| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL0_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DSACK0|VAC_CTRL_DSACK1| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL1_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DSACK0|VAC_CTRL_DSACK1| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL2_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DSACK0|VAC_CTRL_DSACK1| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL3_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL4_CTRL); + vac_outw(VAC_CTRL_IOWR| + VAC_CTRL_DELAY_IOWR(3)| + VAC_CTRL_DELAY_IORD(3)| + VAC_CTRL_RECOVERY_IOSELI(2)| + VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL5_CTRL); + + vac_show(); +} + +__initfunc(static void vac_start(void)) +{ + vac_outw(0, VAC_ID); + vac_outw(VAC_INT_CTRL_TIMER_DISABLE| + VAC_INT_CTRL_UART_B_DISABLE| + VAC_INT_CTRL_UART_A_DISABLE| + VAC_INT_CTRL_MBOX_DISABLE| + VAC_INT_CTRL_PIO4_DISABLE| + VAC_INT_CTRL_PIO7_DISABLE| + VAC_INT_CTRL_PIO8_DISABLE| + VAC_INT_CTRL_PIO9_DISABLE,VAC_INT_CTRL); + vac_outw(VAC_INT_CTRL_TIMER_PIO10| + VAC_INT_CTRL_UART_B_PIO7| + VAC_INT_CTRL_UART_A_PIO7,VAC_INT_CTRL); + /* + * Set quadro speed for both UARTs. + * To do it we need use formulae from VIC/VAC manual, + * keeping in mind Baget's 50MHz frequency... + */ + vac_outw((500000/(384*16))<<8,VAC_CPU_CLK_DIV); +} + +__initfunc(static void vic_show(void)) +{ + unsigned char val; + char *timeout[] = { "4", "16", "32", "64", "128", "256", "disabled" }; + char *deadlock[] = { "[dedlk only]", "[dedlk only]", + "[dedlk], [halt w/ rmc], [lberr]", + "[dedlk], [halt w/o rmc], [lberr]" }; + + val = vic_inb(VIC_IFACE_CFG); + if (val & VIC_IFACE_CFG_VME) + printk("VMEbus controller "); + if (val & VIC_IFACE_CFG_TURBO) + printk("turbo "); + if (val & VIC_IFACE_CFG_MSTAB) + printk("metastability delay "); + printk("%s ", + deadlock[VIC_IFACE_CFG_DEADLOCK_VAL(val)]); + + + printk("interrupts: "); + val = vic_inb(VIC_ERR_INT); + if (!(val & VIC_ERR_INT_SYSFAIL)) + printk("[sysfail]"); + if (!(val & VIC_ERR_INT_TIMO)) + printk("[timeout]"); + if (!(val & VIC_ERR_INT_WRPOST)) + printk("[write post]"); + if (!(val & VIC_ERR_INT_ACFAIL)) + printk("[acfail] "); + printk("\n"); + + printk("timeouts: "); + val = vic_inb(VIC_XFER_TIMO); + printk("local %s, vme %s ", + timeout[VIC_XFER_TIMO_LOCAL_PERIOD_VAL(val)], + timeout[VIC_XFER_TIMO_VME_PERIOD_VAL(val)]); + if (val & VIC_XFER_TIMO_VME) + printk("acquisition "); + if (val & VIC_XFER_TIMO_ARB) + printk("arbitration "); + printk("\n"); + + val = vic_inb(VIC_LOCAL_TIM); + printk("pas time: (%d,%d), ds time: %d\n", + VIC_LOCAL_TIM_PAS_ASSERT_VAL(val), + VIC_LOCAL_TIM_PAS_DEASSERT_VAL(val), + VIC_LOCAT_TIM_DS_DEASSERT_VAL(val)); + + val = vic_inb(VIC_BXFER_DEF); + printk("dma: "); + if (val & VIC_BXFER_DEF_DUAL) + printk("[dual path]"); + if (val & VIC_BXFER_DEF_LOCAL_CROSS) + printk("[local boundary cross]"); + if (val & VIC_BXFER_DEF_VME_CROSS) + printk("[vme boundary cross]"); + +} + +__initfunc(static void vic_init(void)) +{ + unsigned char id = vic_inb(VIC_ID); + if ((id & 0xf0) != 0xf0) + panic("VIC not found"); + printk(" VIC068A Rev. %X: ", id & 0x0f); + + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_II); + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT1); + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT2); + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT3); + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT4); +/* + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT5); +*/ + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT6); + + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT7); + vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_DMA_INT); + vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT1); + vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_HIGH|VIC_INT_DISABLE, VIC_LINT2); + vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_HIGH|VIC_INT_DISABLE, VIC_LINT3); + vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT4); +/* + vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_LEVEL| + VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT5); +*/ + vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT6); + vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT7); + + vic_outb(VIC_INT_IPL(3)| + VIC_INT_SWITCH(0)| + VIC_INT_SWITCH(1)| + VIC_INT_SWITCH(2)| + VIC_INT_SWITCH(3), VIC_ICGS_INT); + vic_outb(VIC_INT_IPL(3)| + VIC_INT_SWITCH(0)| + VIC_INT_SWITCH(1)| + VIC_INT_SWITCH(2)| + VIC_INT_SWITCH(3), VIC_ICMS_INT); + vic_outb(VIC_INT_IPL(6)| + VIC_ERR_INT_SYSFAIL| + VIC_ERR_INT_TIMO| + VIC_ERR_INT_WRPOST| + VIC_ERR_INT_ACFAIL, VIC_ERR_INT); + vic_outb(VIC_ICxS_BASE_ID(0xf), VIC_ICGS_BASE); + vic_outb(VIC_ICxS_BASE_ID(0xe), VIC_ICMS_BASE); + vic_outb(VIC_LOCAL_BASE_ID(0x6), VIC_LOCAL_BASE); + vic_outb(VIC_ERR_BASE_ID(0x3), VIC_ERR_BASE); + vic_outb(VIC_XFER_TIMO_VME_PERIOD_32| + VIC_XFER_TIMO_LOCAL_PERIOD_32, VIC_XFER_TIMO); + vic_outb(VIC_LOCAL_TIM_PAS_ASSERT(2)| + VIC_LOCAT_TIM_DS_DEASSERT(1)| + VIC_LOCAL_TIM_PAS_DEASSERT(1), VIC_LOCAL_TIM); + vic_outb(VIC_BXFER_DEF_VME_CROSS| + VIC_BXFER_DEF_LOCAL_CROSS| + VIC_BXFER_DEF_AMSR| + VIC_BXFER_DEF_DUAL, VIC_BXFER_DEF); + vic_outb(VIC_SSxCR0_LOCAL_XFER_SINGLE| + VIC_SSxCR0_A32|VIC_SSxCR0_D32| + VIC_SS0CR0_TIMER_FREQ_NONE, VIC_SS0CR0); + vic_outb(VIC_SSxCR1_TF1(0xf)| + VIC_SSxCR1_TF2(0xf), VIC_SS0CR1); + vic_outb(VIC_SSxCR0_LOCAL_XFER_SINGLE| + VIC_SSxCR0_A24|VIC_SSxCR0_D32, VIC_SS1CR0); + vic_outb(VIC_SSxCR1_TF1(0xf)| + VIC_SSxCR1_TF2(0xf), VIC_SS1CR1); + vic_outb(VIC_IFACE_CFG_NOHALT| + VIC_IFACE_CFG_NOTURBO, VIC_IFACE_CFG); + vic_outb(VIC_AMS_CODE(0), VIC_AMS); + vic_outb(VIC_BXFER_CTRL_INTERLEAVE(0), VIC_BXFER_CTRL); + vic_outb(0, VIC_BXFER_LEN_LO); + vic_outb(0, VIC_BXFER_LEN_HI); + vic_outb(VIC_REQ_CFG_FAIRNESS_DISABLED| + VIC_REQ_CFG_LEVEL(3)| + VIC_REQ_CFG_RR_ARBITRATION, VIC_REQ_CFG); + vic_outb(VIC_RELEASE_BLKXFER_BLEN(0)| + VIC_RELEASE_RWD, VIC_RELEASE); + vic_outb(VIC_IC6_RUN, VIC_IC6); + vic_outb(0, VIC_IC7); + + vic_show(); +} + +static void vic_start(void) +{ + vic_outb(VIC_INT_IPL(3)| + VIC_INT_NOAUTO| + VIC_INT_EDGE| + VIC_INT_HIGH| + VIC_INT_ENABLE, VIC_LINT7); +} + +__initfunc(void baget_irq_setup(void)) +{ + extern void bagetIRQ(void); + + /* Now, it's safe to set the exception vector. */ + set_except_vector(0, bagetIRQ); +} + +extern void baget_machine_restart(char *command); +extern void baget_machine_halt(void); +extern void baget_machine_power_off(void); + +__initfunc(void baget_setup(void)) +{ + printk("BT23/63-201n found.\n"); + *BAGET_WRERR_ACK = 0; + irq_setup = baget_irq_setup; + + wbflush_setup(); + + _machine_restart = baget_machine_restart; + _machine_halt = baget_machine_halt; + _machine_power_off = baget_machine_power_off; + + vac_init(); + vic_init(); + vac_start(); + vic_start(); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/time.c linux/arch/mips/baget/time.c --- v2.2.10/linux/arch/mips/baget/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/time.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,96 @@ +/* $Id$ + * time.c: Baget/MIPS specific time handling details + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* + * To have precision clock, we need to fix available clock frequency + */ +#define FREQ_NOM 79125 /* Baget frequency ratio */ +#define FREQ_DEN 10000 +static inline int timer_intr_valid(void) +{ + static unsigned long long ticks, valid_ticks; + + if (ticks++ * FREQ_DEN >= valid_ticks * FREQ_NOM) { + /* + * We need no overflow checks, + * due baget unable to work 3000 years... + * At least without reboot... + */ + valid_ticks++; + return 1; + } + return 0; +} + +void static timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + if (timer_intr_valid()) { + sti(); + do_timer(regs); + } +} + +__initfunc(static void timer_enable(void)) +{ + unsigned char ss0cr0 = vic_inb(VIC_SS0CR0); + ss0cr0 &= ~VIC_SS0CR0_TIMER_FREQ_MASK; + ss0cr0 |= VIC_SS0CR0_TIMER_FREQ_1000HZ; + vic_outb(ss0cr0, VIC_SS0CR0); + + vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE| + VIC_INT_LOW|VIC_INT_ENABLE, VIC_LINT2); +} + +__initfunc(void time_init(void)) +{ + if (request_irq(BAGET_VIC_TIMER_IRQ, timer_interrupt, + SA_INTERRUPT|SA_STATIC_ALLOC, "timer", NULL) < 0) + printk("time_init: unable request irq for system timer\n"); + + timer_enable(); + + /* We don't call sti() here, because it is too early for baget */ +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_and_cli(flags); + *tv = xtime; + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_and_cli(flags); + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + restore_flags(flags); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.2.10/linux/arch/mips/baget/vacserial.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/vacserial.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,2943 @@ +/* $Id$ + * vacserial.c: VAC UART serial driver + * This code stealed and adopted from linux/drivers/char/serial.c + * See that for author info + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +#undef SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART + +#define CONFIG_SERIAL_SHARE_IRQ + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 2 /* Beget is not a super-computer (old=256) */ + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define SERIAL_INLINE + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) baget_printk("(%s):[%x] refc=%d, serc=%d, ttyc=%d-> %s\n", \ + kdevname(tty->device),(info->flags),serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +#define QUAD_UART_SPEED /* Useful for Baget */ + +/* + * End of serial driver configuration section. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SERIAL_CONSOLE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define BAGET_VAC_UART_IRQ 0x35 + +/* + * Implementation note: + * It was descovered by means of advanced electronic tools, + * if the driver works via TX_READY interrupts then VIC generates + * strange self-eliminating traps. Thus, the driver is rewritten to work + * via TX_EMPTY + */ + +/* VAC-specific check/debug switches */ + +#undef CHECK_REG_INDEX +#undef DEBUG_IO_PORT_A + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +static char *serial_name = "VAC Serial driver"; +static char *serial_version = "4.26"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +#endif + +static void autoconfig(struct serial_state * info); +static void change_speed(struct async_struct *info); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +/* + * Here we define the default xmit fifo size used for each type of + * UART + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, /* Must go first -- used as unasigned */ + { "VAC UART", 1, 0 } +}; +#define VAC_UART_TYPE 1 /* Just index in above array */ + +static struct serial_state rs_table[] = { +/* + * VAC has tricky layout for pair of his SIO registers, + * so we need special function to access ones. + * To identify port we use their TX offset + */ + { 0, 9600, VAC_UART_B_TX, BAGET_VAC_UART_IRQ, + STD_COM_FLAGS }, /* VAC UART B */ + { 0, 9600, VAC_UART_A_TX, BAGET_VAC_UART_IRQ, + STD_COM_FLAGS } /* VAC UART A */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* + To unify UART A/B access we will use following function + to compute register offsets by register index. + */ + +#define VAC_UART_MODE 0 +#define VAC_UART_TX 1 +#define VAC_UART_RX 2 +#define VAC_UART_INT_MASK 3 +#define VAC_UART_INT_STATUS 4 + +#define VAC_UART_REG_NR 5 + +static inline int uart_offset_map(unsigned long port, int reg_index) +{ + static const unsigned int ind_to_reg[VAC_UART_REG_NR][NR_PORTS] = { + { VAC_UART_B_MODE, VAC_UART_A_MODE }, + { VAC_UART_B_TX, VAC_UART_A_TX }, + { VAC_UART_B_RX, VAC_UART_A_RX }, + { VAC_UART_B_INT_MASK, VAC_UART_A_INT_MASK }, + { VAC_UART_B_INT_STATUS, VAC_UART_A_INT_STATUS } + }; +#ifdef CHECK_REG_INDEX + if (reg_index > VAC_UART_REG_NR) panic("vacserial: bad reg_index"); +#endif + return ind_to_reg[reg_index][port == VAC_UART_B_TX ? 0 : 1]; +} + +static inline unsigned int serial_inw(struct async_struct *info, int offset) +{ + int val = vac_inw(uart_offset_map(info->port,offset)); +#ifdef DEBUG_IO_PORT_A + if (info->port == VAC_UART_A_TX) + printk("UART_A_IN: reg = 0x%04x, val = 0x%04x\n", + uart_offset_map(info->port,offset), val); +#endif + return val; +} + +static inline unsigned int serial_inp(struct async_struct *info, int offset) +{ + return serial_inw(info, offset); +} + +static inline unsigned int serial_in(struct async_struct *info, int offset) +{ + return serial_inw(info, offset); +} + +static inline void serial_outw(struct async_struct *info,int offset, int value) +{ +#ifdef DEBUG_IO_PORT_A + if (info->port == VAC_UART_A_TX) + printk("UART_A_OUT: offset = 0x%04x, val = 0x%04x\n", + uart_offset_map(info->port,offset), value); +#endif + vac_outw(value, uart_offset_map(info->port,offset)); +} + +static inline void serial_outp(struct async_struct *info,int offset, int value) +{ + serial_outw(info,offset,value); +} + +static inline void serial_out(struct async_struct *info,int offset, int value) +{ + serial_outw(info,offset,value); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & VAC_UART_INT_TX_EMPTY) { + info->IER &= ~VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, info->IER); + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf + && !(info->IER & VAC_UART_INT_TX_EMPTY)) { + info->IER |= VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, info->IER); + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status) +{ + struct tty_struct *tty = info->tty; + unsigned short rx; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + rx = serial_inw(info, VAC_UART_RX); + ch = VAC_UART_RX_DATA_MASK & rx; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + baget_printk("DR%02x:%02x...", rx, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (VAC_UART_STATUS_RX_BREAK_CHANGE + | VAC_UART_STATUS_RX_ERR_PARITY + | VAC_UART_STATUS_RX_ERR_FRAME + | VAC_UART_STATUS_RX_ERR_OVERRUN)) { + /* + * For statistics only + */ + if (*status & VAC_UART_STATUS_RX_BREAK_CHANGE) { + *status &= ~(VAC_UART_STATUS_RX_ERR_FRAME + | VAC_UART_STATUS_RX_ERR_PARITY); + icount->brk++; + } else if (*status & VAC_UART_STATUS_RX_ERR_PARITY) + icount->parity++; + else if (*status & VAC_UART_STATUS_RX_ERR_FRAME) + icount->frame++; + if (*status & VAC_UART_STATUS_RX_ERR_OVERRUN) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (VAC_UART_STATUS_RX_BREAK_CHANGE)) { +#ifdef SERIAL_DEBUG_INTR + baget_printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & VAC_UART_STATUS_RX_ERR_PARITY) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & VAC_UART_STATUS_RX_ERR_FRAME) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & VAC_UART_STATUS_RX_ERR_OVERRUN) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = serial_inw(info, VAC_UART_INT_STATUS); + } while ((*status & VAC_UART_STATUS_RX_READY)); + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + if (info->x_char) { + serial_outw(info, VAC_UART_TX, + (((unsigned short)info->x_char)<<8)); + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~VAC_UART_INT_TX_EMPTY; + serial_outw(info, VAC_UART_INT_MASK, info->IER); + return; + } + count = info->xmit_fifo_size; + do { + serial_out(info, VAC_UART_TX, + (unsigned short)info->xmit_buf[info->xmit_tail++] \ + << 8); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + baget_printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit_cnt <= 0) { + info->IER &= ~VAC_UART_INT_TX_EMPTY; + serial_outw(info, VAC_UART_INT_MASK, info->IER); + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ +#if 0 /* VAC hasn't modem control */ + wake_up_interruptible(&info->open_wait); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); +#endif +} + +#ifdef CONFIG_SERIAL_SHARE_IRQ + + +/* + * Specific functions needed for VAC UART interrupt enter/leave + */ + +#define VAC_INT_CTRL_UART_ENABLE \ + (VAC_INT_CTRL_TIMER_PIO10|VAC_INT_CTRL_UART_B_PIO7|VAC_INT_CTRL_UART_A_PIO7) + +#define VAC_INT_CTRL_UART_DISABLE(info) \ + (VAC_INT_CTRL_TIMER_PIO10 | \ + ((info->port == VAC_UART_A_TX) ? \ + (VAC_INT_CTRL_UART_A_DISABLE|VAC_INT_CTRL_UART_B_PIO7) : \ + (VAC_INT_CTRL_UART_A_PIO7|VAC_INT_CTRL_UART_B_DISABLE))) + +/* + * Following two functions were proposed by Pavel Osipenko + * to make VAC/VIC behaviour more regular. + */ +static void intr_begin(struct async_struct* info) +{ + serial_outw(info, VAC_UART_INT_MASK, 0); +} + +static void intr_end(struct async_struct* info) +{ + vac_outw(VAC_INT_CTRL_UART_DISABLE(info), VAC_INT_CTRL); + vac_outw(VAC_INT_CTRL_UART_ENABLE, VAC_INT_CTRL); + + serial_outw(info, VAC_UART_INT_MASK, info->IER); +} + +/* + * This is the serial driver's generic interrupt routine + */ +static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct async_struct * info; + int pass_counter = 0; + struct async_struct *end_mark = 0; + +#ifdef SERIAL_DEBUG_INTR + baget_printk("rs_interrupt(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info) + return; + + do { + intr_begin(info); /* Mark we begin port handling */ + + if (!info->tty || + (serial_inw (info, VAC_UART_INT_STATUS) + & VAC_UART_STATUS_INTS) == 0) + { + if (!end_mark) + end_mark = info; + goto next; + } + end_mark = 0; + + info->last_active = jiffies; + + status = serial_inw(info, VAC_UART_INT_STATUS); +#ifdef SERIAL_DEBUG_INTR + baget_printk("status = %x...", status); +#endif + if (status & VAC_UART_STATUS_RX_READY) { + receive_chars(info, &status); + } + check_modem_status(info); + if (status & VAC_UART_STATUS_TX_EMPTY) + transmit_chars(info, 0); + + next: + intr_end(info); /* Mark this port handled */ + + info = info->next_port; + if (!info) { + info = IRQ_ports[irq]; + if (pass_counter++ > RS_ISR_PASS_LIMIT) { + break; /* Prevent infinite loops */ + } + continue; + } + } while (end_mark != info); +#ifdef SERIAL_DEBUG_INTR + baget_printk("end.\n"); +#endif + + +} +#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ + + +/* The original driver was simplified here: + two functions were joined to reduce code */ + +#define rs_interrupt_single rs_interrupt + + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + void (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + if (!state->port || !state->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + baget_printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + if (uart_config[info->state->type].flags & UART_STARTECH) { + /* Wake up UART */ + serial_outp(info, VAC_UART_MODE, 0); + serial_outp(info, VAC_UART_INT_MASK, 0); + } + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + + if (IRQ_ports[state->irq]) { +#ifdef CONFIG_SERIAL_SHARE_IRQ + free_irq(state->irq, NULL); + handler = rs_interrupt; +#else + retval = -EBUSY; + goto errout; +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + } else + handler = rs_interrupt_single; + + + retval = request_irq(state->irq, handler, IRQ_T(info), + "serial", NULL); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Clear the interrupt registers. + */ + /* (void) serial_inw(info, VAC_UART_INT_STATUS); */ /* (see above) */ + (void) serial_inw(info, VAC_UART_RX); + + /* + * Now, initialize the UART + */ + serial_outp(info, VAC_UART_MODE, VAC_UART_MODE_INITIAL); /*reset DLAB*/ + + /* + * Finally, enable interrupts + */ + info->IER = VAC_UART_INT_RX_BREAK_CHANGE | VAC_UART_INT_RX_ERRS | \ + VAC_UART_INT_RX_READY; + serial_outp(info, VAC_UART_INT_MASK, info->IER); /*enable interrupts*/ + + /* + * And clear the interrupt registers again for luck. + */ + (void)serial_inp(info, VAC_UART_INT_STATUS); + (void)serial_inp(info, VAC_UART_RX); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up serial timers... + */ + timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; + timer_active |= 1 << RS_TIMER; + + /* + * and set the speed of the serial port + */ + change_speed(info); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + baget_printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, NULL); + retval = request_irq(state->irq, rs_interrupt_single, + IRQ_T(info), "serial", NULL); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, NULL); + } + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->IER = 0; + serial_outp(info, VAC_UART_INT_MASK, 0x00); /* disable all intrs */ + + /* disable break condition */ + serial_out(info, VAC_UART_MODE, serial_inp(info, VAC_UART_MODE) & \ + ~VAC_UART_MODE_SEND_BREAK); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * When we set line mode, we call this function + * for Baget-specific adjustments. + */ + +static inline unsigned short vac_uart_mode_fixup (unsigned short cval) +{ +#ifdef QUAD_UART_SPEED + /* + * When we are using 4-x advantage in speed: + * + * Disadvantage : can't support 75, 150 bauds + * Advantage : can support 19200, 38400 bauds + */ + char speed = 7 & (cval >> 10); + cval &= ~(7 << 10); + cval |= VAC_UART_MODE_BAUD(speed-2); +#endif + + /* + * In general, we have Tx and Rx ON all time + * and use int mask flag for their disabling. + */ + cval |= VAC_UART_MODE_RX_ENABLE; + cval |= VAC_UART_MODE_TX_ENABLE; + cval |= VAC_UART_MODE_CHAR_RX_ENABLE; + cval |= VAC_UART_MODE_CHAR_TX_ENABLE; + + /* Low 4 bits are not used in UART */ + cval &= ~0xf; + + return cval; +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info) +{ + unsigned short port; + int quot = 0, baud_base, baud; + unsigned cflag, cval; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!(port = info->port)) + return; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS7: cval = 0x0; bits = 9; break; + case CS8: cval = VAC_UART_MODE_8BIT_CHAR; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + case CS5: + case CS6: + default: cval = 0x0; bits = 9; break; + } + cval &= ~VAC_UART_MODE_PARITY_ENABLE; + if (cflag & PARENB) { + cval |= VAC_UART_MODE_PARITY_ENABLE; + bits++; + } + if (cflag & PARODD) + cval |= VAC_UART_MODE_PARITY_ODD; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + baud_base = info->state->baud_base; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + /* If the quotient is ever zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + serial_out(info, VAC_UART_INT_MASK, info->IER); + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = VAC_UART_STATUS_RX_ERR_OVERRUN | \ + VAC_UART_STATUS_TX_EMPTY | VAC_UART_STATUS_RX_READY; + if (I_INPCK(info->tty)) + info->read_status_mask |= VAC_UART_STATUS_RX_ERR_FRAME | \ + VAC_UART_STATUS_RX_ERR_PARITY; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= VAC_UART_STATUS_RX_ERR_PARITY | \ + VAC_UART_STATUS_RX_ERR_FRAME; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= \ + VAC_UART_STATUS_RX_ERR_OVERRUN; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= VAC_UART_STATUS_RX_READY; + save_flags(flags); cli(); + + + switch (baud) { + default: + case 9600: + cval |= VAC_UART_MODE_BAUD(7); + break; + case 4800: + cval |= VAC_UART_MODE_BAUD(6); + break; + case 2400: + cval |= VAC_UART_MODE_BAUD(5); + break; + case 1200: + cval |= VAC_UART_MODE_BAUD(4); + break; + case 600: + cval |= VAC_UART_MODE_BAUD(3); + break; + case 300: + cval |= VAC_UART_MODE_BAUD(2); + break; +#ifndef QUAD_UART_SPEED + case 150: +#else + case 38400: +#endif + cval |= VAC_UART_MODE_BAUD(1); + break; +#ifndef QUAD_UART_SPEED + case 75: +#else + case 19200: +#endif + cval |= VAC_UART_MODE_BAUD(0); + break; + } + + /* Baget VAC need some adjustments for computed value */ + cval = vac_uart_mode_fixup(cval); + + serial_outp(info, VAC_UART_MODE, cval); + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, info->IER); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & VAC_UART_INT_TX_EMPTY)) { + info->IER |= VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, info->IER); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + info->IER |= VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, info->IER); + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + baget_printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + baget_printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = state->hub6; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int i,change_irq,change_port; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + change_irq = new_serial.irq != state->irq; + change_port = (new_serial.port != state->port) || + (new_serial.hub6 != state->hub6); + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != state->baud_base) || + (new_serial.type != state->type) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((state->flags & ~ASYNC_USR_MASK) | + (info->flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + new_serial.irq = irq_cannonicalize(new_serial.irq); + + if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) || + (new_serial.baud_base == 0) || (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { + return -EINVAL; + } + + if ((new_serial.type != state->type) || + (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = + uart_config[state->type].dfl_xmit_fifo_size; + + /* Make sure address is not already in use */ + if (new_serial.type) { + for (i = 0 ; i < NR_PORTS; i++) + if ((state != &rs_table[i]) && + (rs_table[i].port == new_serial.port) && + rs_table[i].type) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (state->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->type = new_serial.type; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->xmit_fifo_size = state->xmit_fifo_size = + new_serial.xmit_fifo_size; + + release_region(state->port,8); + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); + state->irq = new_serial.irq; + info->port = state->port = new_serial.port; + info->hub6 = state->hub6 = new_serial.hub6; + } + if (state->type != PORT_UNKNOWN) + request_region(state->port,8,"serial(set)"); + + +check_and_exit: + if (!state->port || !state->type) + return 0; + if (state->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + change_speed(info); + } + } else + retval = startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned short status; + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + status = serial_inw(info, VAC_UART_INT_STATUS); + restore_flags(flags); + result = ((status & VAC_UART_STATUS_TX_EMPTY) ? TIOCSER_TEMT : 0); + return put_user(result,value); +} + + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned int result; + + result = TIOCM_CAR | TIOCM_DSR; + return put_user(result,value); +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + + error = get_user(arg, value); + if (error) + return error; + switch (cmd) { + default: + return -EINVAL; + } + return 0; +} + +static int do_autoconfig(struct async_struct * info) +{ + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (info->state->count > 1) + return -EBUSY; + + shutdown(info); + + autoconfig(info->state); + + retval = startup(info); + if (retval) + return retval; + return 0; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!info->port) + return; + save_flags(flags); cli(); + if (break_state == -1) + serial_outp(info, VAC_UART_MODE, + serial_inp(info, VAC_UART_MODE) | \ + VAC_UART_MODE_SEND_BREAK); + else + serial_outp(info, VAC_UART_MODE, + serial_inp(info, VAC_UART_MODE) & \ + ~VAC_UART_MODE_SEND_BREAK); + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + return do_autoconfig(info); + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); cli(); + /* note the counters on entry */ + cprev = info->state->icount; + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && + cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && + cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && + (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && + (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && + (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && + (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = info->state->icount; + restore_flags(flags); + p_cuser = (struct serial_icounter_struct *) arg; + error = put_user(cnow.cts, &p_cuser->cts); + if (error) return error; + error = put_user(cnow.dsr, &p_cuser->dsr); + if (error) return error; + error = put_user(cnow.rng, &p_cuser->rng); + if (error) return error; + error = put_user(cnow.dcd, &p_cuser->dcd); + if (error) return error; + error = put_user(cnow.rx, &p_cuser->rx); + if (error) return error; + error = put_user(cnow.tx, &p_cuser->tx); + if (error) return error; + error = put_user(cnow.frame, &p_cuser->frame); + if (error) return error; + error = put_user(cnow.overrun, &p_cuser->overrun); + if (error) return error; + error = put_user(cnow.parity, &p_cuser->parity); + if (error) return error; + error = put_user(cnow.brk, &p_cuser->brk); + if (error) return error; + error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); + + if (error) return error; + return 0; + + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if ( (tty->termios->c_cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info); + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + baget_printk("rs_close ttys%d, count = %d\n", + info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + baget_printk("rs_close: bad serial port count; " + "tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + baget_printk("rs_close: bad serial port count for " + "ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~(VAC_UART_INT_RX_BREAK_CHANGE | VAC_UART_INT_RX_ERRS); + info->read_status_mask &= ~VAC_UART_STATUS_RX_READY; + if (info->flags & ASYNC_INITIALIZED) { + serial_outw(info, VAC_UART_INT_MASK, info->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->state->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + baget_printk("In rs_wait_until_sent(%d) check=%lu...", + timeout, char_time); + baget_printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_inp(info, VAC_UART_INT_STATUS)) & \ + VAC_UART_STATUS_TX_EMPTY)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + baget_printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + baget_printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + struct wait_queue wait = { current, NULL }; + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + baget_printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING)) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + baget_printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + baget_printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree_s(info, sizeof(struct async_struct)); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + if (serial_paranoia_check(info, tty->device, "rs_open")) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ + return -ENODEV; + } + +#ifdef SERIAL_DEBUG_OPEN + baget_printk("rs_open %s%d, count = %d\n", + tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ +#ifdef SERIAL_DEBUG_OPEN + baget_printk("rs_open returning after block_til_ready " + "with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info); + } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + baget_printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + int ret; + + ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + state->line, uart_config[state->type].name, + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + return ret; +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s with", serial_name, serial_version); +#ifdef CONFIG_SERIAL_SHARE_IRQ + printk(" SHARE_IRQ"); +#endif +#define SERIAL_OPT +#ifdef CONFIG_SERIAL_DETECT_IRQ + printk(" DETECT_IRQ"); +#endif +#ifdef SERIAL_OPT + printk(" enabled\n"); +#else + printk(" no serial options enabled\n"); +#endif +#undef SERIAL_OPT +} + + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ + +/* + * Functionality of this function is reduced: we already know we have a VAC, + * but still need to perform some important actions (see code :-). + */ +static void autoconfig(struct serial_state * state) +{ + struct async_struct *info, scr_info; + unsigned long flags; + + /* Setting up important parameters */ + state->type = VAC_UART_TYPE; + state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; + + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + + save_flags(flags); cli(); + + /* + Flush VAC input fifo */ + (void)serial_in(info, VAC_UART_RX); + (void)serial_in(info, VAC_UART_RX); + (void)serial_in(info, VAC_UART_RX); + (void)serial_in(info, VAC_UART_RX); + + /* Disable interrupts */ + serial_outp(info, VAC_UART_INT_MASK, 0); + + restore_flags(flags); +} + +int register_serial(struct serial_struct *req); +void unregister_serial(int line); + +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); + +/* + * Important function for VAC UART check and reanimation. + */ + +static void rs_timer(void) +{ + static unsigned long last_strobe = 0; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=1; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + if (info->next_port) { + do { + serial_out(info, VAC_UART_INT_MASK, 0); + info->IER |= VAC_UART_INT_TX_EMPTY; + serial_out(info, VAC_UART_INT_MASK, + info->IER); + info = info->next_port; + } while (info); + rs_interrupt(i, NULL, NULL); + } else +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME; + timer_active |= 1 << RS_TIMER; + + /* + * It looks this code for case we share IRQ with console... + */ + + if (IRQ_ports[0]) { + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + rs_interrupt(0, NULL, NULL); +#else + rs_interrupt_single(0, NULL, NULL); +#endif + restore_flags(flags); + + timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2; + } +} + +/* + * The serial driver boot-time initialization code! + */ +__initfunc(int rs_init(void)) +{ + int i; + struct serial_state * state; + extern void atomwide_serial_init (void); + extern void dualsp_serial_init (void); + +#ifdef CONFIG_ATOMWIDE_SERIAL + atomwide_serial_init (); +#endif +#ifdef CONFIG_DUALSP_SERIAL + dualsp_serial_init (); +#endif + + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; + } + + +/* + * It is not a good idea to share interrupts with console, + * but it looks we cannot avoid it. + */ +#if 0 + +#ifdef CONFIG_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "serial"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + if (check_region(state->port,8)) + continue; + if (state->flags & ASYNC_BOOT_AUTOCONF) + autoconfig(state); + } + + /* + * Detect the IRQ only once every port is initialised, + * because some 16450 do not reset to 0 the MCR register. + */ + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) + continue; + printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n", + state->line, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->port, state->irq, + uart_config[state->type].name); + } + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +int register_serial(struct serial_struct *req) +{ + int i; + unsigned long flags; + struct serial_state *state; + + save_flags(flags); + cli(); + for (i = 0; i < NR_PORTS; i++) { + if (rs_table[i].port == req->port) + break; + } + if (i == NR_PORTS) { + for (i = 0; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } + if (i == NR_PORTS) { + restore_flags(flags); + return -1; + } + state = &rs_table[i]; + if (rs_table[i].count) { + restore_flags(flags); + printk("Couldn't configure serial #%d (port=%d,irq=%d): " + "device already open\n", i, req->port, req->irq); + return -1; + } + state->irq = req->irq; + state->port = req->port; + state->flags = req->flags; + + autoconfig(state); + if (state->type == PORT_UNKNOWN) { + restore_flags(flags); + printk("register_serial(): autoconfig failed\n"); + return -1; + } + restore_flags(flags); + + printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n", + state->line, state->port, state->irq, + uart_config[state->type].name); + return state->line; +} + +void unregister_serial(int line) +{ + unsigned long flags; + struct serial_state *state = &rs_table[line]; + + save_flags(flags); + cli(); + if (state->info && state->info->tty) + tty_hangup(state->info->tty); + state->type = PORT_UNKNOWN; + printk(KERN_INFO "tty%02d unloaded\n", state->line); + restore_flags(flags); +} + +#ifdef MODULE +int init_module(void) +{ + return rs_init(); +} + +void cleanup_module(void) +{ + unsigned long flags; + int e1, e2; + int i; + + printk("Unloading %s: version %s\n", serial_name, serial_version); + save_flags(flags); + cli(); + + timer_active &= ~(1 << RS_TIMER); + timer_table[RS_TIMER].fn = NULL; + timer_table[RS_TIMER].expires = 0; + remove_bh(SERIAL_BH); + + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if (rs_table[i].type != PORT_UNKNOWN) + release_region(rs_table[i].port, 8); + } + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } +} +#endif /* MODULE */ + + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + +#define BOTH_EMPTY (VAC_UART_STATUS_TX_EMPTY | VAC_UART_STATUS_TX_EMPTY) + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + int lsr; + unsigned int tmout = 1000000; + + do { + lsr = serial_inp(info, VAC_UART_INT_STATUS); + if (--tmout == 0) break; + } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + struct serial_state *ser; + int ier; + unsigned i; + struct async_struct scr_info; /* serial_{in,out} because HUB6 */ + + ser = rs_table + co->index; + scr_info.magic = SERIAL_MAGIC; + scr_info.port = ser->port; + scr_info.flags = ser->flags; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_inp(&scr_info, VAC_UART_INT_MASK); + serial_outw(&scr_info, VAC_UART_INT_MASK, 0x00); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(&scr_info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_outp(&scr_info, VAC_UART_TX, (unsigned short)*s << 8); + if (*s == 10) { + wait_for_xmitr(&scr_info); + serial_outp(&scr_info, VAC_UART_TX, 13 << 8); + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(&scr_info); + serial_outp(&scr_info, VAC_UART_INT_MASK, ier); +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + struct serial_state *ser; + int ier; + int lsr; + int c; + struct async_struct scr_info; /* serial_{in,out} because HUB6 */ + + ser = rs_table + co->index; + scr_info.magic = SERIAL_MAGIC; + scr_info.port = ser->port; + scr_info.flags = ser->flags; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = serial_inp(&scr_info, VAC_UART_INT_MASK); + serial_outp(&scr_info, VAC_UART_INT_MASK, 0x00); + + do { + lsr = serial_inp(&scr_info, VAC_UART_INT_STATUS); + } while (!(lsr & VAC_UART_STATUS_RX_READY)); + c = serial_inp(&scr_info, VAC_UART_RX); + + /* + * Restore the interrupts + */ + serial_outp(&scr_info, VAC_UART_INT_MASK, ier); + + return c; +} + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +__initfunc(static int serial_console_setup(struct console *co, char *options)) +{ + struct serial_state *ser; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + struct async_struct scr_info; /* serial_{in,out} because HUB6 */ + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + ser = rs_table + co->index; + scr_info.magic = SERIAL_MAGIC; + scr_info.port = ser->port; + scr_info.flags = ser->flags; + + quot = ser->baud_base / baud; + cval = cflag & (CSIZE | CSTOPB); + + cval >>= 4; + + cval &= ~VAC_UART_MODE_PARITY_ENABLE; + if (cflag & PARENB) + cval |= VAC_UART_MODE_PARITY_ENABLE; + if (cflag & PARODD) + cval |= VAC_UART_MODE_PARITY_ODD; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + switch (baud) { + default: + case 9600: + cval |= VAC_UART_MODE_BAUD(7); + break; + case 4800: + cval |= VAC_UART_MODE_BAUD(6); + break; + case 2400: + cval |= VAC_UART_MODE_BAUD(5); + break; + case 1200: + cval |= VAC_UART_MODE_BAUD(4); + break; + case 600: + cval |= VAC_UART_MODE_BAUD(3); + break; + case 300: + cval |= VAC_UART_MODE_BAUD(2); + break; +#ifndef QUAD_UART_SPEED + case 150: +#else + case 38400: +#endif + cval |= VAC_UART_MODE_BAUD(1); + break; +#ifndef QUAD_UART_SPEED + case 75: +#else + case 19200: +#endif + cval |= VAC_UART_MODE_BAUD(0); + break; + } + + /* Baget VAC need some adjustments for computed value */ + cval = vac_uart_mode_fixup(cval); + + serial_outp(&scr_info, VAC_UART_MODE, cval); + serial_outp(&scr_info, VAC_UART_INT_MASK, 0); + + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} +#endif + +#ifdef CONFIG_REMOTE_DEBUG +#undef PRINT_DEBUG_PORT_INFO + +/* + * This is the interface to the remote debugger stub. + * I've put that here to be able to control the serial + * device more directly. + */ + +static int initialized = 0; + +static int rs_debug_init(struct async_struct *info) +{ + int quot; + + autoconfig(info); /* autoconfigure ttyS0, whatever that is */ + +#ifdef PRINT_DEBUG_PORT_INFO + baget_printk("kgdb debug interface:: tty%02d at 0x%04x", + info->line, info->port); + switch (info->type) { + case PORT_8250: + baget_printk(" is a 8250\n"); + break; + case PORT_16450: + baget_printk(" is a 16450\n"); + break; + case PORT_16550: + baget_printk(" is a 16550\n"); + break; + case PORT_16550A: + baget_printk(" is a 16550A\n"); + break; + case PORT_16650: + baget_printk(" is a 16650\n"); + break; + default: + baget_printk(" is of unknown type -- unusable\n"); + break; + } +#endif + + if (info->port == PORT_UNKNOWN) + return -1; + + /* + * Clear all interrupts + */ + + (void)serial_inp(info, VAC_UART_INT_STATUS); + (void)serial_inp(info, VAC_UART_RX); + + /* + * Now, initialize the UART + */ + serial_outp(info,VAC_UART_MODE,VAC_UART_MODE_INITIAL); /* reset DLAB */ + if (info->flags & ASYNC_FOURPORT) { + info->MCR = UART_MCR_DTR | UART_MCR_RTS; + info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1; + } else { + info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS; + } + + info->MCR = info->MCR_noint; /* no interrupts, please */ + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + quot = info->baud_base / 9600; /* baud rate is fixed to 9600 */ + /* FIXME: if rs_debug interface is needed, we need to set speed here */ + + return 0; +} + +int putDebugChar(char c) +{ + struct async_struct *info = rs_table; + + if (!initialized) { /* need to init device first */ + if (rs_debug_init(info) == 0) + initialized = 1; + else + return 0; + } + + while ((serial_inw(info, VAC_UART_INT_STATUS) & \ + VAC_UART_STATUS_TX_EMPTY) == 0) + ; + serial_out(info, VAC_UART_TX, (unsigned short)c << 8); + + return 1; +} + +char getDebugChar(void) +{ + struct async_struct *info = rs_table; + + if (!initialized) { /* need to init device first */ + if (rs_debug_init(info) == 0) + initialized = 1; + else + return 0; + } + while (!(serial_inw(info, VAC_UART_INT_STATUS) & \ + VAC_UART_STATUS_RX_READY)) + ; + + return(serial_inp(info, VAC_UART_RX)); +} + +#endif /* CONFIG_REMOTE_DEBUG */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/baget/wbflush.c linux/arch/mips/baget/wbflush.c --- v2.2.10/linux/arch/mips/baget/wbflush.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/baget/wbflush.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,24 @@ +/* + * Setup the right wbflush routine for Baget/MIPS. + * + * Copyright (C) 1999 Gleb Raiko & Vladimir Roganov + */ + +#include +#include + +void (*__wbflush) (void); + +static void wbflush_baget(void); + +__initfunc(void wbflush_setup(void)) +{ + __wbflush = wbflush_baget; +} + +/* + * Baget/MIPS doesnt need to write back the WB. + */ +static void wbflush_baget(void) +{ +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/boot/Makefile linux/arch/mips/boot/Makefile --- v2.2.10/linux/arch/mips/boot/Makefile Tue Aug 4 16:06:56 1998 +++ linux/arch/mips/boot/Makefile Mon Aug 9 12:04:38 1999 @@ -1,11 +1,10 @@ -# -# arch/mips/boot/Makefile +# $Id: Makefile,v 1.9 1999/04/07 18:45:23 harald Exp $ # # 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. # -# Copyright (C) 1995 by Ralf Baechle +# Copyright (C) 1995, 1998 by Ralf Baechle # .S.s: @@ -16,35 +15,37 @@ OBJS = milo.o a.out.o # +# Some DECstations need all possible sections of an ECOFF executable +# +ifdef CONFIG_DECSTATION + E2EFLAGS = -a +else + E2EFLAGS = +endif + +# # Drop some uninteresting sections in the kernel. # This is only relevant for ELF kernels but doesn't hurt a.out # drop-sections = .reginfo .mdebug strip-flags = $(addprefix --remove-section=,$(drop-sections)) -# -# Fake compressed boot -# -zImage: $(CONFIGURE) mkboot $(TOPDIR)/vmlinux - $(OBJCOPY) $(strip-flags) $(TOPDIR)/vmlinux zImage.tmp - ./mkboot zImage.tmp zImage - rm -f zImage.tmp +all: vmlinux.ecoff addinitrd -mkboot: mkboot.c +vmlinux.ecoff: $(CONFIGURE) elf2ecoff $(TOPDIR)/vmlinux + ./elf2ecoff $(TOPDIR)/vmlinux vmlinux.ecoff $(E2EFLAGS) + +elf2ecoff: elf2ecoff.c $(HOSTCC) -o $@ $^ -zdisk: zImage - if [ -f /etc/remote-mcopy ]; then \ - ssh rio mcopy -o - a:vmlinux +#include +#include +#include + +#include "ecoff.h" + +#define MIPS_PAGE_SIZE 4096 +#define MIPS_PAGE_MASK (MIPS_PAGE_SIZE-1) + +#define swab16(x) \ + ((unsigned short)( \ + (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ + (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) )) + +#define swab32(x) \ + ((unsigned int)( \ + (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) + +#define SWAB(a) (swab ? swab32(a) : (a)) + +void die (char *s) +{ + perror (s); + exit (1); +} + +int main (int argc, char *argv[]) +{ + int fd_vmlinux,fd_initrd,fd_outfile; + FILHDR efile; + AOUTHDR eaout; + SCNHDR esecs[3]; + struct stat st; + char buf[1024]; + unsigned long loadaddr; + unsigned long initrd_header[2]; + int i; + int swab = 0; + + if (argc != 4) { + printf ("Usage: %s \n",argv[0]); + exit (1); + } + + if ((fd_vmlinux = open (argv[1],O_RDWR)) < 0) + die ("open vmlinux"); + if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile) + die ("read file header"); + if (read (fd_vmlinux, &eaout, sizeof eaout) != sizeof eaout) + die ("read aout header"); + if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs) + die ("read section headers"); + + /* + * check whether the file is good for us + */ + /* TBD */ + + /* + * check, if we have to swab words + */ + if (ntohs(0xaa55) == 0xaa55) { + if (efile.f_magic == swab16(MIPSELMAGIC)) + swab = 1; + } else { + if (efile.f_magic == swab16(MIPSEBMAGIC)) + swab = 1; + } + + if ((fd_initrd = open (argv[2], O_RDONLY)) < 0) + die ("open initrd"); + if (fstat (fd_initrd, &st) < 0) + die ("fstat initrd"); + loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size) + + MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8; + if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size))) + loadaddr += MIPS_PAGE_SIZE; + initrd_header[0] = SWAB(0x494E5244); + initrd_header[1] = SWAB(st.st_size); + eaout.dsize = esecs[1].s_size = initrd_header[1] = SWAB(st.st_size+8); + eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr); + + if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC,0666)) < 0) + die ("open outfile"); + if (write (fd_outfile, &efile, sizeof efile) != sizeof efile) + die ("write file header"); + if (write (fd_outfile, &eaout, sizeof eaout) != sizeof eaout) + die ("write aout header"); + if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs) + die ("write section headers"); + while ((i = read (fd_vmlinux, buf, sizeof buf)) > 0) + if (write (fd_outfile, buf, i) != i) + die ("write vmlinux"); + if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header) + die ("write initrd header"); + while ((i = read (fd_initrd, buf, sizeof buf)) > 0) + if (write (fd_outfile, buf, i) != i) + die ("write initrd"); + close (fd_vmlinux); + close (fd_initrd); + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/boot/ecoff.h linux/arch/mips/boot/ecoff.h --- v2.2.10/linux/arch/mips/boot/ecoff.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/boot/ecoff.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,62 @@ +/* + * Some ECOFF definitions. + */ +typedef struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symbolic header */ + long f_nsyms; /* sizeof(symbolic hdr) */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +} FILHDR; +#define FILHSZ sizeof(FILHDR) + +#define OMAGIC 0407 +#define MIPSEBMAGIC 0x160 +#define MIPSELMAGIC 0x162 + +typedef struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address, aliased s_nlib */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to gp histogram */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of gp histogram entries */ + long s_flags; /* flags */ +} SCNHDR; +#define SCNHSZ sizeof(SCNHDR) +#define SCNROUND ((long)16) + +typedef struct aouthdr { + short magic; /* see above */ + short vstamp; /* version stamp */ + long tsize; /* text size in bytes, padded to DW bdry*/ + long dsize; /* initialized data " " */ + long bsize; /* uninitialized data " " */ + long entry; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ + long bss_start; /* base of bss used for this file */ + long gprmask; /* general purpose register mask */ + long cprmask[4]; /* co-processor register masks */ + long gp_value; /* the gp value used for this object */ +} AOUTHDR; +#define AOUTHSZ sizeof(AOUTHDR) + +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define SMAGIC 0411 +#define LIBMAGIC 0443 + +#define N_TXTOFF(f, a) \ + ((a).magic == ZMAGIC || (a).magic == LIBMAGIC ? 0 : \ + ((a).vstamp < 23 ? \ + ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + 7) & 0xfffffff8) : \ + ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + SCNROUND-1) & ~(SCNROUND-1)) ) ) +#define N_DATOFF(f, a) \ + N_TXTOFF(f, a) + (a).tsize; diff -u --recursive --new-file v2.2.10/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c --- v2.2.10/linux/arch/mips/boot/elf2ecoff.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/boot/elf2ecoff.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,639 @@ +/* + * Copyright (c) 1995 + * Ted Lemon (hereinafter referred to as the author) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* elf2ecoff.c + + This program converts an elf executable to an ECOFF executable. + No symbol table is retained. This is useful primarily in building + net-bootable kernels for machines (e.g., DECstation and Alpha) which + only support the ECOFF object file format. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ecoff.h" + +/* + * Some extra ELF definitions + * MIPS hosts may already have definitions, so we define it conditional. + */ +#ifndef PT_MIPS_REGINFO +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#endif + +/* -------------------------------------------------------------------- */ + +struct sect { + unsigned long vaddr; + unsigned long len; +}; + +int phcmp (); +char *saveRead (int file, off_t offset, off_t len, char *name); +int copy (int, int, off_t, off_t); +int translate_syms (int, int, off_t, off_t, off_t, off_t); +void convert_elf_hdr (Elf32_Ehdr *); +void convert_elf_phdrs (Elf32_Phdr *, int); +void convert_elf_shdrs (Elf32_Shdr *, int); +void convert_ecoff_filehdr(struct filehdr *); +void convert_ecoff_aouthdr(struct aouthdr *); +void convert_ecoff_esecs(struct scnhdr *, int); +extern int errno; +int *symTypeTable; +int must_convert_endian = 0; +int format_bigendian = 0; + +main (int argc, char **argv, char **envp) +{ + Elf32_Ehdr ex; + Elf32_Phdr *ph; + Elf32_Shdr *sh; + Elf32_Sym *symtab; + char *shstrtab; + int strtabix, symtabix; + int i, pad; + struct sect text, data, bss; + struct filehdr efh; + struct aouthdr eah; + struct scnhdr esecs [6]; + int infile, outfile; + unsigned long cur_vma = ULONG_MAX; + int addflag = 0; + int nosecs; + + text.len = data.len = bss.len = 0; + text.vaddr = data.vaddr = bss.vaddr = 0; + + /* Check args... */ + if (argc < 3 || argc > 4) + { + usage: + fprintf (stderr, + "usage: elf2aout [-a]\n"); + exit (1); + } + if (argc == 4) + { + if (strcmp (argv [3], "-a")) + goto usage; + addflag = 1; + } + + /* Try the input file... */ + if ((infile = open (argv [1], O_RDONLY)) < 0) + { + fprintf (stderr, "Can't open %s for read: %s\n", + argv [1], strerror (errno)); + exit (1); + } + + /* Read the header, which is at the beginning of the file... */ + i = read (infile, &ex, sizeof ex); + if (i != sizeof ex) + { + fprintf (stderr, "ex: %s: %s.\n", + argv [1], i ? strerror (errno) : "End of file reached"); + exit (1); + } + + if (ex.e_ident[EI_DATA] == ELFDATA2MSB) + format_bigendian = 1; + + if (ntohs (0xaa55) == 0xaa55) { + if (!format_bigendian) + must_convert_endian = 1; + } else { + if (format_bigendian) + must_convert_endian = 1; + } + if (must_convert_endian) + convert_elf_hdr (&ex); + + /* Read the program headers... */ + ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff, + ex.e_phnum * sizeof (Elf32_Phdr), "ph"); + if (must_convert_endian) + convert_elf_phdrs (ph, ex.e_phnum); + /* Read the section headers... */ + sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff, + ex.e_shnum * sizeof (Elf32_Shdr), "sh"); + if (must_convert_endian) + convert_elf_shdrs (sh, ex.e_shnum); + /* Read in the section string table. */ + shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset, + sh [ex.e_shstrndx].sh_size, "shstrtab"); + + /* Figure out if we can cram the program header into an ECOFF + header... Basically, we can't handle anything but loadable + segments, but we can ignore some kinds of segments. We can't + handle holes in the address space. Segments may be out of order, + so we sort them first. */ + + qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp); + + for (i = 0; i < ex.e_phnum; i++) + { + /* Section types we can ignore... */ + if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE || + ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO) + continue; + /* Section types we can't handle... */ + else if (ph [i].p_type != PT_LOAD) + { + fprintf (stderr, "Program header %d type %d can't be converted.\n"); + exit (1); + } + /* Writable (data) segment? */ + if (ph [i].p_flags & PF_W) + { + struct sect ndata, nbss; + + ndata.vaddr = ph [i].p_vaddr; + ndata.len = ph [i].p_filesz; + nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz; + nbss.len = ph [i].p_memsz - ph [i].p_filesz; + + combine (&data, &ndata, 0); + combine (&bss, &nbss, 1); + } + else + { + struct sect ntxt; + + ntxt.vaddr = ph [i].p_vaddr; + ntxt.len = ph [i].p_filesz; + + combine (&text, &ntxt, 0); + } + /* Remember the lowest segment start address. */ + if (ph [i].p_vaddr < cur_vma) + cur_vma = ph [i].p_vaddr; + } + + /* Sections must be in order to be converted... */ + if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || + text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) + { + fprintf (stderr, "Sections ordering prevents a.out conversion.\n"); + exit (1); + } + + /* If there's a data section but no text section, then the loader + combined everything into one section. That needs to be the + text section, so just make the data section zero length following + text. */ + if (data.len && !text.len) + { + text = data; + data.vaddr = text.vaddr + text.len; + data.len = 0; + } + + /* If there is a gap between text and data, we'll fill it when we copy + the data, so update the length of the text segment as represented in + a.out to reflect that, since a.out doesn't allow gaps in the program + address space. */ + if (text.vaddr + text.len < data.vaddr) + text.len = data.vaddr - text.vaddr; + + /* We now have enough information to cons up an a.out header... */ + eah.magic = OMAGIC; + eah.vstamp = 200; + eah.tsize = text.len; + eah.dsize = data.len; + eah.bsize = bss.len; + eah.entry = ex.e_entry; + eah.text_start = text.vaddr; + eah.data_start = data.vaddr; + eah.bss_start = bss.vaddr; + eah.gprmask = 0xf3fffffe; + memset (&eah.cprmask, '\0', sizeof eah.cprmask); + eah.gp_value = 0; /* unused. */ + + if (format_bigendian) + efh.f_magic = MIPSEBMAGIC; + else + efh.f_magic = MIPSELMAGIC; + if (addflag) + nosecs = 6; + else + nosecs = 3; + efh.f_nscns = nosecs; + efh.f_timdat = 0; /* bogus */ + efh.f_symptr = 0; + efh.f_nsyms = 0; + efh.f_opthdr = sizeof eah; + efh.f_flags = 0x100f; /* Stripped, not sharable. */ + + memset (esecs, 0, sizeof esecs); + strcpy (esecs [0].s_name, ".text"); + strcpy (esecs [1].s_name, ".data"); + strcpy (esecs [2].s_name, ".bss"); + if (addflag) { + strcpy (esecs [3].s_name, ".rdata"); + strcpy (esecs [4].s_name, ".sdata"); + strcpy (esecs [5].s_name, ".sbss"); + } + esecs [0].s_paddr = esecs [0].s_vaddr = eah.text_start; + esecs [1].s_paddr = esecs [1].s_vaddr = eah.data_start; + esecs [2].s_paddr = esecs [2].s_vaddr = eah.bss_start; + if (addflag) { + esecs [3].s_paddr = esecs [3].s_vaddr = 0; + esecs [4].s_paddr = esecs [4].s_vaddr = 0; + esecs [5].s_paddr = esecs [5].s_vaddr = 0; + } + esecs [0].s_size = eah.tsize; + esecs [1].s_size = eah.dsize; + esecs [2].s_size = eah.bsize; + if (addflag) { + esecs [3].s_size = 0; + esecs [4].s_size = 0; + esecs [5].s_size = 0; + } + esecs [0].s_scnptr = N_TXTOFF (efh, eah); + esecs [1].s_scnptr = N_DATOFF (efh, eah); +#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10 +#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1)) + esecs [2].s_scnptr = esecs [1].s_scnptr + + ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eah)); + if (addflag) { + esecs [3].s_scnptr = 0; + esecs [4].s_scnptr = 0; + esecs [5].s_scnptr = 0; + } + esecs [0].s_relptr = esecs [1].s_relptr + = esecs [2].s_relptr = 0; + esecs [0].s_lnnoptr = esecs [1].s_lnnoptr + = esecs [2].s_lnnoptr = 0; + esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0; + esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0; + if (addflag) { + esecs [3].s_relptr = esecs [4].s_relptr + = esecs [5].s_relptr = 0; + esecs [3].s_lnnoptr = esecs [4].s_lnnoptr + = esecs [5].s_lnnoptr = 0; + esecs [3].s_nreloc = esecs [4].s_nreloc = esecs [5].s_nreloc = 0; + esecs [3].s_nlnno = esecs [4].s_nlnno = esecs [5].s_nlnno = 0; + } + esecs [0].s_flags = 0x20; + esecs [1].s_flags = 0x40; + esecs [2].s_flags = 0x82; + if (addflag) { + esecs [3].s_flags = 0x100; + esecs [4].s_flags = 0x200; + esecs [5].s_flags = 0x400; + } + + /* Make the output file... */ + if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0) + { + fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno)); + exit (1); + } + + if (must_convert_endian) + convert_ecoff_filehdr (&efh); + /* Write the headers... */ + i = write (outfile, &efh, sizeof efh); + if (i != sizeof efh) + { + perror ("efh: write"); + exit (1); + + for (i = 0; i < nosecs; i++) + { + printf ("Section %d: %s phys %x size %x file offset %x\n", + i, esecs [i].s_name, esecs [i].s_paddr, + esecs [i].s_size, esecs [i].s_scnptr); + } + } + fprintf (stderr, "wrote %d byte file header.\n", i); + + if (must_convert_endian) + convert_ecoff_aouthdr (&eah); + i = write (outfile, &eah, sizeof eah); + if (i != sizeof eah) + { + perror ("eah: write"); + exit (1); + } + fprintf (stderr, "wrote %d byte a.out header.\n", i); + + if (must_convert_endian) + convert_ecoff_esecs (&esecs[0], nosecs); + i = write (outfile, &esecs, nosecs * sizeof(struct scnhdr)); + if (i != nosecs * sizeof(struct scnhdr)) + { + perror ("esecs: write"); + exit (1); + } + fprintf (stderr, "wrote %d bytes of section headers.\n", i); + + if (pad = ((sizeof efh + sizeof eah + nosecs * sizeof(struct scnhdr)) & 15)) + { + pad = 16 - pad; + i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); + if (i < 0) + { + perror ("ipad: write"); + exit (1); + } + fprintf (stderr, "wrote %d byte pad.\n", i); + } + + /* Copy the loadable sections. Zero-fill any gaps less than 64k; + complain about any zero-filling, and die if we're asked to zero-fill + more than 64k. */ + for (i = 0; i < ex.e_phnum; i++) + { + /* Unprocessable sections were handled above, so just verify that + the section can be loaded before copying. */ + if (ph [i].p_type == PT_LOAD && ph [i].p_filesz) + { + if (cur_vma != ph [i].p_vaddr) + { + unsigned long gap = ph [i].p_vaddr - cur_vma; + char obuf [1024]; + if (gap > 65536) + { + fprintf (stderr, "Intersegment gap (%d bytes) too large.\n", + gap); + exit (1); + } + fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap); + memset (obuf, 0, sizeof obuf); + while (gap) + { + int count = write (outfile, obuf, (gap > sizeof obuf + ? sizeof obuf : gap)); + if (count < 0) + { + fprintf (stderr, "Error writing gap: %s\n", + strerror (errno)); + exit (1); + } + gap -= count; + } + } +fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz); + copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz); + cur_vma = ph [i].p_vaddr + ph [i].p_filesz; + } + } + + /* + * Write a page of padding for boot PROMS that read entire pages. + * Without this, they may attempt to read past the end of the + * data section, incur an error, and refuse to boot. + */ + { + char obuf[4096]; + memset(obuf, 0, sizeof obuf); + if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) { + fprintf(stderr, "Error writing PROM padding: %s\n", + strerror(errno)); + exit(1); + } + } + + /* Looks like we won... */ + exit (0); +} + +copy (out, in, offset, size) + int out, in; + off_t offset, size; +{ + char ibuf [4096]; + int remaining, cur, count; + + /* Go the the start of the ELF symbol table... */ + if (lseek (in, offset, SEEK_SET) < 0) + { + perror ("copy: lseek"); + exit (1); + } + + remaining = size; + while (remaining) + { + cur = remaining; + if (cur > sizeof ibuf) + cur = sizeof ibuf; + remaining -= cur; + if ((count = read (in, ibuf, cur)) != cur) + { + fprintf (stderr, "copy: read: %s\n", + count ? strerror (errno) : "premature end of file"); + exit (1); + } + if ((count = write (out, ibuf, cur)) != cur) + { + perror ("copy: write"); + exit (1); + } + } +} + +/* Combine two segments, which must be contiguous. If pad is true, it's + okay for there to be padding between. */ +combine (base, new, pad) + struct sect *base, *new; + int pad; +{ + if (!base -> len) + *base = *new; + else if (new -> len) + { + if (base -> vaddr + base -> len != new -> vaddr) + { + if (pad) + base -> len = new -> vaddr - base -> vaddr; + else + { + fprintf (stderr, + "Non-contiguous data can't be converted.\n"); + exit (1); + } + } + base -> len += new -> len; + } +} + +phcmp (h1, h2) + Elf32_Phdr *h1, *h2; +{ + if (h1 -> p_vaddr > h2 -> p_vaddr) + return 1; + else if (h1 -> p_vaddr < h2 -> p_vaddr) + return -1; + else + return 0; +} + +char *saveRead (int file, off_t offset, off_t len, char *name) +{ + char *tmp; + int count; + off_t off; + if ((off = lseek (file, offset, SEEK_SET)) < 0) + { + fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno)); + exit (1); + } + if (!(tmp = (char *)malloc (len))) + { + fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len); + exit (1); + } + count = read (file, tmp, len); + if (count != len) + { + fprintf (stderr, "%s: read: %s.\n", + name, count ? strerror (errno) : "End of file reached"); + exit (1); + } + return tmp; +} + +#define swab16(x) \ + ((unsigned short)( \ + (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ + (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) )) + +#define swab32(x) \ + ((unsigned int)( \ + (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) + +void convert_elf_hdr (Elf32_Ehdr *e) +{ + e->e_type = swab16(e->e_type); + e->e_machine = swab16(e->e_machine); + e->e_version = swab32(e->e_version); + e->e_entry = swab32(e->e_entry); + e->e_phoff = swab32(e->e_phoff); + e->e_shoff = swab32(e->e_shoff); + e->e_flags = swab32(e->e_flags); + e->e_ehsize = swab16(e->e_ehsize); + e->e_phentsize = swab16(e->e_phentsize); + e->e_phnum = swab16(e->e_phnum); + e->e_shentsize = swab16(e->e_shentsize); + e->e_shnum = swab16(e->e_shnum); + e->e_shstrndx = swab16(e->e_shstrndx); +} + +void convert_elf_phdrs (Elf32_Phdr *p, int num) +{ + int i; + + for (i = 0; i < num; i++,p++) { + p->p_type = swab32(p->p_type); + p->p_offset = swab32(p->p_offset); + p->p_vaddr = swab32(p->p_vaddr); + p->p_paddr = swab32(p->p_paddr); + p->p_filesz = swab32(p->p_filesz); + p->p_memsz = swab32(p->p_memsz); + p->p_flags = swab32(p->p_flags); + p->p_align = swab32(p->p_align); + } + +} + +void convert_elf_shdrs (Elf32_Shdr *s, int num) +{ + int i; + + for (i = 0; i < num; i++,s++) { + s->sh_name = swab32(s->sh_name); + s->sh_type = swab32(s->sh_type); + s->sh_flags = swab32(s->sh_flags); + s->sh_addr = swab32(s->sh_addr); + s->sh_offset = swab32(s->sh_offset); + s->sh_size = swab32(s->sh_size); + s->sh_link = swab32(s->sh_link); + s->sh_info = swab32(s->sh_info); + s->sh_addralign = swab32(s->sh_addralign); + s->sh_entsize = swab32(s->sh_entsize); + } +} + +void convert_ecoff_filehdr(struct filehdr *f) +{ + f->f_magic = swab16(f->f_magic); + f->f_nscns = swab16(f->f_nscns); + f->f_timdat = swab32(f->f_timdat); + f->f_symptr = swab32(f->f_symptr); + f->f_nsyms = swab32(f->f_nsyms); + f->f_opthdr = swab16(f->f_opthdr); + f->f_flags = swab16(f->f_flags); +} + +void convert_ecoff_aouthdr(struct aouthdr *a) +{ + a->magic = swab16(a->magic); + a->vstamp = swab16(a->vstamp); + a->tsize = swab32(a->tsize); + a->dsize = swab32(a->dsize); + a->bsize = swab32(a->bsize); + a->entry = swab32(a->entry); + a->text_start = swab32(a->text_start); + a->data_start = swab32(a->data_start); + a->bss_start = swab32(a->bss_start); + a->gprmask = swab32(a->gprmask); + a->cprmask[0] = swab32(a->cprmask[0]); + a->cprmask[1] = swab32(a->cprmask[1]); + a->cprmask[2] = swab32(a->cprmask[2]); + a->cprmask[3] = swab32(a->cprmask[3]); + a->gp_value = swab32(a->gp_value); +} + +void convert_ecoff_esecs(struct scnhdr *s, int num) +{ + int i; + + for (i = 0; i < num; i++, s++) { + s->s_paddr = swab32(s->s_paddr); + s->s_vaddr = swab32(s->s_vaddr); + s->s_size = swab32(s->s_size); + s->s_scnptr = swab32(s->s_scnptr); + s->s_relptr = swab32(s->s_relptr); + s->s_lnnoptr = swab32(s->s_lnnoptr); + s->s_nreloc = swab16(s->s_nreloc); + s->s_nlnno = swab16(s->s_nlnno); + s->s_flags = swab32(s->s_flags); + } +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.2.10/linux/arch/mips/config.in Mon Feb 1 12:03:20 1999 +++ linux/arch/mips/config.in Mon Aug 9 12:04:38 1999 @@ -14,6 +14,8 @@ bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Support for Algorithmics P4032' CONFIG_ALGOR_P4032 + bool 'Support for BAGET MIPS series' CONFIG_BAGET_MIPS + bool 'Support for DECstations' CONFIG_DECSTATION fi bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 @@ -33,14 +35,13 @@ if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ "$CONFIG_OLIVETTI_M700" = "y" ]; then define_bool CONFIG_MIPS_JAZZ y - define_bool CONFIG_VIDEO_G364 y - define_bool CONFIG_VGA_CONSOLE y + define_bool CONFIG_FB y + define_bool CONFIG_FB_G364 y fi if [ "$CONFIG_ACER_PICA_61" = "y" ]; then define_bool CONFIG_MIPS_JAZZ y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then - define_bool CONFIG_VGA_CONSOLE y define_bool CONFIG_PCI y fi endmenu @@ -61,14 +62,23 @@ mainmenu_option next_comment comment 'General setup' + +if [ "$CONFIG_PCI" = "y" ]; then + bool ' PCI quirks' CONFIG_PCI_QUIRKS + if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE + fi + bool ' Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC +fi + if [ "$CONFIG_DECSTATION" = "y" ]; then - bool 'Compile the kernel into the ECOFF object format' CONFIG_ECOFF_KERNEL define_bool CONFIG_CPU_LITTLE_ENDIAN y else - define_bool CONFIG_ELF_KERNEL y bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN fi +define_bool CONFIG_ELF_KERNEL y + if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then define_bool CONFIG_BINFMT_IRIX y define_bool CONFIG_FORWARD_KEYBOARD y @@ -77,7 +87,6 @@ define_bool CONFIG_BINFMT_ELF y tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA fi @@ -86,7 +95,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -if [ "$CONFIG_SGI" != "y" ]; then +if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then tristate 'Parallel port support' CONFIG_PARPORT fi endmenu @@ -105,6 +114,16 @@ endmenu +if [ "$CONFIG_DECSTATION" = "y" ]; then + mainmenu_option next_comment + comment 'TURBOchannel support' + bool 'TURBOchannel support' CONFIG_TC +# if [ "$CONFIG_TC" = "y" ]; then +# tristate 'MAGMA Parallel port support' CONFIG_PARPORT +# fi + endmenu +fi + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then @@ -117,7 +136,7 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - if [ "$CONFIG_SGI" = "y" ]; then + if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then comment 'SCSI support type (disk, tape, CDrom)' dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI @@ -133,9 +152,15 @@ #mainmenu_option next_comment comment 'SCSI low-level drivers' - + if [ "$CONFIG_SGI" = "y" ]; then dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI else + if [ "$CONFIG_TC" = "y" ]; then + dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI + fi + dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI + fi + else source drivers/scsi/Config.in fi fi @@ -147,7 +172,7 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then - if [ "$CONFIG_SGI" != "y" ]; then + if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then source drivers/net/Config.in else tristate 'Dummy net driver support' CONFIG_DUMMY @@ -160,52 +185,113 @@ if [ ! "$CONFIG_PPP" = "n" ]; then comment 'CCP compressors for PPP are only built as modules.' fi + if [ "$CONFIG_SGI" = "y" ]; then bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ fi + if [ "$CONFIG_DECSTATION" = "y" ]; then + bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE + fi + if [ "$CONFIG_BAGET_MIPS" = "y" ]; then + tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE + tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM + fi + fi fi endmenu fi -if [ "$CONFIG_SGI" != "y" ]; then - source drivers/net/hamradio/Config.in +if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then + source drivers/net/hamradio/Config.in - mainmenu_option next_comment - comment 'ISDN subsystem' - tristate 'ISDN support' CONFIG_ISDN - if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in - fi - endmenu + mainmenu_option next_comment + comment 'ISDN subsystem' - mainmenu_option next_comment - comment 'Old CD-ROM drivers (not SCSI, not IDE)' + if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi + fi + endmenu - bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI - if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in - fi - endmenu + + mainmenu_option next_comment + comment comment 'Old CD-ROM drivers (not SCSI, not IDE)' + + bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI + if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in + fi + endmenu +fi + +if [ "$CONFIG_DECSTATION" != "y" ]; then + source drivers/char/Config.in +else + mainmenu_option next_comment + comment 'DECstation Character devices' + + bool 'Virtual terminal' CONFIG_VT + if [ "$CONFIG_VT" = "y" ]; then + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE + fi + tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL + if [ "$CONFIG_SGI" = "y" ]; then + bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE + fi + if [ "$CONFIG_SERIAL" = "y" ]; then + bool 'DZ11 Serial Support' CONFIG_DZ + if [ "$CONFIG_TC" = "y" ]; then + bool 'Z85C30 Serial Support' CONFIG_ZS + fi + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + fi + 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 + bool 'Keyboard Support' CONFIG_KEYBOARD + bool 'Mouse Support' CONFIG_MOUSE +# bool 'Enhanced Real Time Clock Support' CONFIG_RTC + endmenu fi -source drivers/char/Config.in +# source drivers/usb/Config.in source fs/Config.in -comment 'Console drivers' -source drivers/video/Config.in +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_SGI" = "y" ]; then + tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE + if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + else + if [ "$CONFIG_DECSTATION" != "y" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + fi + bool 'Support for frame buffer devices' CONFIG_FB + source drivers/video/Config.in + fi + endmenu +fi -mainmenu_option next_comment -comment 'Sound' +if [ "$CONFIG_DECSTATION" != "y" ]; then + mainmenu_option next_comment + comment 'Sound' -tristate 'Sound card support' CONFIG_SOUND -if [ "$CONFIG_SOUND" != "n" ]; then + tristate 'Sound card support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in + fi + endmenu fi -endmenu if [ "$CONFIG_SGI" = "y" ]; then - source drivers/sgi/char/Config.in + source drivers/sgi/Config.in fi mainmenu_option next_comment @@ -216,6 +302,8 @@ if [ "$CONFIG_MODULES" = "y" ]; then bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE fi -bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +if [ "$CONFIG_SERIAL" = "y" ]; then + bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/Makefile linux/arch/mips/dec/Makefile --- v2.2.10/linux/arch/mips/dec/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,30 @@ +# +# Makefile for the DECstation family specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: dec.o +O_TARGET := dec.o +O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o + +ifdef CONFIG_PROM_CONSOLE +O_OBJS += promcon.o +endif + +ifdef CONFIG_SERIAL +O_OBJS += serial.o +endif + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/boot/Makefile linux/arch/mips/dec/boot/Makefile --- v2.2.10/linux/arch/mips/dec/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/boot/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,26 @@ +# +# Makefile for the DECstation family specific parts of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +netboot: all + mipsel-linux-ld -N -G 0 -T ld.ecoff ../../boot/zImage \ + dec_boot.o ramdisk.img -o nbImage + +all: dec_boot.o + +O_TARGET := dec_boot.o +O_OBJS := decstation.o + +clean: + rm -f nbImage + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/boot/decstation.c linux/arch/mips/dec/boot/decstation.c --- v2.2.10/linux/arch/mips/dec/boot/decstation.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/boot/decstation.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,91 @@ +/* + * arch/mips/dec/decstation.c + */ +#include + +#define RELOC +#define INITRD +#define DEBUG_BOOT + +/* + * Magic number indicating REX PROM available on DECSTATION. + */ +#define REX_PROM_MAGIC 0x30464354 + +#define REX_PROM_CLEARCACHE 0x7c/4 +#define REX_PROM_PRINTF 0x30/4 + +#define VEC_RESET 0xBFC00000 /* Prom base address */ +#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */ +#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17) + +#define PARAM (k_start + 0x2000) + +#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) +#define INITRD_START (*(unsigned long *) (PARAM+0x218)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) + +extern int _ftext, _end; /* begin and end of kernel image */ +extern void *__rd_start, *__rd_end; /* begin and end of ramdisk image */ +extern void kernel_entry(int, char **, unsigned long, int *); + +void * memcpy(void * dest, const void *src, unsigned int count) +{ + unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src; + + count >>= 2; + while (count--) + *tmp++ = *s++; + + return dest; +} + +void dec_entry(int argc, char **argv, + unsigned long magic, int *prom_vec) +{ + void (*rex_clear_cache)(void); + int (*prom_printf)(char *, ...); + unsigned long k_start, len; + + /* + * The DS5100 leaves cpu with BEV enabled, clear it. + */ + asm( "lui\t$8,0x3000\n\t" + "mtc0\t$8,$12\n\t" + ".section\t.sdata\n\t" + ".section\t.sbss\n\t" + ".section\t.text" + : : : "$8"); + +#ifdef DEBUG_BOOT + if (magic == REX_PROM_MAGIC) { + prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF); + } else { + prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF; + } + prom_printf("Launching kernel...\n"); +#endif + + k_start = (unsigned long) (&kernel_entry) & 0xffff0000; + +#ifdef RELOC + /* + * Now copy kernel image to it's destination. + */ + len = ((unsigned long) (&_end) - k_start); + memcpy((void *)k_start, &_ftext, len); +#endif + + if (magic == REX_PROM_MAGIC) { + rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE); + rex_clear_cache(); + } + +#ifdef CONFIG_BLK_DEV_INITRD + LOADER_TYPE = 1; + INITRD_START = (long)&__rd_start; + INITRD_SIZE = (long)&__rd_end - (long)&__rd_start; +#endif + + kernel_entry(argc, argv, magic, prom_vec); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/boot/ld.ecoff linux/arch/mips/dec/boot/ld.ecoff --- v2.2.10/linux/arch/mips/dec/boot/ld.ecoff Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/boot/ld.ecoff Mon Aug 9 12:04:38 1999 @@ -0,0 +1,43 @@ +OUTPUT_FORMAT("ecoff-littlemips") +OUTPUT_ARCH(mips) +ENTRY(dec_entry) +SECTIONS +{ + . = 0x80200000; + + .text : + { + _ftext = .; + *(.text) + *(.fixup) + } + .rdata : + { + *(.rodata .rdata) + } + .data : + { + . = ALIGN(0x1000); + ramdisk.img (.data) + *(.data) + } + .sdata : + { + *(.sdata) + } + _gp = .; + .sbss : + { + *(.sbss) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + /DISCARD/ : { + *(.reginfo .mdebug .note) + } +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/int-handler.S linux/arch/mips/dec/int-handler.S --- v2.2.10/linux/arch/mips/dec/int-handler.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/int-handler.S Mon Aug 9 12:04:38 1999 @@ -0,0 +1,362 @@ +/* + * arch/mips/dec/int-handler.S + * + * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen + * + * Written by Ralf Baechle and Andreas Busse, modified for DECStation + * support by Paul Antoine and Harald Koerfgen. + * + * completly rewritten: + * Copyright (C) 1998 Harald Koerfgen + * + */ +#include +#include +#include +#include +#include + +#include + + + .text + .set noreorder +/* + * decstation_handle_int: Interrupt handler for DECStations + * + * FIXME: Detection of spurious interrupts not yet implemented! + * + * We follow the model in the Indy interrupt code by David Miller, where he + * says: a lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop + * and moving across all the pending IRQ bits in the cause + * register is _NOT_ the answer, the common case is one + * pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register + * IRQ mask, that would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs + * off, nothing in between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the DECStations look basically (barring + * software IRQs which we don't use at all) like... + * + * DS2100/3100's, aka kn01, aka Pmax: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 SCSI + * 3 Lance Ethernet + * 4 DZ11 serial + * 5 RTC + * 6 Memory Controller + * 7 FPU + * + * DS5000/200, aka kn02, aka 3max: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 TurboChannel + * 3 RTC + * 4 Reserved + * 5 Memory Controller + * 6 Reserved + * 7 FPU + * + * DS5000/1xx's, aka kn02ba, aka 3min: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 TurboChannel Slot 0 + * 3 TurboChannel Slot 1 + * 4 TurboChannel Slot 2 + * 5 TurboChannel Slot 3 (ASIC) + * 6 Halt button + * 7 FPU + * + * DS5000/2x's, aka kn02ca, aka maxine: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Periodic Interrupt (100usec) + * 3 RTC + * 4 I/O write timeout + * 5 TurboChannel (ASIC) + * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER) + * 7 FPU + * + * DS5000/2xx's, aka kn03, aka 3maxplus: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 System Board (ASIC) + * 3 RTC + * 4 Reserved + * 5 Memory + * 6 Halt Button + * 7 FPU + * + * We handle the IRQ according to _our_ priority. + * Priority is: + * + * Highest ---- RTC + * SCSI (if separate from TC) + * Ethernet (if separate from TC) + * Serial (if separate from TC) + * TurboChannel (if there is one!) + * Memory Controller (execept kmin) + * Lowest ---- Halt (if there is one!) + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + * + */ + .align 5 + NESTED(decstation_handle_int, PT_SIZE, ra) + .set noat + SAVE_ALL + CLI # TEST: interrupts should be off + .set at + .set noreorder + + /* + * Get pending Interrupts + */ + mfc0 t0,CP0_CAUSE # get pending interrupts + mfc0 t2,CP0_STATUS + la t1,cpu_mask_tbl + and t0,t2 # isolate allowed ones + + /* insert detection of spurious interrupts here */ + + /* + * Find irq with highest priority + */ +1: lw t2,(t1) + move t3,t0 + and t3,t2 + beq t3,zero,1b + addu t1,PTRSIZE # delay slot + + /* + * Do the low-level stuff + */ + lw a0,%lo(cpu_irq_nr-cpu_mask_tbl-PTRSIZE)(t1) + lw t0,%lo(cpu_ivec_tbl-cpu_mask_tbl-PTRSIZE)(t1) + bgez a0, handle_it # irq_nr >= 0? + # irq_nr < 0: a0 contains an address + nop + jr t0 + nop # delay slot + +/* + * Handle "IRQ Controller" Interrupts + * Masked Interrupts are still visible and have to be masked "by hand". + * %hi(KN02_CSR_ADDR) does not work so all addresses are hardcoded :-(. + */ + EXPORT(kn02_io_int) +kn02_io_int: lui t0,0xbff0 # get interrupt status and mask + lw t0,(t0) + la t1,asic_mask_tbl + move t3,t0 + sll t3,16 # shift interrupt status + b find_int + and t0,t3 # mask out allowed ones + + EXPORT(kn03_io_int) +kn03_io_int: lui t2,0xbf84 # upper part of IOASIC Address + lw t0,0x0110(t2) # get status: IOASIC isr + lw t3,0x0120(t2) # get mask: IOASIC isrm + la t1,asic_mask_tbl + b find_int + and t0,t3 # mask out allowed ones + + EXPORT(kn02ba_io_int) +kn02ba_io_int: lui t2,0xbc04 + lw t0,0x0110(t2) # IOASIC isr, works for maxine also + lw t3,0x0120(t2) # IOASIC isrm + la t1,asic_mask_tbl + and t0,t3 + + /* + * Find irq with highest priority + */ +find_int: lw t2,(t1) + move t3,t0 + and t3,t2 + beq zero,t3,find_int + addu t1,PTRSIZE # delay slot + + /* + * Do the low-level stuff + */ + lw a0,%lo(asic_irq_nr-asic_mask_tbl-PTRSIZE)(t1) + nop + +handle_it: jal do_IRQ + move a1,sp + j ret_from_irq + nop + + END(decstation_handle_int) +/* + * Interrupt routines common to all DECStations first. + */ + EXPORT(dec_intr_fpu) +dec_intr_fpu: PANIC("Unimplemented FPU interrupt handler") + +/* + * Halt interrupt + */ + EXPORT(intr_halt) +intr_halt: la k0,0xbc000000 + jr k0 + nop + +/* + * Generic unimplemented interrupt routines - ivec_tbl is initialised to + * point all interrupts here. The table is then filled in by machine-specific + * initialisation in dec_setup(). + */ + EXPORT(dec_intr_unimplemented) +dec_intr_unimplemented: + mfc0 a1,CP0_CAUSE # cheats way of printing an arg! + nop # to be sure... + PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%x"); + + EXPORT(asic_intr_unimplemented) +asic_intr_unimplemented: + move a1,t0 # cheats way of printing an arg! + PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%x"); + +/* + * FIXME: This interrupt vector table is experimental. It is initialised with + * *_intr_unimplemented and filled in with the addresses of + * machine-specific interrupt routines in dec_setup() Paul 10/5/97. + * + * The mask_tbls contain the interrupt masks which are used. It is + * initialised with all possible interrupt status bits set, so that + * unused Interrupts are catched. Harald + */ + .data + EXPORT(cpu_mask_tbl) +cpu_mask_tbl: + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 # these two are unlikely + .word 0x00000000 # to be used + .word 0x0000ff00 # End of list + + EXPORT(cpu_irq_nr) +cpu_irq_nr: + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 + .word 0x00000000 # these two are unlikely + .word 0x00000000 # to be used + .word 0x00ffffff # End of list + + EXPORT(cpu_ivec_tbl) +cpu_ivec_tbl: + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented + PTR dec_intr_unimplemented # these two are unlikely + PTR dec_intr_unimplemented # to be used + PTR dec_intr_unimplemented # EOL + + EXPORT(asic_mask_tbl) +asic_mask_tbl: + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0xffffffff # EOL + + EXPORT(asic_irq_nr) +asic_irq_nr: + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0xffffffff # EOL + + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/irq.c linux/arch/mips/dec/irq.c --- v2.2.10/linux/arch/mips/dec/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/irq.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,269 @@ +/* + * Code to handle DECstation IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994, 1995, 1996, 1997 Ralf Baechle + * + * $Id: irq.c,v 1.3 1999/04/11 17:06:16 harald Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +extern volatile unsigned int *isr; /* address of the interrupt status register */ +extern volatile unsigned int *imr; /* address of the interrupt mask register */ +extern decint_t dec_interrupt[NR_INTS]; + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; + +static inline void mask_irq(unsigned int irq_nr) +{ + unsigned int dummy; + + if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ + *imr &= ~dec_interrupt[irq_nr].iemask; + dummy = *imr; + dummy = *imr; + } else /* This is a cpu interrupt */ + set_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) & ~dec_interrupt[irq_nr].cpu_mask); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + unsigned int dummy; + + if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */ + *imr |= dec_interrupt[irq_nr].iemask; + dummy = *imr; + dummy = *imr; + } + set_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) | dec_interrupt[irq_nr].cpu_mask); +} + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + mask_irq(irq_nr); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_and_cli(flags); + unmask_irq(irq_nr); + restore_flags(flags); +} + +/* + * Pointers to the low-level handlers: first the general ones, then the + * fast ones, then the bad ones. + */ +extern void interrupt(void); + +static struct irqaction *irq_action[32] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + struct irqaction *action; + + for (i = 0; i < 32; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf + len, "%2d: %8d %c %s", + i, kstat.irqs[0][i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action = action->next; action; action = action->next) { + len += sprintf(buf + len, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + len += sprintf(buf + len, "\n"); + } + return len; +} + +atomic_t __mips_bh_counter; + +/* + * do_IRQ handles IRQ's that have been installed without the + * SA_INTERRUPT flag: it uses the full signal-handling return + * and runs with other interrupts enabled. All relatively slow + * IRQ's should use this format: notably the keyboard/timer + * routines. + */ +asmlinkage void do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + hardirq_enter(cpu); + kstat.irqs[cpu][irq]++; + + mask_irq(irq); + action = *(irq + irq_action); + if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + unmask_irq(irq); + __cli(); + } + hardirq_exit(cpu); + + /* unmasking and bottom half handling is done magically for us. */ +} + +/* + * Idea is to put all interrupts + * in a single table and differenciate them just by number. + */ +int setup_dec_irq(int irq, struct irqaction *new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_and_cli(flags); + *p = new; + + if (!shared) { + unmask_irq(irq); + } + restore_flags(flags); + return 0; +} + +int request_irq(unsigned int irq, + void (*handler) (int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id) +{ + int retval; + struct irqaction *action; + + if (irq >= 32) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_dec_irq(irq, action); + + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **p; + unsigned long flags; + + if (irq > 39) { + printk("Trying to free IRQ%d\n", irq); + return; + } + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_and_cli(flags); + *p = action->next; + if (!irq[irq_action]) + mask_irq(irq); + restore_flags(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n", irq); +} + +unsigned long probe_irq_on(void) +{ + /* TODO */ + return 0; +} + +int probe_irq_off(unsigned long irqs) +{ + /* TODO */ + return 0; +} + +__initfunc(void init_IRQ(void)) +{ + irq_setup(); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/Makefile linux/arch/mips/dec/prom/Makefile --- v2.2.10/linux/arch/mips/dec/prom/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/Makefile Mon Aug 9 12:04:38 1999 @@ -0,0 +1,29 @@ +# $Id: $ +# Makefile for the DECstation prom monitor library routines +# under Linux. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +OBJS = init.o memory.o cmdline.o identify.o locore.o + +all: rexlib.a + +rexlib.a: $(OBJS) + $(AR) rcs rexlib.a $(OBJS) + sync + +locore.o: locore.S + +dep: + $(CPP) -M *.c > .depend + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/cmdline.c linux/arch/mips/dec/prom/cmdline.c --- v2.2.10/linux/arch/mips/dec/prom/cmdline.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/cmdline.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,46 @@ +/* + * cmdline.c: read the command line passed to us by the PROM. + * + * Copyright (C) 1998 Harald Koerfgen + * + * $Id: $ + */ +#include +#include +#include + +#include + +#include "prom.h" + +#undef PROM_DEBUG + +#ifdef PROM_DEBUG +extern int (*prom_printf)(char *, ...); +#endif + +char arcs_cmdline[CL_SIZE]; + +__initfunc(void prom_init_cmdline(int argc, char **argv, unsigned long magic)) +{ + int start_arg, i; + + /* + * collect args and prepare cmd_line + */ + if (magic != REX_PROM_MAGIC) + start_arg = 1; + else + start_arg = 2; + for (i = start_arg; i < argc; i++) { + strcat(arcs_cmdline, argv[i]); + if (i < (argc - 1)) + strcat(arcs_cmdline, " "); + } + +#ifdef PROM_DEBUG + prom_printf("arcs_cmdline: %s\n", &(arcs_cmdline[0])); +#endif + +} + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/dectypes.h linux/arch/mips/dec/prom/dectypes.h --- v2.2.10/linux/arch/mips/dec/prom/dectypes.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/dectypes.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,14 @@ +#ifndef DECTYPES +#define DECTYPES + +#define DS2100_3100 1 /* DS2100/3100 Pmax */ +#define DS5000_200 2 /* DS5000/200 3max */ +#define DS5000_1XX 3 /* DS5000/1xx kmin */ +#define DS5000_2X0 4 /* DS5000/2x0 3max+ */ +#define DS5800 5 /* DS5800 Isis */ +#define DS5400 6 /* DS5400 MIPSfair */ +#define DS5000_XX 7 /* DS5000/xx maxine */ +#define DS5500 11 /* DS5500 MIPSfair-2 */ +#define DS5100 12 /* DS5100 MIPSmate */ + +#endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/identify.c linux/arch/mips/dec/prom/identify.c --- v2.2.10/linux/arch/mips/dec/prom/identify.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/identify.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,98 @@ +/* + * identify.c: machine identification code. + * + * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine + * + * $Id: $ + */ +#include +#include +#include + +#include + +#include "dectypes.h" +#include "prom.h" + +extern char *(*prom_getenv)(char *); +extern int (*prom_printf)(char *, ...); +extern int (*rex_getsysid)(void); + +extern unsigned long mips_machgroup; +extern unsigned long mips_machtype; + +__initfunc(void prom_identify_arch (unsigned int magic)) +{ + unsigned char dec_cpunum, dec_firmrev, dec_etc; + int dec_systype; + unsigned long dec_sysid; + + if (magic != REX_PROM_MAGIC) { + dec_sysid = simple_strtoul(prom_getenv("systype"), (char **)0, 0); + } else { + dec_sysid = rex_getsysid(); + if (dec_sysid == 0) { + prom_printf("Zero sysid returned from PROMs! Assuming PMAX-like machine.\n"); + dec_sysid = 1; + } + } + + dec_cpunum = (dec_sysid & 0xff000000) >> 24; + dec_systype = (dec_sysid & 0xff0000) >> 16; + dec_firmrev = (dec_sysid & 0xff00) >> 8; + dec_etc = dec_sysid & 0xff; + + /* We're obviously one of the DEC machines */ + mips_machgroup = MACH_GROUP_DEC; + + /* + * FIXME: This may not be an exhaustive list of DECStations/Servers! + * Put all model-specific initialisation calls here. + */ + prom_printf("This DECstation is a "); + + switch (dec_systype) { + case DS2100_3100: + prom_printf("DS2100/3100\n"); + mips_machtype = MACH_DS23100; + break; + case DS5100: /* DS5100 MIPSMATE */ + prom_printf("DS5100\n"); + mips_machtype = MACH_DS5100; + break; + case DS5000_200: /* DS5000 3max */ + prom_printf("DS5000/200\n"); + mips_machtype = MACH_DS5000_200; + break; + case DS5000_1XX: /* DS5000/100 3min */ + prom_printf("DS5000/1xx\n"); + mips_machtype = MACH_DS5000_1XX; + break; + case DS5000_2X0: /* DS5000/240 3max+ */ + prom_printf("DS5000/2x0\n"); + mips_machtype = MACH_DS5000_2X0; + break; + case DS5000_XX: /* Personal DS5000/2x */ + prom_printf("Personal DS5000/xx\n"); + mips_machtype = MACH_DS5000_XX; + break; + case DS5800: /* DS5800 Isis */ + prom_printf("DS5800\n"); + mips_machtype = MACH_DS5800; + break; + case DS5400: /* DS5400 MIPSfair */ + prom_printf("DS5400\n"); + mips_machtype = MACH_DS5400; + break; + case DS5500: /* DS5500 MIPSfair-2 */ + prom_printf("DS5500\n"); + mips_machtype = MACH_DS5500; + break; + default: + prom_printf("unknown, id is %x", dec_systype); + mips_machtype = MACH_DSUNKNOWN; + break; + } +} + + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/init.c linux/arch/mips/dec/prom/init.c --- v2.2.10/linux/arch/mips/dec/prom/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/init.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,95 @@ +/* + * init.c: PROM library initialisation code. + * + * Copyright (C) 1998 Harald Koerfgen + * + * $Id: $ + */ +#include +#include "prom.h" + +/* + * PROM Interface (whichprom.c) + */ +typedef struct { + int pagesize; + unsigned char bitmap[0]; +} memmap; + +int (*rex_bootinit)(void); +int (*rex_bootread)(void); +int (*rex_getbitmap)(memmap *); +unsigned long *(*rex_slot_address)(int); +void *(*rex_gettcinfo)(void); +int (*rex_getsysid)(void); +void (*rex_clear_cache)(void); + +int (*prom_getchar)(void); +char *(*prom_getenv)(char *); +int (*prom_printf)(char *, ...); + +int (*pmax_open)(char*, int); +int (*pmax_lseek)(int, long, int); +int (*pmax_read)(int, void *, int); +int (*pmax_close)(int); + +extern void prom_meminit(unsigned int); +extern void prom_identify_arch(unsigned int); +extern void prom_init_cmdline(int, char **, unsigned long); + +/* + * Detect which PROM's the DECSTATION has, and set the callback vectors + * appropriately. + */ +__initfunc(void which_prom(unsigned long magic, int *prom_vec)) +{ + /* + * No sign of the REX PROM's magic number means we assume a non-REX + * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx) + */ + if (magic == REX_PROM_MAGIC) + { + /* + * Set up prom abstraction structure with REX entry points. + */ + rex_bootinit = (int (*)(void)) *(prom_vec + REX_PROM_BOOTINIT); + rex_bootread = (int (*)(void)) *(prom_vec + REX_PROM_BOOTREAD); + rex_getbitmap = (int (*)(memmap *)) *(prom_vec + REX_PROM_GETBITMAP); + prom_getchar = (int (*)(void)) *(prom_vec + REX_PROM_GETCHAR); + prom_getenv = (char *(*)(char *)) *(prom_vec + REX_PROM_GETENV); + rex_getsysid = (int (*)(void)) *(prom_vec + REX_PROM_GETSYSID); + rex_gettcinfo = (void *(*)(void)) *(prom_vec + REX_PROM_GETTCINFO); + prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF); + rex_slot_address = (unsigned long *(*)(int)) *(prom_vec + REX_PROM_SLOTADDR); + rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE); + } + else + { + /* + * Set up prom abstraction structure with non-REX entry points. + */ + prom_getchar = (int (*)(void)) PMAX_PROM_GETCHAR; + prom_getenv = (char *(*)(char *)) PMAX_PROM_GETENV; + prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF; + pmax_open = (int (*)(char *, int)) PMAX_PROM_OPEN; + pmax_lseek = (int (*)(int, long, int)) PMAX_PROM_LSEEK; + pmax_read = (int (*)(int, void *, int)) PMAX_PROM_READ; + pmax_close = (int (*)(int)) PMAX_PROM_CLOSE; + } +} + +__initfunc(int prom_init(int argc, char **argv, + unsigned long magic, int *prom_vec)) +{ + /* Determine which PROM's we have (and therefore which machine we're on!) */ + which_prom(magic, prom_vec); + + if (magic == REX_PROM_MAGIC) + rex_clear_cache(); + + prom_meminit(magic); + prom_identify_arch(magic); + prom_init_cmdline(argc, argv, magic); + + return 0; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/locore.S linux/arch/mips/dec/prom/locore.S --- v2.2.10/linux/arch/mips/dec/prom/locore.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/locore.S Mon Aug 9 12:04:38 1999 @@ -0,0 +1,30 @@ +/* + * locore.S + */ +#include +#include +#include + + .text + +/* + * Simple general exception handling routine. This one is used for the + * Memory sizing routine for pmax machines. HK + */ + +NESTED(genexcept_early, 0, sp) + .set noat + .set noreorder + + mfc0 k0, CP0_STATUS + la k1, mem_err + + sw k0,0(k1) + + mfc0 k0, CP0_EPC + nop + addiu k0,4 # skip the causing instruction + jr k0 + rfe +END(genexcept_early) + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c --- v2.2.10/linux/arch/mips/dec/prom/memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/memory.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,103 @@ +/* + * memory.c: memory initialisation code. + * + * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine + * + * $Id: $ + */ +#include +#include +#include +#include "prom.h" + +typedef struct { + int pagesize; + unsigned char bitmap[0]; +} memmap; + +extern int (*rex_getbitmap)(memmap *); + +#undef PROM_DEBUG + +#ifdef PROM_DEBUG +extern int (*prom_printf)(char *, ...); +#endif + +extern unsigned long mips_memory_upper; + +volatile unsigned long mem_err = 0; /* So we know an error occured */ + +/* + * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen + * off the end of real memory. Only suitable for the 2100/3100's (PMAX). + */ + +#define CHUNK_SIZE 0x400000 + +__initfunc(unsigned long pmax_get_memory_size(void)) +{ + volatile unsigned char *memory_page, dummy; + char old_handler[0x80]; + extern char genexcept_early; + + /* Install exception handler */ + memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80); + memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80); + + /* read unmapped and uncached (KSEG1) + * DECstations have at least 4MB RAM + * Assume less than 480MB of RAM, as this is max for 5000/2xx + * FIXME this should be replaced by the first free page! + */ + for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE; + (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000)); + memory_page += CHUNK_SIZE) { + dummy = *memory_page; + } + memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80); + return (unsigned long)memory_page - KSEG1 - CHUNK_SIZE; +} + +/* + * Use the REX prom calls to get hold of the memory bitmap, and thence + * determine memory size. + */ +__initfunc(unsigned long rex_get_memory_size(void)) +{ + int i, bitmap_size; + unsigned long mem_size = 0; + memmap *bm; + + /* some free 64k */ + bm = (memmap *) 0x80028000; + + bitmap_size = rex_getbitmap(bm); + + for (i = 0; i < bitmap_size; i++) { + /* FIXME: very simplistically only add full sets of pages */ + if (bm->bitmap[i] == 0xff) + mem_size += (8 * bm->pagesize); + } + return (mem_size); +} + +__initfunc(void prom_meminit(unsigned int magic)) +{ + if (magic != REX_PROM_MAGIC) + mips_memory_upper = KSEG0 + pmax_get_memory_size(); + else + mips_memory_upper = KSEG0 + rex_get_memory_size(); + +#ifdef PROM_DEBUG + prom_printf("mips_memory_upper: 0x%08x\n", mips_memory_upper); +#endif +} + +/* Called from mem_init() to fixup the mem_map page settings. */ +__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end)) +{ +} + +void prom_free_prom_memory (void) +{ +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/prom/prom.h linux/arch/mips/dec/prom/prom.h --- v2.2.10/linux/arch/mips/dec/prom/prom.h Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/prom/prom.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,51 @@ +/* + * Miscellaneous definitions used to call the routines contained in the boot + * PROMs on various models of DECSTATION's. + * the rights to redistribute these changes. + */ + +#ifndef __ASM_DEC_PROM_H +#define __ASM_DEC_PROM_H + +/* + * PMAX/3MAX PROM entry points for DS2100/3100's and DS5000/2xx's. Many of + * these will work for MIPSen as well! + */ +#define VEC_RESET 0xBFC00000 /* Prom base address */ +#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */ + +#define PMAX_PROM_HALT PMAX_PROM_ENTRY(2) /* valid on MIPSen */ +#define PMAX_PROM_AUTOBOOT PMAX_PROM_ENTRY(5) /* valid on MIPSen */ +#define PMAX_PROM_OPEN PMAX_PROM_ENTRY(6) +#define PMAX_PROM_READ PMAX_PROM_ENTRY(7) +#define PMAX_PROM_CLOSE PMAX_PROM_ENTRY(10) +#define PMAX_PROM_LSEEK PMAX_PROM_ENTRY(11) +#define PMAX_PROM_GETCHAR PMAX_PROM_ENTRY(12) +#define PMAX_PROM_PUTCHAR PMAX_PROM_ENTRY(13) /* 12 on MIPSen */ +#define PMAX_PROM_GETS PMAX_PROM_ENTRY(15) +#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17) +#define PMAX_PROM_GETENV PMAX_PROM_ENTRY(33) /* valid on MIPSen */ + +/* + * Magic number indicating REX PROM available on DECSTATION. Found in + * register a2 on transfer of control to program from PROM. + */ +#define REX_PROM_MAGIC 0x30464354 + +/* + * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's, and + * DS5000/2x0. + */ +#define REX_PROM_GETBITMAP 0x84/4 /* get mem bitmap */ +#define REX_PROM_GETCHAR 0x24/4 /* getch() */ +#define REX_PROM_GETENV 0x64/4 /* get env. variable */ +#define REX_PROM_GETSYSID 0x80/4 /* get system id */ +#define REX_PROM_GETTCINFO 0xa4/4 +#define REX_PROM_PRINTF 0x30/4 /* printf() */ +#define REX_PROM_SLOTADDR 0x6c/4 /* slotaddr */ +#define REX_PROM_BOOTINIT 0x54/4 /* open() */ +#define REX_PROM_BOOTREAD 0x58/4 /* read() */ +#define REX_PROM_CLEARCACHE 0x7c/4 + +#endif /* __ASM_DEC_PROM_H */ + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/promcon.c linux/arch/mips/dec/promcon.c --- v2.2.10/linux/arch/mips/dec/promcon.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/promcon.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,71 @@ +/* + * Wrap-around code for a console using the + * DECstation PROM io-routines. + * + * Copyright (c) 1998 Harald Koerfgen + */ + +#include +#include +#include +#include +#include +#include + +extern int (*prom_getchar) (void); +extern int (*prom_printf) (char *,...); + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + unsigned i; + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} + +static int prom_console_wait_key(struct console *co) +{ + return prom_getchar(); +} + +__initfunc(static int prom_console_setup(struct console *co, char *options)) +{ + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console sercons = +{ + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +__initfunc(long prom_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/reset.c linux/arch/mips/dec/reset.c --- v2.2.10/linux/arch/mips/dec/reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/reset.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,25 @@ +/* + * $Id: reset.c,v 1.4 1999/04/11 17:06:16 harald Exp $ + * + * Reset a DECstation machine. + * + */ + +void (*back_to_prom)(void) = (void (*)(void))0xBFC00000; + +void dec_machine_restart(char *command) +{ + back_to_prom(); +} + +void dec_machine_halt(void) +{ + back_to_prom(); +} + +void dec_machine_power_off(void) +{ + /* DECstations don't have a software power switch */ + back_to_prom(); +} + diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/rtc-dec.c linux/arch/mips/dec/rtc-dec.c --- v2.2.10/linux/arch/mips/dec/rtc-dec.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/rtc-dec.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,36 @@ + +/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $ + + * 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. + * + * RTC routines for DECstation style attached Dallas chip. + * + * Copyright (C) 1998 by Ralf Baechle, Harald Koerfgen + */ +#include + +extern char *dec_rtc_base; + +static unsigned char dec_rtc_read_data(unsigned long addr) +{ + return (dec_rtc_base[addr * 4]); +} + +static void dec_rtc_write_data(unsigned char data, unsigned long addr) +{ + dec_rtc_base[addr * 4] = data; +} + +static int dec_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops dec_rtc_ops = +{ + &dec_rtc_read_data, + &dec_rtc_write_data, + &dec_rtc_bcd_mode +}; diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/serial.c linux/arch/mips/dec/serial.c --- v2.2.10/linux/arch/mips/dec/serial.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/serial.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,98 @@ +/* + * sercons.c + * choose the right serial device at boot time + * + * triemer 6-SEP-1998 + * sercons.c is designed to allow the three different kinds + * of serial devices under the decstation world to co-exist + * in the same kernel. The idea here is to abstract + * the pieces of the drivers that are common to this file + * so that they do not clash at compile time and runtime. + * + * HK 16-SEP-1998 v0.002 + * removed the PROM console as this is not a real serial + * device. Added support for PROM console in drivers/char/tty_io.c + * instead. Although it may work to enable more than one + * console device I strongly recommend to use only one. + */ + +#include +#include +#include + +#ifdef CONFIG_ZS +extern int zs_init(void); +#endif + +#ifdef CONFIG_DZ +extern int dz_init(void); +#endif + +#ifdef CONFIG_SERIAL_CONSOLE + +#ifdef CONFIG_ZS +extern long zs_serial_console_init(long, long); +#endif + +#ifdef CONFIG_DZ +extern long dz_serial_console_init(long, long); +#endif + +#endif + +/* rs_init - starts up the serial interface - + handle normal case of starting up the serial interface */ + +#ifdef CONFIG_SERIAL + +__initfunc(int rs_init(void)) +{ + +#if defined(CONFIG_ZS) && defined(CONFIG_DZ) + if (IOASIC) + return zs_init(); + else + return dz_init(); +#else + +#ifdef CONFIG_ZS + return zs_init(); +#endif + +#ifdef CONFIG_DZ + return dz_init(); +#endif + +#endif +} + +#endif + +#ifdef CONFIG_SERIAL_CONSOLE + +/* serial_console_init handles the special case of starting + * up the console on the serial port + */ +__initfunc(long serial_console_init(long kmem_start, long kmem_end)) +{ +#if defined(CONFIG_ZS) && defined(CONFIG_DZ) + if (IOASIC) + kmem_start = zs_serial_console_init(kmem_start, kmem_end); + else + kmem_start = dz_serial_console_init(kmem_start, kmem_end); +#else + +#ifdef CONFIG_ZS + kmem_start = zs_serial_console_init(kmem_start, kmem_end); +#endif + +#ifdef CONFIG_DZ + kmem_start = dz_serial_console_init(kmem_start, kmem_end); +#endif + +#endif + + return kmem_start; +} + +#endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/setup.c linux/arch/mips/dec/setup.c --- v2.2.10/linux/arch/mips/dec/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/setup.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,503 @@ +/* + * Setup the interrupt stuff. + * + * 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. + * + * Copyright (C) 1998 Harald Koerfgen + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern asmlinkage void decstation_handle_int(void); + +void dec_init_kn01(void); +void dec_init_kn230(void); +void dec_init_kn02(void); +void dec_init_kn02ba(void); +void dec_init_kn02ca(void); +void dec_init_kn03(void); + +char *dec_rtc_base = (char *) KN01_RTC_BASE; /* Assume DS2100/3100 initially */ + +decint_t dec_interrupt[NR_INTS]; + +/* + * Information regarding the IRQ Controller + * + * isr and imr are also hardcoded for different machines in int_handler.S + */ + +volatile unsigned int *isr = 0L; /* address of the interrupt status register */ +volatile unsigned int *imr = 0L; /* address of the interrupt mask register */ + +extern void dec_machine_restart(char *command); +extern void dec_machine_halt(void); +extern void dec_machine_power_off(void); + +extern void wbflush_setup(void); + +extern struct rtc_ops dec_rtc_ops; + +extern void intr_halt(void); + +extern int setup_dec_irq(int, struct irqaction *); + +void (*board_time_init) (struct irqaction * irq); + +__initfunc(static void dec_irq_setup(void)) +{ + switch (mips_machtype) { + case MACH_DS23100: + dec_init_kn01(); + break; + case MACH_DS5100: /* DS5100 MIPSMATE */ + dec_init_kn230(); + break; + case MACH_DS5000_200: /* DS5000 3max */ + dec_init_kn02(); + break; + case MACH_DS5000_1XX: /* DS5000/100 3min */ + dec_init_kn02ba(); + break; + case MACH_DS5000_2X0: /* DS5000/240 3max+ */ + dec_init_kn03(); + break; + case MACH_DS5000_XX: /* Personal DS5000/2x */ + dec_init_kn02ca(); + break; + case MACH_DS5800: /* DS5800 Isis */ + panic("Don't know how to set this up!"); + break; + case MACH_DS5400: /* DS5400 MIPSfair */ + panic("Don't know how to set this up!"); + break; + case MACH_DS5500: /* DS5500 MIPSfair-2 */ + panic("Don't know how to set this up!"); + break; + } + set_except_vector(0, decstation_handle_int); +} + +/* + * enable the periodic interrupts + */ +__initfunc(static void dec_time_init(struct irqaction *irq)) +{ + /* + * Here we go, enable periodic rtc interrupts. + */ + +#ifndef LOG_2_HZ +# define LOG_2_HZ 7 +#endif + + CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A); + CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B); + setup_dec_irq(CLOCK, irq); +} + +__initfunc(void decstation_setup(void)) +{ + irq_setup = dec_irq_setup; + board_time_init = dec_time_init; + + wbflush_setup(); + + _machine_restart = dec_machine_restart; + _machine_halt = dec_machine_halt; + _machine_power_off = dec_machine_power_off; + + rtc_ops = &dec_rtc_ops; +} + +/* + * Machine-specific initialisation for kn01, aka Pmax, aka DS2100, DS3100, + * and possibly also the DS5100. + */ +__initfunc(void dec_init_kn01(void)) +{ + /* + * Setup some memory addresses. + */ + dec_rtc_base = (char *) KN01_RTC_BASE; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ3; + dec_interrupt[CLOCK].iemask = 0; + cpu_mask_tbl[0] = IE_IRQ3; + cpu_irq_nr[0] = CLOCK; + + dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0; + dec_interrupt[SCSI_INT].iemask = 0; + cpu_mask_tbl[1] = IE_IRQ0; + cpu_irq_nr[1] = SCSI_INT; + + dec_interrupt[ETHER].cpu_mask = IE_IRQ1; + dec_interrupt[ETHER].iemask = 0; + cpu_mask_tbl[2] = IE_IRQ1; + cpu_irq_nr[2] = ETHER; + + dec_interrupt[SERIAL].cpu_mask = IE_IRQ2; + dec_interrupt[SERIAL].iemask = 0; + cpu_mask_tbl[3] = IE_IRQ2; + cpu_irq_nr[3] = SERIAL; + + dec_interrupt[MEMORY].cpu_mask = IE_IRQ4; + dec_interrupt[MEMORY].iemask = 0; + cpu_mask_tbl[4] = IE_IRQ4; + cpu_irq_nr[4] = MEMORY; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[5] = IE_IRQ5; + cpu_irq_nr[5] = FPU; +} /* dec_init_kn01 */ + +/* + * Machine-specific initialisation for kn230, aka MIPSmate, aka DS5100 + * + * There are a lot of experiments to do, this is definitely incomplete. + */ +__initfunc(void dec_init_kn230(void)) +{ + /* + * Setup some memory addresses. + */ + dec_rtc_base = (char *) KN01_RTC_BASE; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ2; + dec_interrupt[CLOCK].iemask = 0; + cpu_mask_tbl[0] = IE_IRQ2; + cpu_irq_nr[0] = CLOCK; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[5] = IE_IRQ5; + cpu_irq_nr[5] = FPU; +} /* dec_init_kn230 */ + +/* + * Machine-specific initialisation for kn02, aka 3max, aka DS5000/2xx. + */ +__initfunc(void dec_init_kn02(void)) +{ + /* + * Setup some memory addresses. FIXME: probably incomplete! + */ + dec_rtc_base = (char *) KN02_RTC_BASE; + isr = (volatile unsigned int *) KN02_CSR_ADDR; + imr = (volatile unsigned int *) KN02_CSR_ADDR; + + /* + * Setup IOASIC interrupt + */ + cpu_ivec_tbl[1] = kn02_io_int; + cpu_mask_tbl[1] = IE_IRQ0; + cpu_irq_nr[1] = -1; + *imr = *imr & 0xff00ff00; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ1; + dec_interrupt[CLOCK].iemask = 0; + cpu_mask_tbl[0] = IE_IRQ1; + cpu_irq_nr[0] = CLOCK; + + dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0; + dec_interrupt[SCSI_INT].iemask = KN02_SLOT5; + asic_mask_tbl[0] = KN02_SLOT5; + asic_irq_nr[0] = SCSI_INT; + + dec_interrupt[ETHER].cpu_mask = IE_IRQ0; + dec_interrupt[ETHER].iemask = KN02_SLOT6; + asic_mask_tbl[1] = KN02_SLOT6; + asic_irq_nr[1] = ETHER; + + dec_interrupt[SERIAL].cpu_mask = IE_IRQ0; + dec_interrupt[SERIAL].iemask = KN02_SLOT7; + asic_mask_tbl[2] = KN02_SLOT7; + asic_irq_nr[2] = SERIAL; + + dec_interrupt[TC0].cpu_mask = IE_IRQ0; + dec_interrupt[TC0].iemask = KN02_SLOT0; + asic_mask_tbl[3] = KN02_SLOT0; + asic_irq_nr[3] = TC0; + + dec_interrupt[TC1].cpu_mask = IE_IRQ0; + dec_interrupt[TC1].iemask = KN02_SLOT1; + asic_mask_tbl[4] = KN02_SLOT1; + asic_irq_nr[4] = TC1; + + dec_interrupt[TC2].cpu_mask = IE_IRQ0; + dec_interrupt[TC2].iemask = KN02_SLOT2; + asic_mask_tbl[5] = KN02_SLOT2; + asic_irq_nr[5] = TC2; + + dec_interrupt[MEMORY].cpu_mask = IE_IRQ3; + dec_interrupt[MEMORY].iemask = 0; + cpu_mask_tbl[2] = IE_IRQ3; + cpu_irq_nr[2] = MEMORY; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[3] = IE_IRQ5; + cpu_irq_nr[3] = FPU; + +} /* dec_init_kn02 */ + +/* + * Machine-specific initialisation for kn02ba, aka 3min, aka DS5000/1xx. + */ +__initfunc(void dec_init_kn02ba(void)) +{ + /* + * Setup some memory addresses. + */ + dec_rtc_base = (char *) KN02XA_RTC_BASE; + isr = (volatile unsigned int *) KN02XA_SIR_ADDR; + imr = (volatile unsigned int *) KN02XA_SIRM_ADDR; + + /* + * Setup IOASIC interrupt + */ + cpu_mask_tbl[0] = IE_IRQ3; + cpu_irq_nr[0] = -1; + cpu_ivec_tbl[0] = kn02ba_io_int; + *imr = 0; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ3; + dec_interrupt[CLOCK].iemask = KMIN_CLOCK; + asic_mask_tbl[0] = KMIN_CLOCK; + asic_irq_nr[0] = CLOCK; + + dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ3; + dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS; + asic_mask_tbl[1] = SCSI_DMA_INTS; + asic_irq_nr[1] = SCSI_DMA_INT; + + dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ3; + dec_interrupt[SCSI_INT].iemask = SCSI_CHIP; + asic_mask_tbl[2] = SCSI_CHIP; + asic_irq_nr[2] = SCSI_INT; + + dec_interrupt[ETHER].cpu_mask = IE_IRQ3; + dec_interrupt[ETHER].iemask = LANCE_INTS; + asic_mask_tbl[3] = LANCE_INTS; + asic_irq_nr[3] = ETHER; + + dec_interrupt[SERIAL].cpu_mask = IE_IRQ3; + dec_interrupt[SERIAL].iemask = SERIAL_INTS; + asic_mask_tbl[4] = SERIAL_INTS; + asic_irq_nr[4] = SERIAL; + + dec_interrupt[MEMORY].cpu_mask = IE_IRQ3; + dec_interrupt[MEMORY].iemask = KMIN_TIMEOUT; + asic_mask_tbl[5] = KMIN_TIMEOUT; + asic_irq_nr[5] = MEMORY; + + dec_interrupt[TC0].cpu_mask = IE_IRQ0; + dec_interrupt[TC0].iemask = 0; + cpu_mask_tbl[1] = IE_IRQ0; + cpu_irq_nr[1] = TC0; + + dec_interrupt[TC1].cpu_mask = IE_IRQ1; + dec_interrupt[TC1].iemask = 0; + cpu_mask_tbl[2] = IE_IRQ1; + cpu_irq_nr[2] = TC1; + + dec_interrupt[TC2].cpu_mask = IE_IRQ2; + dec_interrupt[TC2].iemask = 0; + cpu_mask_tbl[3] = IE_IRQ2; + cpu_irq_nr[3] = TC2; + + dec_interrupt[HALT].cpu_mask = IE_IRQ4; + dec_interrupt[HALT].iemask = 0; + cpu_mask_tbl[4] = IE_IRQ4; + cpu_irq_nr[4] = HALT; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[5] = IE_IRQ5; + cpu_irq_nr[5] = FPU; + +} /* dec_init_kn02ba */ + +/* + * Machine-specific initialisation for kn02ca, aka maxine, aka DS5000/2x. + */ +__initfunc(void dec_init_kn02ca(void)) +{ + /* + * Setup some memory addresses. FIXME: probably incomplete! + */ + dec_rtc_base = (char *) KN02XA_RTC_BASE; + isr = (volatile unsigned int *) KN02XA_SIR_ADDR; + imr = (volatile unsigned int *) KN02XA_SIRM_ADDR; + + /* + * Setup IOASIC interrupt + */ + cpu_ivec_tbl[1] = kn02ba_io_int; + cpu_irq_nr[1] = -1; + cpu_mask_tbl[1] = IE_IRQ3; + *imr = 0; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ1; + dec_interrupt[CLOCK].iemask = 0; + cpu_mask_tbl[0] = IE_IRQ1; + cpu_irq_nr[0] = CLOCK; + + dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ3; + dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS; + asic_mask_tbl[0] = SCSI_DMA_INTS; + asic_irq_nr[0] = SCSI_DMA_INT; + + dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ3; + dec_interrupt[SCSI_INT].iemask = SCSI_CHIP; + asic_mask_tbl[1] = SCSI_CHIP; + asic_irq_nr[1] = SCSI_INT; + + dec_interrupt[ETHER].cpu_mask = IE_IRQ3; + dec_interrupt[ETHER].iemask = LANCE_INTS; + asic_mask_tbl[2] = LANCE_INTS; + asic_irq_nr[2] = ETHER; + + dec_interrupt[SERIAL].cpu_mask = IE_IRQ3; + dec_interrupt[SERIAL].iemask = XINE_SERIAL_INTS; + asic_mask_tbl[3] = XINE_SERIAL_INTS; + asic_irq_nr[3] = SERIAL; + + dec_interrupt[TC0].cpu_mask = IE_IRQ3; + dec_interrupt[TC0].iemask = MAXINE_TC0; + asic_mask_tbl[4] = MAXINE_TC0; + asic_irq_nr[4] = TC0; + + dec_interrupt[TC1].cpu_mask = IE_IRQ3; + dec_interrupt[TC1].iemask = MAXINE_TC1; + asic_mask_tbl[5] = MAXINE_TC1; + asic_irq_nr[5] = TC1; + + dec_interrupt[MEMORY].cpu_mask = IE_IRQ2; + dec_interrupt[MEMORY].iemask = 0; + cpu_mask_tbl[2] = IE_IRQ2; + cpu_irq_nr[2] = MEMORY; + + dec_interrupt[HALT].cpu_mask = IE_IRQ4; + dec_interrupt[HALT].iemask = 0; + cpu_mask_tbl[3] = IE_IRQ4; + cpu_irq_nr[3] = HALT; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[4] = IE_IRQ5; + cpu_irq_nr[4] = FPU; + +} /* dec_init_kn02ca */ + +/* + * Machine-specific initialisation for kn03, aka 3max+, aka DS5000/240. + */ +__initfunc(void dec_init_kn03(void)) +{ + /* + * Setup some memory addresses. FIXME: probably incomplete! + */ + dec_rtc_base = (char *) KN03_RTC_BASE; + isr = (volatile unsigned int *) KN03_SIR_ADDR; + imr = (volatile unsigned int *) KN03_SIRM_ADDR; + + /* + * Setup IOASIC interrupt + */ + cpu_ivec_tbl[1] = kn03_io_int; + cpu_mask_tbl[1] = IE_IRQ0; + cpu_irq_nr[1] = -1; + *imr = 0; + + /* + * Setup interrupt structure + */ + dec_interrupt[CLOCK].cpu_mask = IE_IRQ1; + dec_interrupt[CLOCK].iemask = 0; + cpu_mask_tbl[0] = IE_IRQ1; + cpu_irq_nr[0] = CLOCK; + + dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ0; + dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS; + asic_mask_tbl[0] = SCSI_DMA_INTS; + asic_irq_nr[0] = SCSI_DMA_INT; + + dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0; + dec_interrupt[SCSI_INT].iemask = SCSI_CHIP; + asic_mask_tbl[1] = SCSI_CHIP; + asic_irq_nr[1] = SCSI_INT; + + dec_interrupt[ETHER].cpu_mask = IE_IRQ0; + dec_interrupt[ETHER].iemask = LANCE_INTS; + asic_mask_tbl[2] = LANCE_INTS; + asic_irq_nr[2] = ETHER; + + dec_interrupt[SERIAL].cpu_mask = IE_IRQ0; + dec_interrupt[SERIAL].iemask = SERIAL_INTS; + asic_mask_tbl[3] = SERIAL_INTS; + asic_irq_nr[3] = SERIAL; + + dec_interrupt[TC0].cpu_mask = IE_IRQ0; + dec_interrupt[TC0].iemask = KN03_TC0; + asic_mask_tbl[4] = KN03_TC0; + asic_irq_nr[4] = TC0; + + dec_interrupt[TC1].cpu_mask = IE_IRQ0; + dec_interrupt[TC1].iemask = KN03_TC1; + asic_mask_tbl[5] = KN03_TC1; + asic_irq_nr[5] = TC1; + + dec_interrupt[TC2].cpu_mask = IE_IRQ0; + dec_interrupt[TC2].iemask = KN03_TC2; + asic_mask_tbl[6] = KN03_TC2; + asic_irq_nr[6] = TC2; + + dec_interrupt[MEMORY].cpu_mask = IE_IRQ3; + dec_interrupt[MEMORY].iemask = 0; + cpu_mask_tbl[2] = IE_IRQ3; + cpu_irq_nr[2] = MEMORY; + + dec_interrupt[HALT].cpu_mask = IE_IRQ4; + dec_interrupt[HALT].iemask = 0; + cpu_mask_tbl[3] = IE_IRQ4; + cpu_irq_nr[3] = HALT; + + dec_interrupt[FPU].cpu_mask = IE_IRQ5; + dec_interrupt[FPU].iemask = 0; + cpu_mask_tbl[4] = IE_IRQ5; + cpu_irq_nr[4] = FPU; + +} /* dec_init_kn03 */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/time.c linux/arch/mips/dec/time.c --- v2.2.10/linux/arch/mips/dec/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/time.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,439 @@ + +/* + * linux/arch/mips/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the time handling details for PC-style clocks as + * found in some MIPS systems. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern volatile unsigned long lost_ticks; + +/* + * Change this if you have some constant time drift + */ +/* This is the value for the PC-style PICs. */ +/* #define USECS_PER_JIFFY (1000020/HZ) */ + +/* This is for machines which generate the exact clock. */ +#define USECS_PER_JIFFY (1000000/HZ) + +/* Cycle counter value at the previous timer interrupt.. */ + +static unsigned int timerhi = 0, timerlo = 0; + +/* + * On MIPS only R4000 and better have a cycle counter. + * + * FIXME: Does playing with the RP bit in c0_status interfere with this code? + */ +static unsigned long do_fast_gettimeoffset(void) +{ + u32 count; + unsigned long res, tmp; + + /* Last jiffy when do_fast_gettimeoffset() was called. */ + static unsigned long last_jiffies = 0; + unsigned long quotient; + + /* + * Cached "1/(clocks per usec)*2^32" value. + * It has to be recalculated once each jiffy. + */ + static unsigned long cached_quotient = 0; + + tmp = jiffies; + + quotient = cached_quotient; + + if (last_jiffies != tmp) { + last_jiffies = tmp; + __asm__(".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "lwu\t%0,%2\n\t" + "dsll32\t$1,%1,0\n\t" + "or\t$1,$1,%0\n\t" + "ddivu\t$0,$1,%3\n\t" + "mflo\t$1\n\t" + "dsll32\t%0,%4,0\n\t" + "nop\n\t" + "ddivu\t$0,%0,$1\n\t" + "mflo\t%0\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + : "=&r"(quotient) + : "r"(timerhi), + "m"(timerlo), + "r"(tmp), + "r"(USECS_PER_JIFFY) + : "$1"); + cached_quotient = quotient; + } + /* Get last timer tick in absolute kernel time */ + count = read_32bit_cp0_register(CP0_COUNT); + + /* .. relative to previous jiffy (32 bits is enough) */ + count -= timerlo; +//printk("count: %08lx, %08lx:%08lx\n", count, timerhi, timerlo); + + __asm__("multu\t%1,%2\n\t" + "mfhi\t%0" + : "=r"(res) + : "r"(count), + "r"(quotient)); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY - 1; + + return res; +} + +/* This function must be called with interrupts disabled + * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs + * + * However, the pc-audio speaker driver changes the divisor so that + * it gets interrupted rather more often - it loads 64 into the + * counter rather than 11932! This has an adverse impact on + * do_gettimeoffset() -- it stops working! What is also not + * good is that the interval that our timer function gets called + * is no longer 10.0002 ms, but 9.9767 ms. To get around this + * would require using a different timing source. Maybe someone + * could use the RTC - I know that this can interrupt at frequencies + * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix + * it so that at startup, the timer code in sched.c would select + * using either the RTC or the 8253 timer. The decision would be + * based on whether there was any other device around that needed + * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz, + * and then do some jiggery to have a version of do_timer that + * advanced the clock by 1/1024 s. Every time that reached over 1/100 + * of a second, then do all the old code. If the time was kept correct + * then do_gettimeoffset could just return 0 - there is no low order + * divider that can be accessed. + * + * Ideally, you would be able to use the RTC for the speaker driver, + * but it appears that the speaker driver really needs interrupt more + * often than every 120 us or so. + * + * Anyway, this needs more thought.... pjsg (1993-08-28) + * + * If you are really that interested, you should be reading + * comp.protocols.time.ntp! + */ + +#define TICK_SIZE tick + +static unsigned long do_slow_gettimeoffset(void) +{ + /* + * This is a kludge until I find a way for the + * DECstations without bus cycle counter. HK + */ + return 0; +} + +static unsigned long (*do_gettimeoffset) (void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_and_cli(flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. lost_ticks is + * nonzero if the timer bottom half hasnt executed yet. + */ + if (lost_ticks) + tv->tv_usec += USECS_PER_JIFFY; + + restore_flags(flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + sti(); +} + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + */ +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds, RTC_SECONDS); + CMOS_WRITE(real_minutes, RTC_MINUTES); + } else + retval = -1; + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void inline + timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile unsigned char dummy; + + dummy = CMOS_READ(RTC_REG_C); /* ACK RTC Interrupt */ + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 500000 - (tick >> 1) && + xtime.tv_usec < 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ +} + +static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int count; + + /* + * The cycle counter is only 32 bit which is good for about + * a minute at current count rates of upto 150MHz or so. + */ + count = read_32bit_cp0_register(CP0_COUNT); + timerhi += (count < timerlo); /* Wrap around */ + timerlo = count; + + timer_interrupt(irq, dev_id, regs); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long) (year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + + year * 365 - 719499 + ) * 24 + hour /* now have hours */ + ) * 60 + min /* now have minutes */ + ) * 60 + sec; /* finally seconds */ +} + +char cyclecounter_available; + +static inline void init_cycle_counter(void) +{ + switch (mips_cputype) { + case CPU_UNKNOWN: + case CPU_R2000: + case CPU_R3000: + case CPU_R3000A: + case CPU_R3041: + case CPU_R3051: + case CPU_R3052: + case CPU_R3081: + case CPU_R3081E: + case CPU_R6000: + case CPU_R6000A: + case CPU_R8000: /* Not shure about that one, play safe */ + cyclecounter_available = 0; + break; + case CPU_R4000PC: + case CPU_R4000SC: + case CPU_R4000MC: + case CPU_R4200: + case CPU_R4400PC: + case CPU_R4400SC: + case CPU_R4400MC: + case CPU_R4600: + case CPU_R10000: + case CPU_R4300: + case CPU_R4650: + case CPU_R4700: + case CPU_R5000: + case CPU_R5000A: + case CPU_R4640: + case CPU_NEVADA: + cyclecounter_available = 1; + break; + } +} + +struct irqaction irq0 = +{timer_interrupt, SA_INTERRUPT, 0, + "timer", NULL, NULL}; + + +void (*board_time_init) (struct irqaction * irq); + +__initfunc(void time_init(void)) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0; i < 1000000; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0; i < 1000000; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + /* + * The DECstation RTC is used as a TOY (Time Of Year). + * The PROM will reset the year to either '70, '71 or '72. + * This hack will only work until Dec 31 2001. + */ + year += 1927; + + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + + init_cycle_counter(); + + if (cyclecounter_available) { + write_32bit_cp0_register(CP0_COUNT, 0); + do_gettimeoffset = do_fast_gettimeoffset; + irq0.handler = r4k_timer_interrupt; + } + board_time_init(&irq0); +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/dec/wbflush.c linux/arch/mips/dec/wbflush.c --- v2.2.10/linux/arch/mips/dec/wbflush.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/dec/wbflush.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,104 @@ +/* + * Setup the right wbflush routine for the different DECstations. + * + * Created with information from: + * DECstation 3100 Desktop Workstation Functional Specification + * DECstation 5000/200 KN02 System Module Functional Specification + * mipsel-linux-objdump --disassemble vmunix | grep "wbflush" :-) + * + * 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. + * + * Copyright (C) 1998 Harald Koerfgen + */ + +#include +#include + +static void wbflush_kn01(void); +static void wbflush_kn210(void); +static void wbflush_kn02ba(void); +static void wbflush_kn03(void); + +void (*__wbflush) (void); + +__initfunc(void wbflush_setup(void)) +{ + switch (mips_machtype) { + case MACH_DS23100: + __wbflush = wbflush_kn01; + break; + case MACH_DS5100: /* DS5100 MIPSMATE */ + __wbflush = wbflush_kn210; + break; + case MACH_DS5000_200: /* DS5000 3max */ + __wbflush = wbflush_kn01; + break; + case MACH_DS5000_1XX: /* DS5000/100 3min */ + __wbflush = wbflush_kn02ba; + break; + case MACH_DS5000_2X0: /* DS5000/240 3max+ */ + __wbflush = wbflush_kn03; + break; + case MACH_DS5000_XX: /* Personal DS5000/2x */ + __wbflush = wbflush_kn02ba; + break; + } +} + +/* + * For the DS3100 and DS5000/200 the writeback buffer functions + * as part of Coprocessor 0. + */ +static void wbflush_kn01(void) +{ + asm(".set\tpush\n\t" + ".set\tnoreorder\n\t" + "1:\tbc0f\t1b\n\t" + "nop\n\t" + ".set\tpop"); +} + +/* + * For the DS5100 the writeback buffer seems to be a part of Coprocessor 3. + * But CP3 has to enabled first. + */ +static void wbflush_kn210(void) +{ + asm(".set\tpush\n\t" + ".set\tnoreorder\n\t" + "mfc0\t$2,$12\n\t" + "lui\t$3,0x8000\n\t" + "or\t$3,$2,$3\n\t" + "mtc0\t$3,$12\n\t" + "nop\n" + "1:\tbc3f\t1b\n\t" + "nop\n\t" + "mtc0\t$2,$12\n\t" + "nop\n\t" + ".set\tpop" + : : :"$2", "$3"); +} + +/* + * Looks like some magic with the System Interrupt Mask Register + * in the famous IOASIC for kmins and maxines. + */ +static void wbflush_kn02ba(void) +{ + asm(".set\tpush\n\t" + ".set\tnoreorder\n\t" + "lui\t$2,0xbc04\n\t" + "lw\t$3,0x120($2)\n\t" + "lw\t$3,0x120($2)\n\t" + ".set\tpop" + : : :"$2", "$3"); +} + +/* + * The DS500/2x0 doesnt need to write back the WB. + */ +static void wbflush_kn03(void) +{ +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.2.10/linux/arch/mips/defconfig Thu Feb 25 10:46:47 1999 +++ linux/arch/mips/defconfig Mon Aug 9 12:04:38 1999 @@ -10,13 +10,11 @@ # # Machine selection # -CONFIG_ACER_PICA_61=y +# CONFIG_ACER_PICA_61 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set # CONFIG_SGI is not set CONFIG_SNI_RM200_PCI=y -CONFIG_MIPS_JAZZ=y -CONFIG_VGA_CONSOLE=y CONFIG_PCI=y # @@ -34,8 +32,10 @@ # # General setup # -CONFIG_ELF_KERNEL=y +CONFIG_PCI_QUIRKS=y +CONFIG_PCI_OLD_PROC=y CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_ELF_KERNEL=y # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set @@ -49,21 +49,21 @@ # Loadable module support # CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set +CONFIG_MODVERSIONS=y CONFIG_KMOD=y # # Block devices # -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y +CONFIG_BLK_DEV_FD=m +CONFIG_BLK_DEV_IDE=m # # Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_BLK_DEV_IDECD=m # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set @@ -75,10 +75,10 @@ # # Additional Block Devices # -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_MD is not set -# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM=m # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set @@ -106,7 +106,6 @@ # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y # CONFIG_SKB_LARGE is not set # @@ -124,8 +123,8 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m # CONFIG_BLK_DEV_SR_VENDOR is not set # CONFIG_CHR_DEV_SG is not set @@ -134,12 +133,13 @@ # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers # # CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set @@ -147,20 +147,25 @@ # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_NCR53C8XX=y +# CONFIG_SCSI_SYM53C8XX is not set CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 -CONFIG_SCSI_NCR53C8XX_SYNC=5 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set @@ -169,13 +174,12 @@ # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set -CONFIG_JAZZ_ESP=y -CONFIG_JAZZ_ESP=y # # Network device support @@ -185,7 +189,6 @@ # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set CONFIG_NET_ETHERNET=y -CONFIG_MIPS_JAZZ_SONIC=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -211,6 +214,8 @@ # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set # CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set @@ -235,7 +240,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# comment # # CONFIG_CD_NO_IDESCSI is not set @@ -244,18 +249,26 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set +CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set # CONFIG_NVRAM is not set +CONFIG_RTC=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver @@ -265,69 +278,85 @@ # # Filesystems # -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -CONFIG_NFSD=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=m # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_MINIX_FS=m +# CONFIG_NTFS_FS is not set +CONFIG_HPFS_FS=m +CONFIG_PROC_FS=y +CONFIG_ROMFS_FS=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=m +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# # CONFIG_BSD_DISKLABEL is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_OSF_PARTITION is not set # CONFIG_SMD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_MAC_PARTITION is not set CONFIG_NLS=y # # Native Language Support # -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -CONFIG_NLS_CODEPAGE_850=y -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -CONFIG_NLS_ISO8859_1=y -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_KOI8_R is not set +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m # # Console drivers # +CONFIG_VGA_CONSOLE=y +# CONFIG_FB is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y # # Sound @@ -337,7 +366,7 @@ # # Kernel hacking # -CONFIG_CROSSCOMPILE=y +# CONFIG_CROSSCOMPILE is not set # CONFIG_MIPS_FPE_MODULE is not set # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/Makefile linux/arch/mips/jazz/Makefile --- v2.2.10/linux/arch/mips/jazz/Makefile Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/Makefile Mon Aug 9 12:04:38 1999 @@ -1,3 +1,4 @@ +# $Id: Makefile,v 1.6 1999/02/25 21:57:01 tsbogend Exp $ # # Makefile for the Jazz family specific parts of the kernel # @@ -13,7 +14,8 @@ all: jazz.o O_TARGET := jazz.o -O_OBJS := hw-access.o int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o +O_OBJS := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \ + kbd-jazz.o int-handler.o: int-handler.S diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/floppy-jazz.c linux/arch/mips/jazz/floppy-jazz.c --- v2.2.10/linux/arch/mips/jazz/floppy-jazz.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/floppy-jazz.c Mon Aug 9 12:04:38 1999 @@ -14,11 +14,11 @@ #include #include #include -#include #include #include #include #include +#include static unsigned char jazz_fd_inb(unsigned int port) { @@ -108,7 +108,7 @@ return order; } -extern inline unsigned long jazz_fd_dma_mem_alloc(unsigned long size) +static unsigned long jazz_fd_dma_mem_alloc(unsigned long size) { int order = __get_order(size); unsigned long mem; @@ -121,14 +121,14 @@ return mem; } -extern inline void jazz_fd_dma_mem_free(unsigned long addr, +static void jazz_fd_dma_mem_free(unsigned long addr, unsigned long size) { - vdma_free(PHYSADDR(addr)); + vdma_free(vdma_phys2log(PHYSADDR(addr))); free_pages(addr, __get_order(size)); } -static void std_fd_drive_type(unsigned long n) +static unsigned long jazz_fd_drive_type(unsigned long n) { /* XXX This is wrong for machines with ED 2.88mb disk drives like the Olivetti M700. Anyway, we should suck this from the ARC diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/hw-access.c linux/arch/mips/jazz/hw-access.c --- v2.2.10/linux/arch/mips/jazz/hw-access.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/hw-access.c Wed Dec 31 16:00:00 1969 @@ -1,90 +0,0 @@ -/* $Id: hw-access.c,v 1.11 1998/09/16 22:50:39 ralf Exp $ - * - * Low-level hardware access stuff for Jazz family machines. - * - * 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. - * - * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static volatile keyboard_hardware *jazz_kh = - (keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS; - -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ - -static unsigned char jazz_read_input(void) -{ - return jazz_kh->data; -} - -static void jazz_write_output(unsigned char val) -{ - int status; - - do { - status = jazz_kh->command; - } while (status & KBD_STAT_IBF); - jazz_kh->data = val; -} - -static void jazz_write_command(unsigned char val) -{ - int status; - - do { - status = jazz_kh->command; - } while (status & KBD_STAT_IBF); - jazz_kh->command = val; -} - -static unsigned char jazz_read_status(void) -{ - return jazz_kh->command; -} - -__initfunc(void jazz_keyboard_setup(void)) -{ - kbd_read_input = jazz_read_input; - kbd_write_output = jazz_write_output; - kbd_write_command = jazz_write_command; - kbd_read_status = jazz_read_status; - request_irq(JAZZ_KEYBOARD_IRQ, keyboard_interrupt, - 0, "keyboard", NULL); - request_region(0x60, 16, "keyboard"); - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) - | JAZZ_IE_KEYBOARD); -} - -int jazz_ps2_request_irq(void) -{ - extern void aux_interrupt(int, void *, struct pt_regs *); - int ret; - - ret = request_irq(JAZZ_MOUSE_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL); - if (!ret) - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | - JAZZ_IE_MOUSE); - return ret; -} - -void jazz_ps2_free_irq(void) -{ - r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, - r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | - JAZZ_IE_MOUSE); - free_irq(JAZZ_MOUSE_IRQ, NULL); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/int-handler.S linux/arch/mips/jazz/int-handler.S --- v2.2.10/linux/arch/mips/jazz/int-handler.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/int-handler.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: int-handler.S,v 1.6 1998/08/28 15:55:19 ralf Exp $ +/* $Id: int-handler.S,v 1.14 1999/05/01 22:40:34 ralf Exp $ * * 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 @@ -91,51 +91,8 @@ * whistles and bells and we're aware of the problem. */ ll_isa_irq: lw a0,JAZZ_EISA_IRQ_ACK - lui s0,%hi(JAZZ_PORT_BASE) - li s1,1 - andi t0,a0,8 # which pic? - bnez t0,ack_second - andi a0,7 # delay slot - /* - * Acknowledge first pic - */ - lb t2,%lo(JAZZ_PORT_BASE)+0x21(s0) - lui s4,%hi(cache_21) - lb t0,%lo(cache_21)(s4) - sllv s1,s1,a0 - or t0,s1 - sb t0,%lo(cache_21)(s4) - sb t0,%lo(JAZZ_PORT_BASE)+0x21(s0) - li t2,0x20 - sb t2,%lo(JAZZ_PORT_BASE)+0x20(s0) - /* - * Now call the real handler - */ - jal do_IRQ - move a1,sp - j ret_from_irq - nop - - .align 5 -ack_second: /* - * Acknowledge second pic - */ - lbu t2,%lo(JAZZ_PORT_BASE)+0xa1(s0) - lui s4,%hi(cache_A1) - lb t3,%lo(cache_A1)(s4) - sllv s1,s1,a0 - or t3,s1 - sb t3,%lo(cache_A1)(s4) - sb t3,%lo(JAZZ_PORT_BASE)+0xa1(s0) - li t3,0x20 - sb t3,%lo(JAZZ_PORT_BASE)+0xa0(s0) - sb t3,%lo(JAZZ_PORT_BASE)+0x20(s0) - /* - * Now call the real handler - */ - or a0, 8 - jal do_IRQ + jal i8259_do_irq move a1,sp j ret_from_irq @@ -144,7 +101,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 +109,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 @@ -163,7 +120,7 @@ ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read li s1,~IE_IRQ4 - li a0,0 + li a0, JAZZ_TIMER_IRQ jal do_IRQ move a1,sp @@ -228,14 +185,14 @@ b loc_call /* - * Floppy IRQ, remapped to level 6 + * Floppy IRQ */ loc_floppy: li s1,~JAZZ_IE_FLOPPY li a0,JAZZ_FLOPPY_IRQ b loc_call /* - * Sound? What sound hardware (whistle) ??? + * Sound IRQ */ loc_sound: PANIC("Unimplemented loc_sound handler") loc_video: PANIC("Unimplemented loc_video handler") diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c --- v2.2.10/linux/arch/mips/jazz/jazzdma.c Fri May 8 00:13:23 1998 +++ linux/arch/mips/jazz/jazzdma.c Mon Aug 9 12:04:38 1999 @@ -97,6 +97,7 @@ unsigned int frame; unsigned long laddr; int i; + unsigned long flags; /* check arguments */ @@ -113,6 +114,7 @@ return VDMA_ERROR; /* invalid physical address */ } + save_and_cli (flags); /* * Find free chunk */ @@ -123,8 +125,10 @@ while (entry[first].owner != VDMA_PAGE_EMPTY && first < VDMA_PGTBL_ENTRIES) first++; - if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */ + if (first+pages > VDMA_PGTBL_ENTRIES) { /* nothing free */ + restore_flags (flags); return VDMA_ERROR; + } last = first+1; while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages) @@ -170,6 +174,7 @@ printk("\n"); } + restore_flags(flags); return laddr; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/kbd-jazz.c linux/arch/mips/jazz/kbd-jazz.c --- v2.2.10/linux/arch/mips/jazz/kbd-jazz.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/jazz/kbd-jazz.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,102 @@ +/* $Id: kbd-jazz.c,v 1.1 1998/10/28 12:38:10 ralf Exp $ + * + * Low-level hardware access stuff for Jazz family machines. + * + * 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. + * + * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle + */ +#include +#include +#include +#include + +#define jazz_kh ((keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS) + +static void jazz_request_region(void) +{ + /* No I/O ports are being used on Jazz. */ +} + +static int jazz_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + int res; + + res = request_irq(JAZZ_KEYBOARD_IRQ, handler, 0, "keyboard", NULL); + if (res != 0) + return res; + + /* jazz_request_irq() should do this ... */ + r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, + r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) + | JAZZ_IE_KEYBOARD); + + return 0; +} + +static int jazz_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + int ret; + + ret = request_irq(JAZZ_MOUSE_IRQ, handler, 0, "PS/2 Mouse", NULL); + if (ret != 0) + return ret; + + r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, + r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | + JAZZ_IE_MOUSE); + return 0; +} + +static void jazz_aux_free_irq(void) +{ + r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, + r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) + | JAZZ_IE_MOUSE); + free_irq(JAZZ_MOUSE_IRQ, NULL); +} + +static unsigned char jazz_read_input(void) +{ + return jazz_kh->data; +} + +static void jazz_write_output(unsigned char val) +{ + int status; + + do { + status = jazz_kh->command; + } while (status & KBD_STAT_IBF); + jazz_kh->data = val; +} + +static void jazz_write_command(unsigned char val) +{ + int status; + + do { + status = jazz_kh->command; + } while (status & KBD_STAT_IBF); + jazz_kh->command = val; +} + +static unsigned char jazz_read_status(void) +{ + return jazz_kh->command; +} + +struct kbd_ops jazz_kbd_ops = { + jazz_request_region, + jazz_request_irq, + + jazz_aux_request_irq, + jazz_aux_free_irq, + + jazz_read_input, + jazz_write_output, + jazz_write_command, + jazz_read_status +}; diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/reset.c linux/arch/mips/jazz/reset.c --- v2.2.10/linux/arch/mips/jazz/reset.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/reset.c Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ * * Reset a Jazz machine. * - * $Id: reset.c,v 1.2 1998/03/04 12:17:40 ralf Exp $ + * $Id: reset.c,v 1.3 1998/03/04 08:29:10 ralf Exp $ */ #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/jazz/rtc-jazz.c linux/arch/mips/jazz/rtc-jazz.c --- v2.2.10/linux/arch/mips/jazz/rtc-jazz.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/rtc-jazz.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: rtc-jazz.c,v 1.3 1998/08/28 15:55:19 ralf Exp $ +/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c --- v2.2.10/linux/arch/mips/jazz/setup.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/jazz/setup.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.14 1998/09/16 22:50:40 ralf Exp $ +/* $Id: setup.c,v 1.20 1999/02/25 21:57:47 tsbogend Exp $ * * Setup pointers to hardware-dependent routines. * @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +39,6 @@ static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; extern asmlinkage void jazz_handle_int(void); -extern void jazz_keyboard_setup(void); extern void jazz_machine_restart(char *command); extern void jazz_machine_halt(void); @@ -48,6 +46,9 @@ extern struct ide_ops std_ide_ops; extern struct rtc_ops jazz_rtc_ops; +extern struct kbd_ops jazz_kbd_ops; +extern struct fd_ops *fd_ops; +extern struct fd_ops jazz_fd_ops; void (*board_time_init)(struct irqaction *irq); @@ -55,7 +56,7 @@ { /* set the clock to 100 Hz */ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); - setup_x86_irq(0, irq); + i8259_setup_irq(JAZZ_TIMER_IRQ, irq); } __initfunc(static void jazz_irq_setup(void)) @@ -75,43 +76,16 @@ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9); request_region(0x20, 0x20, "pic1"); request_region(0xa0, 0x20, "pic2"); - setup_x86_irq(2, &irq2); + i8259_setup_irq(2, &irq2); } __initfunc(void jazz_setup(void)) { - tag *atag; - - /* - * we just check if a tag_screen_info can be gathered - * in setup_arch(), if yes we don't proceed futher... - */ - atag = bi_TagFind(tag_screen_info); - if (!atag) { - /* - * If no, we try to find the tag_arc_displayinfo which is - * always created by Milo for an ARC box (for now Milo only - * works on ARC boxes :) -Stoned. - */ - atag = bi_TagFind(tag_arcdisplayinfo); - if (atag) { - screen_info.orig_x = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; - screen_info.orig_y = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; - screen_info.orig_video_cols = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; - screen_info.orig_video_lines = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; - } - } - add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M); add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M); irq_setup = jazz_irq_setup; - keyboard_setup = jazz_keyboard_setup; mips_io_port_base = JAZZ_PORT_BASE; isa_slot_offset = 0xe3000000; request_region(0x00,0x20,"dma1"); @@ -128,6 +102,8 @@ #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif - conswitchp = &fb_con; + conswitchp = &dummy_con; rtc_ops = &jazz_rtc_ops; + kbd_ops = &jazz_kbd_ops; + fd_ops = &jazz_fd_ops; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile --- v2.2.10/linux/arch/mips/kernel/Makefile Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/Makefile Mon Aug 9 12:04:38 1999 @@ -23,10 +23,14 @@ 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 + ifndef CONFIG_DECSTATION + ifndef CONFIG_BAGET_MIPS + O_OBJS += irq.o time.o + endif + endif endif # diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S --- v2.2.10/linux/arch/mips/kernel/entry.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/entry.S Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (C) 1994, 1995 by Ralf Baechle * - * $Id: entry.S,v 1.15 1998/10/14 20:26:26 ralf Exp $ + * $Id: entry.S,v 1.14 1999/04/12 19:13:21 harald Exp $ */ /* @@ -146,7 +146,7 @@ BUILD_HANDLER(adel,ade,ade,silent) /* #4 */ BUILD_HANDLER(ades,ade,ade,silent) /* #5 */ BUILD_HANDLER(ibe,ibe,cli,verbose) /* #6 */ - BUILD_HANDLER(dbe,dbe,cli,verbose) /* #7 */ + BUILD_HANDLER(dbe,dbe,cli,silent) /* #7 */ BUILD_HANDLER(bp,bp,sti,silent) /* #9 */ BUILD_HANDLER(ri,ri,sti,silent) /* #10 */ BUILD_HANDLER(cpu,cpu,sti,silent) /* #11 */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/fpe.c linux/arch/mips/kernel/fpe.c --- v2.2.10/linux/arch/mips/kernel/fpe.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/fpe.c Mon Aug 9 12:04:38 1999 @@ -6,7 +6,7 @@ * * Copyright (C) 1997 Ralf Baechle * - * $Id: fpe.c,v 1.2 1998/03/27 08:53:39 ralf Exp $ + * $Id: fpe.c,v 1.4 1999/05/01 22:40:35 ralf Exp $ */ #include #include @@ -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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/gdb-low.S linux/arch/mips/kernel/gdb-low.S --- v2.2.10/linux/arch/mips/kernel/gdb-low.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/gdb-low.S Mon Aug 9 12:04:38 1999 @@ -5,7 +5,7 @@ * * Copyright (C) 1995 Andreas Busse * - * $Id: gdb-low.S,v 1.3 1997/12/02 05:51:05 ralf Exp $ + * $Id: gdb-low.S,v 1.4 1997/12/01 17:57:26 ralf Exp $ */ #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/gdb-stub.c linux/arch/mips/kernel/gdb-stub.c --- v2.2.10/linux/arch/mips/kernel/gdb-stub.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/gdb-stub.c Mon Aug 9 12:04:38 1999 @@ -12,7 +12,7 @@ * * Copyright (C) 1995 Andreas Busse * - * $Id: gdb-stub.c,v 1.4 1997/12/02 05:51:06 ralf Exp $ + * $Id: gdb-stub.c,v 1.7 1999/06/12 18:39:28 ulfc Exp $ */ /* @@ -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 */ @@ -362,8 +362,6 @@ initialized = 1; restore_flags(flags); - - breakpoint(); } @@ -379,7 +377,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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S --- v2.2.10/linux/arch/mips/kernel/head.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/head.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.13 1998/10/14 20:26:27 ralf Exp $ +/* $Id: head.S,v 1.11 1998/10/18 13:27:12 tsbogend Exp $ * * arch/mips/kernel/head.S * @@ -408,15 +408,7 @@ probe_done: -#ifndef CONFIG_SGI - /* Get the memory upper limit the bootloader passed to us - * in a0 - */ - la t0, mips_memory_upper - nop - sw a0, (t0) -#else - /* On SGI's the firmware/bootloader passes argc/argp/envp + /* The firmware/bootloader passes argc/argp/envp * to us as arguments. But clear bss first because * the romvec and other important info is stored there * by prom_init(). @@ -431,6 +423,7 @@ jal prom_init /* prom_init(argc, argv, envp); */ nop +#ifdef CONFIG_SGI jal sgi_sysinit nop #endif @@ -440,18 +433,6 @@ nop #endif - /* Get the very one tags we need early in the boot process */ - nop - jal bi_EarlySnarf - nop -#ifndef CONFIG_SGI - /* Clear BSS first so that there are no surprises... */ - la t0, _edata - la t1, _end -1: addiu t0, 1 - bne t0, t1, 1b - sb zero, -1(t0) -#endif /* * Determine the mmu/cache attached to this machine, * then flush the tlb and caches. On the r4xx0 @@ -460,34 +441,10 @@ jal loadmmu nop - la t2, mips_cputype - lw t4, (t2) - li t1, CPU_R2000 - li t2, CPU_R3000 - li t3, CPU_R3000A - beq t4,t1,2f - nop - - beq t4,t2,2f - nop - - beq t4,t3,2f - nop - - jal wire_mappings_r4xx0 - nop - - b 9f - nop - -2: - jal wire_mappings_r3000 - nop - /* * Stack for kernel and init, current variable */ -9: la $28, init_task_union + la $28, init_task_union addiu t0, $28, KERNEL_STACK_SIZE-32 sw t0, kernelsp subu sp, t0, 4*SZREG @@ -509,81 +466,6 @@ nop # delay slot END(kernel_entry) -/* - * wire_mappings - used to map hardware registers, r4xx0 version. - */ -LEAF(wire_mappings_r4xx0) - mtc0 zero, CP0_WIRED - nop - nop - nop - j ra - nop - END(wire_mappings_r4xx0) - -/* - * R3000 version of wire_mappings. - */ -LEAF(wire_mappings_r3000) - /* - * Get base address of map0 table for the - * the board we're running on - */ - lw t1, mips_machtype - la t0, map0table - sll t1, PTRLOG # machtype used as index - addu t0, t1 - lw t0, (t0) # get base address - nop - /* Get number of wired TLB entries and - * loop over selected map0 table. - */ - lw t1, (t0) # number of wired TLB entries - move t2, zero # TLB entry counter - addiu t3, t1, 1 # wire one additional entry - beqz t1, 2f # null, exit - nop - - addiu t0, 8 -1: - lw t4, 24(t0) # PageMask - ld t5, 0(t0) # entryHi - ld t6, 8(t0) # entryLo0 - addiu t2, 1 # increment ctr - mtc0 t2, CP0_INDEX # set TLB entry - nop - mtc0 t5, CP0_ENTRYHI - nop - mtc0 t6, CP0_ENTRYLO0 - addiu t0, 32 - bne t1, t2, 1b # next TLB entry - tlbwi - - /* We use only 4k pages. Therefore the PageMask register - * is expected to be setup for 4k pages. - */ -2: - /* Now map the pagetables */ - mtc0 zero, CP0_INDEX - la t0, TLB_ROOT - mtc0 t0, CP0_ENTRYHI - nop - la t0, swapper_pg_dir - srl t0, 12 - ori t0, (0x00e0|0x0100) # uncachable, dirty, valid - mtc0 t0, CP0_ENTRYLO0 - nop - tlbwi # delayed - - /* Load the context register with zero. To see why, look - * at how the tlb refill code above works. - */ - mtc0 zero, CP0_CONTEXT - - jr ra - nop - END(wire_mappings_r3000) - /* CPU type probing code, called at Kernel entry. */ LEAF(cpu_probe) mfc0 t0, CP0_PRID @@ -707,115 +589,6 @@ b probe_done nop END(cpu_probe) - - .data -/* - * Build an entry for table of wired entries - */ -#define MAPDATA(q1,q2,q3,w1) \ - .quad q1; \ - .quad q2; \ - .quad q3; \ - .word w1; \ - .word 0 - -/* - * Initial mapping tables for supported Mips boards. - * First item is always the number of wired TLB entries, - * following by EntryHi/EntryLo pairs and page mask. - * Since everything must be quad-aligned (8) we insert - * some dummy zeros. - * - * Keep in mind that the PFN does not depend on the page size in the - * TLB page mask register. See milo's lib/dumptlb.c for how to decode - * and encode these entries. Don't see the same routine in the linux - * kernel distribution, since it is older and unreliable. - */ - -/* - * Address table of mapping tables for supported Mips boards. - * Add your own stuff here but don't forget to define your - * target system in bootinfo.h - */ - -map0table: PTR map0_dummy # machtype = unknown - PTR map0_rpc # Deskstation rPC44 - PTR map0_tyne # Deskstation Tyne - PTR map0_pica61 # Acer Pica-61 - PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030) - PTR map0_dummy - PTR map0_dummy # DEC Personal DECStation 5000/2x (for now) - PTR map0_sni_rm200_pci # SNI RM200 PCI - PTR map0_dummy # SGI INDY - -map0_dummy: .word 0 # 0 entries - - .align 3 -/* - * Deskstation rpc44 mappings. This machine has its EISA bus at physical - * address 0xa0000000 which we map for 32M, but that doesn't match EISA - * spec. Not sure what to do about this. Its I/O ports are memory mapped - * at physical memory location 0xb0000000. - */ -map0_rpc: .word 2 # no. of wired TLB entries - .word 0 # pad for alignment - -MAPDATA(0xffffffffe0000000, 0x02800017, 0x00000001, PM_16M) # ISA Memory space -MAPDATA(0xffffffffe2000000, 0x02c00017, 0x00000001, PM_64K) # ISA I/O Space - -/* - * Initial mappings for Deskstation Tyne boards. - */ -map0_tyne: .word 2 # no. of wired TLB entries - .word 0 # pad for alignment - -MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache -MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space - -/* - * Initial mapping for ACER PICA-61 boards. - * FIXME: These are rather preliminary since many drivers, such as serial, - * parallel, scsi and ethernet need some changes to distinguish between "local" - * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped - * to the same location as the bios maps it to. Console driver has been changed - * accordingly (new video type: VIDEO_TYPE_PICA_S3). - * FIXME: Remove or merge some of the mappings. - */ -map0_pica61: .word 7 # no. wired TLB entries - .word 0 # dummy - -MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # Local I/O space -MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # Interrupt source register -MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # Local video control -MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # Extended video control -MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # Local video memory (BIOS mapping) -MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # ISA I/O and ISA memory space (both 16M) -MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # PCR (???) - -/* - * Initial mapping for Mips Magnum 4000PC systems. - * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-) - * FIXME: Remove or merge some of the mappings. - */ -map0_magnum4000: - .word 8 # no. wired TLB entries - .word 0 # dummy - -MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, PM_256K) # 0 -MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # 1 local I/O -MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # 2 IRQ source -MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # 3 local video ctrl -MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # 4 ext. video ctrl -MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # 5 local video mem. -MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # 6 ISA I/O and mem. -MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # 7 PCR - -/* - * The RM200 doesn't need any wired entries. - */ -map0_sni_rm200_pci: - .word 0 # no. wired TLB entries - .word 0 # dummy /* * This buffer is reserved for the use of the cache error handler. diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c --- v2.2.10/linux/arch/mips/kernel/init_task.c Fri May 8 00:13:23 1998 +++ linux/arch/mips/kernel/init_task.c Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/ipc.c linux/arch/mips/kernel/ipc.c --- v2.2.10/linux/arch/mips/kernel/ipc.c Fri May 8 00:13:23 1998 +++ linux/arch/mips/kernel/ipc.c Mon Aug 9 12:04:38 1999 @@ -1,5 +1,4 @@ -/* - * linux/arch/mips/kernel/ipc.c +/* $Id$ * * This file contains various random system calls that * have a non-standard calling sequence on the Linux/MIPS @@ -22,106 +21,92 @@ * * This is really horribly ugly. FIXME: Get rid of this wrapper. */ -asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) { int version, ret; - lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); - goto out; + return sys_semop (first, (struct sembuf *)ptr, second); case SEMGET: - ret = sys_semget (first, second, third); - goto out; + return sys_semget (first, second, third); case SEMCTL: { union semun fourth; - ret = -EINVAL; if (!ptr) - goto out; - ret = -EFAULT; + return -EINVAL; if (get_user(fourth.__pad, (void **) ptr)) - goto out; - ret = sys_semctl (first, second, third, fourth); - goto out; + return -EFAULT; + return sys_semctl (first, second, third, fourth); } default: - ret = -EINVAL; - goto out; + return -EINVAL; } + if (call <= MSGCTL) switch (call) { case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); - goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - ret = -EINVAL; if (!ptr) - goto out; - ret = -EFAULT; - if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, - sizeof (tmp))) - goto out; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); - goto out; + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); } - case 1: default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); - goto out; + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); } case MSGGET: - ret = sys_msgget ((key_t) first, second); - goto out; + return sys_msgget ((key_t) first, second); case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); - goto out; + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } if (call <= SHMCTL) switch (call) { case SHMAT: switch (version) { - case 0: default: { + default: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char *) ptr, + second, &raddr); if (ret) - goto out; - ret = put_user (raddr, (ulong *) third); - goto out; + return ret; + return put_user (raddr, (ulong *) third); } case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; if (!segment_eq(get_fs(), get_ds())) - goto out; - ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); - goto out; + return -EINVAL; + return sys_shmat (first, (char *) ptr, + second, (ulong *) third); } case SHMDT: - ret = sys_shmdt ((char *)ptr); - goto out; + return sys_shmdt ((char *)ptr); case SHMGET: - ret = sys_shmget (first, second, third); - goto out; + return sys_shmget (first, second, third); case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); - goto out; + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } - else - ret = -EINVAL; -out: - unlock_kernel(); - return ret; + + return -EINVAL; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/irix5sys.h linux/arch/mips/kernel/irix5sys.h --- v2.2.10/linux/arch/mips/kernel/irix5sys.h Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/irix5sys.h Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: irix5sys.h,v 1.2 1998/08/17 10:16:25 ralf Exp $ +/* $Id: irix5sys.h,v 1.2 1998/08/25 09:14:39 ralf Exp $ * * irix5sys.h: 32-bit IRIX5 ABI system call table. * diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.2.10/linux/arch/mips/kernel/irixelf.c Wed Nov 11 11:49:59 1998 +++ linux/arch/mips/kernel/irixelf.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: irixelf.c,v 1.17.2.2 1999/06/22 20:53:26 ralf Exp $ + * * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. * @@ -309,7 +310,7 @@ return 0xffffffff; } - file = current->files->fd[elf_exec_fileno]; + file = fget(elf_exec_fileno); eppnt = elf_phdata; for(i=0; ie_phnum; i++, eppnt++) { @@ -367,6 +368,7 @@ } /* Now use mmap to map the library into memory. */ + fput(file); sys_close(elf_exec_fileno); if(error < 0 && error > -1024) { #ifdef DEBUG_ELF @@ -617,8 +619,9 @@ unsigned int load_addr, elf_bss, elf_brk; unsigned int elf_entry, interp_load_addr = 0; unsigned int start_code, end_code, end_data, elf_stack; - int elf_exec_fileno, retval, has_interp, has_ephdr, i; + int elf_exec_fileno, retval, has_interp, has_ephdr, size, i; char *elf_interpreter; + struct file *file; mm_segment_t old_fs; load_addr = 0; @@ -634,17 +637,15 @@ #endif /* Now read in all of the header information */ - elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * - elf_ex.e_phnum, GFP_KERNEL); + size = elf_ex.e_phentsize * elf_ex.e_phnum; + elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); if (elf_phdata == NULL) return -ENOMEM; - retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata, - elf_ex.e_phentsize * elf_ex.e_phnum, 1); - if (retval < 0) { - kfree (elf_phdata); - return retval; - } + retval = read_exec(bprm->dentry, elf_ex.e_phoff, + (char *) elf_phdata, size, 1); + if (retval < 0) + goto out_phdata; #ifdef DEBUG_ELF dump_phdrs(elf_phdata, elf_ex.e_phnum); @@ -669,12 +670,10 @@ elf_bss = 0; elf_brk = 0; - elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY); - - if (elf_exec_fileno < 0) { - kfree (elf_phdata); - return elf_exec_fileno; - } + retval = open_dentry(bprm->dentry, O_RDONLY); + if (retval < 0) + goto out_phdata; + file = fget(elf_exec_fileno = retval); elf_stack = 0xffffffff; elf_interpreter = NULL; @@ -686,40 +685,26 @@ &interpreter_dentry, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); - if(retval) { - kfree(elf_phdata); - sys_close(elf_exec_fileno); - return retval; - } + if(retval) + goto out_file; if(elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); - if(retval) { - kfree(elf_interpreter); - kfree(elf_phdata); - sys_close(elf_exec_fileno); - return retval; - } + if(retval) + goto out_interp; } /* OK, we are done with that, now set up the arg stuff, * and then start this sucker up. */ - if (!bprm->sh_bang) { - if (!bprm->p) { - if(elf_interpreter) { - kfree(elf_interpreter); - } - kfree (elf_phdata); - sys_close(elf_exec_fileno); - return -E2BIG; - } - } + retval = -E2BIG; + if (!bprm->sh_bang && !bprm->p) + goto out_interp; /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) - return retval; + goto out_interp; /* OK, This is the point of no return */ current->mm->end_data = 0; @@ -741,8 +726,7 @@ old_fs = get_fs(); set_fs(get_ds()); - map_executable(current->files->fd[elf_exec_fileno], elf_phdata, - elf_ex.e_phnum, &elf_stack, &load_addr, + map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack, &load_addr, &start_code, &elf_bss, &end_code, &end_data, &elf_brk); if(elf_interpreter) { @@ -762,6 +746,7 @@ set_fs(old_fs); kfree(elf_phdata); + fput(file); sys_close(elf_exec_fileno); current->personality = PER_IRIX32; @@ -824,6 +809,17 @@ if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); return 0; + +out_interp: + if(elf_interpreter) { + kfree(elf_interpreter); + } +out_file: + fput(file); + sys_close(elf_exec_fileno); +out_phdata: + kfree (elf_phdata); + return retval; } static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) @@ -839,9 +835,8 @@ /* This is really simpleminded and specialized - we are loading an * a.out library that is given an ELF header. */ -static inline int do_load_irix_library(int fd) +static inline int do_load_irix_library(struct file *file) { - struct file * file; struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; struct dentry *dentry; @@ -854,14 +849,12 @@ int i,j, k; len = 0; - file = current->files->fd[fd]; + if (!file->f_op) + return -EACCES; dentry = file->f_dentry; inode = dentry->d_inode; elf_bss = 0; - if (!file || !file->f_op) - return -EACCES; - /* Seek to the beginning of the file. */ if (file->f_op->llseek) { if ((error = file->f_op->llseek(file, 0, 0)) != 0) @@ -940,10 +933,15 @@ static int load_irix_library(int fd) { - int retval; + int retval = -EACCES; + struct file *file; MOD_INC_USE_COUNT; - retval = do_load_irix_library(fd); + file = fget(fd); + if (file) { + retval = do_load_irix_library(file); + fput(file); + } MOD_DEC_USE_COUNT; return retval; } @@ -984,9 +982,12 @@ return -ENOEXEC; } - filp = current->files->fd[fd]; - if(!filp || !filp->f_op) { + filp = fget(fd); + if (!filp) + return -EACCES; + if(!filp->f_op) { printk("irix_mapelf: Bogon filp!\n"); + fput(file); return -EACCES; } @@ -1004,6 +1005,7 @@ if(retval != (hp->p_vaddr & 0xfffff000)) { printk("irix_mapelf: do_mmap fails with %d!\n", retval); + fput(file); return retval; } } @@ -1011,6 +1013,7 @@ #ifdef DEBUG_ELF printk("irix_mapelf: Success, returning %08lx\n", user_phdrp->p_vaddr); #endif + fput(file); return user_phdrp->p_vaddr; } @@ -1026,7 +1029,13 @@ */ static int dump_write(struct file *file, const void *addr, int nr) { - return file->f_op->write(file, addr, nr, &file->f_pos) == 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; } static int dump_seek(struct file *file, off_t off) @@ -1108,10 +1117,10 @@ #undef DUMP_SEEK #define DUMP_WRITE(addr, nr) \ - if (!dump_write(&file, (addr), (nr))) \ + if (!dump_write(file, (addr), (nr))) \ goto close_coredump; #define DUMP_SEEK(off) \ - if (!dump_seek(&file, (off))) \ + if (!dump_seek(file, (off))) \ goto close_coredump; /* Actual dumper. * @@ -1122,7 +1131,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs) { int has_dumped = 0; - struct file file; + struct file *file; struct dentry *dentry; struct inode *inode; mm_segment_t fs; @@ -1191,26 +1200,28 @@ fs = get_fs(); set_fs(KERNEL_DS); + memcpy(corefile,"core.", 5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = '\0'; #endif - dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(dentry)) { - inode = NULL; + file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); + if (IS_ERR(file)) goto end_coredump; - } + dentry = file->f_dentry; inode = dentry->d_inode; + if (inode->i_nlink > 1) + goto close_coredump; /* multiple links - don't dump */ + if (!S_ISREG(inode->i_mode)) - goto end_coredump; + goto close_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) - goto end_coredump; - if (init_private_file(&file, dentry, 3)) - goto end_coredump; - if (!file.f_op->write) goto close_coredump; + if (!file->f_op->write) + goto close_coredump; + has_dumped = 1; current->flags |= PF_DUMPCORE; @@ -1346,7 +1357,7 @@ } for(i = 0; i < numnote; i++) - if (!writenote(¬es[i], &file)) + if (!writenote(¬es[i], file)) goto close_coredump; set_fs(fs); @@ -1368,19 +1379,17 @@ DUMP_WRITE((void *)addr, len); } - if ((off_t) file.f_pos != offset) { + if ((off_t) file->f_pos != offset) { /* Sanity check. */ - printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n", - (off_t) file.f_pos, offset); + printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", + (off_t) file->f_pos, offset); } close_coredump: - if (file.f_op->release) - file.f_op->release(inode, &file); + filp_close(file, NULL); end_coredump: set_fs(fs); - dput(dentry); #ifndef CONFIG_BINFMT_ELF MOD_DEC_USE_COUNT; #endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/irixinv.c linux/arch/mips/kernel/irixinv.c --- v2.2.10/linux/arch/mips/kernel/irixinv.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/irixinv.c Mon Aug 9 12:04:38 1999 @@ -5,7 +5,7 @@ * * Miguel de Icaza, 1997. * - * $Id: irixinv.c,v 1.3 1998/03/27 08:53:40 ralf Exp $ + * $Id: irixinv.c,v 1.3 1998/04/05 11:23:51 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c --- v2.2.10/linux/arch/mips/kernel/irixioctl.c Sat May 8 11:14:01 1999 +++ linux/arch/mips/kernel/irixioctl.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: irixioctl.c,v 1.4 1998/03/04 12:17:41 ralf Exp $ +/* $Id: irixioctl.c,v 1.6 1999/02/06 05:12:56 adevries Exp $ * irixioctl.c: A fucking mess... * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -33,15 +34,13 @@ { struct file *filp; - file = fcheck(fd); - if(!file) + if(!(filp = fcheck(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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c --- v2.2.10/linux/arch/mips/kernel/irixsig.c Thu Nov 5 09:58:29 1998 +++ linux/arch/mips/kernel/irixsig.c Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: irixsig.c,v 1.11 1998/03/26 07:39:09 ralf Exp $ + * $Id: irixsig.c,v 1.10.2.2 1999/06/17 12:06:39 ralf Exp $ */ #include @@ -272,6 +272,7 @@ default: lock_kernel(); sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c --- v2.2.10/linux/arch/mips/kernel/irq.c Wed Dec 23 09:44:40 1998 +++ linux/arch/mips/kernel/irq.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.13 1998/05/28 03:17:55 ralf Exp $ +/* $Id: irq.c,v 1.15 1999/02/25 21:50:49 tsbogend Exp $ * * 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 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,21 @@ #include #include #include +#include -unsigned char cache_21 = 0xff; -unsigned char cache_A1 = 0xff; +/* + * This contains the irq mask for both 8259A irq controllers, it's an + * int so we can deal with the third PIC in some systems like the RM300. + * (XXX This is broken for big endian.) + */ +static unsigned int cached_irq_mask = 0xffff; + +#define __byte(x,y) (((unsigned char *)&(y))[x]) +#define __word(x,y) (((unsigned short *)&(y))[x]) +#define __long(x,y) (((unsigned int *)&(y))[x]) + +#define cached_21 (__byte(0,cached_irq_mask)) +#define cached_A1 (__byte(1,cached_irq_mask)) unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; @@ -39,31 +52,23 @@ * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and * PCI devices. Other onboard hardware needs specific routines. */ -static inline void mask_irq(unsigned int irq_nr) +static inline void mask_irq(unsigned int irq) { - unsigned char mask; - - mask = 1 << (irq_nr & 7); - if (irq_nr < 8) { - cache_21 |= mask; - outb(cache_21,0x21); + cached_irq_mask |= 1 << irq; + if (irq & 8) { + outb(cached_A1, 0xa1); } else { - cache_A1 |= mask; - outb(cache_A1,0xA1); + outb(cached_21, 0x21); } } -static inline void unmask_irq(unsigned int irq_nr) +static inline void unmask_irq(unsigned int irq) { - unsigned char mask; - - mask = ~(1 << (irq_nr & 7)); - if (irq_nr < 8) { - cache_21 &= mask; - outb(cache_21,0x21); + cached_irq_mask &= ~(1 << irq); + if (irq & 8) { + outb(cached_A1, 0xa1); } else { - cache_A1 &= mask; - outb(cache_A1,0xA1); + outb(cached_21, 0x21); } } @@ -84,13 +89,11 @@ restore_flags(flags); } -/* - * Pointers to the low-level handlers: first the general ones, then the - * fast ones, then the bad ones. - */ -extern void interrupt(void); - -static struct irqaction *irq_action[32] = { +static struct irqaction *irq_action[NR_IRQS] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -122,6 +125,59 @@ atomic_t __mips_bh_counter; +static inline void i8259_mask_and_ack_irq(int irq) +{ + cached_irq_mask |= 1 << irq; + + if (irq & 8) { + inb(0xa1); + outb(cached_A1, 0xa1); + outb(0x62, 0x20); /* Specific EOI to cascade */ + outb(0x20, 0xa0); + } else { + inb(0x21); + outb(cached_21, 0x21); + outb(0x20, 0x20); + } +} + +asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + hardirq_enter(cpu); + + if (irq >= 16) + goto out; + + i8259_mask_and_ack_irq(irq); + + kstat.irqs[cpu][irq]++; + + action = *(irq + irq_action); + if (!action) + goto out; + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + action = *(irq + irq_action); + do_random = 0; + do { + do_random |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + unmask_irq (irq); + +out: + hardirq_exit(cpu); +} + /* * do_IRQ handles IRQ's that have been installed without the * SA_INTERRUPT flag: it uses the full signal-handling return @@ -135,23 +191,9 @@ int do_random, cpu; cpu = smp_processor_id(); - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[cpu][irq]++; - /* - * mask and ack quickly, we don't want the irq controller - * thinking we're snobs just because some other CPU has - * disabled global interrupts (we have already done the - * INT_ACK cycles, it's too late to try to pretend to the - * controller that we aren't taking the interrupt). - * - * Commented out because we've already done this in the - * machinespecific part of the handler. It's reasonable to - * do this here in a highlevel language though because that way - * we could get rid of a good part of duplicated code ... - */ - /* mask_and_ack_irq(irq); */ - action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) @@ -165,21 +207,14 @@ } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - unmask_irq (irq); __cli(); } - irq_exit(cpu, irq); + hardirq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } -/* - * Used only for setup of PC style interrupts and therefore still - * called setup_x86_irq. Later on I'll provide a machine specific - * function with similar purpose. Idea is to put all interrupts - * in a single table and differenciate them just by number. - */ -int setup_x86_irq(int irq, struct irqaction * new) +int i8259_setup_irq(int irq, struct irqaction * new) { int shared = 0; struct irqaction *old, **p; @@ -216,11 +251,15 @@ return 0; } +/* + * Request_interrupt and free_interrupt ``sort of'' handle interrupts of + * non i8259 devices. They will have to be replaced by architecture + * specific variants. For now we still use this as broken as it is because + * it used to work ... + */ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) + unsigned long irqflags, const char * devname, void *dev_id) { int retval; struct irqaction * action; @@ -241,7 +280,7 @@ action->next = NULL; action->dev_id = dev_id; - retval = setup_x86_irq(irq, action); + retval = i8259_setup_irq(irq, action); if (retval) kfree(action); @@ -275,7 +314,7 @@ unsigned long probe_irq_on (void) { - unsigned int i, irqs = 0, irqmask; + unsigned int i, irqs = 0; unsigned long delay; /* first, enable any unassigned (E)ISA irqs */ @@ -291,19 +330,17 @@ /* about 100ms delay */; /* now filter out any obviously spurious interrupts */ - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; - return irqs & ~irqmask; + return irqs & ~cached_irq_mask; } int probe_irq_off (unsigned long irqs) { - unsigned int i, irqmask; + unsigned int i; - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; #ifdef DEBUG printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask); #endif - irqs &= irqmask; + irqs &= cached_irq_mask; if (!irqs) return 0; i = ffz(~irqs); @@ -314,13 +351,36 @@ int (*irq_cannonicalize)(int irq); -static int i8259a_irq_cannonicalize(int irq) +static int i8259_irq_cannonicalize(int irq) { return ((irq == 2) ? 9 : irq); } +__initfunc(static void i8259_init(void)) +{ + /* Init master interrupt controller */ + outb(0x11, 0x20); /* Start init sequence */ + outb(0x00, 0x21); /* Vector base */ + outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0x21); /* Select 8086 mode */ + outb(0xff, 0x21); /* Mask all */ + + /* Init slave interrupt controller */ + outb(0x11, 0xa0); /* Start init sequence */ + outb(0x08, 0xa1); /* Vector base */ + outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */ + outb(0x01, 0xa1); /* Select 8086 mode */ + outb(0xff, 0xa1); /* Mask all */ + + outb(cached_A1, 0xa1); + outb(cached_21, 0x21); +} + __initfunc(void init_IRQ(void)) { - irq_cannonicalize = i8259a_irq_cannonicalize; + irq_cannonicalize = i8259_irq_cannonicalize; + /* i8259_init(); */ irq_setup(); } + +EXPORT_SYMBOL(irq_cannonicalize); diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c --- v2.2.10/linux/arch/mips/kernel/mips_ksyms.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/mips_ksyms.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: mips_ksyms.c,v 1.12 1998/09/16 22:50:41 ralf Exp $ +/* $Id: mips_ksyms.c,v 1.19 1999/04/11 18:37:55 harald Exp $ * * Export MIPS-specific functions needed for loadable modules. * @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -50,23 +51,25 @@ EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(__mips_bh_counter); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); -//EXPORT_SYMBOL(enable_irq); -//EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); /* * Userspace access stuff. */ -EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(__bzero); -EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm); -EXPORT_SYMBOL(__strncpy_from_user_asm); -EXPORT_SYMBOL(__strlen_user_nocheck_asm); -EXPORT_SYMBOL(__strlen_user_asm); +EXPORT_SYMBOL_NOVERS(__copy_user); +EXPORT_SYMBOL_NOVERS(__bzero); +EXPORT_SYMBOL_NOVERS(__strncpy_from_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); +EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strlen_user_asm); /* Networking helper routines. */ @@ -77,6 +80,10 @@ */ EXPORT_SYMBOL(flush_page_to_ram); EXPORT_SYMBOL(flush_cache_all); +EXPORT_SYMBOL(dma_cache_wback_inv); +EXPORT_SYMBOL(dma_cache_inv); + +EXPORT_SYMBOL(invalid_pte_table); /* * Base address of ports for Intel style I/O. @@ -106,12 +113,12 @@ int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)); #ifdef CONFIG_MIPS_FPE_MODULE -EXPORT_SYMBOL(force_sig); EXPORT_SYMBOL(__compute_return_epc); EXPORT_SYMBOL(register_fpe); EXPORT_SYMBOL(unregister_fpe); #endif -#if CONFIG_PCI -EXPORT_SYMBOL(pci_devices); +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); #endif + diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c --- v2.2.10/linux/arch/mips/kernel/pci.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/pci.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.6 1998/08/19 21:53:50 ralf Exp $ +/* $Id: pci.c,v 1.8 1999/05/01 22:40:36 ralf Exp $ * * 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 @@ -36,13 +36,13 @@ } /* - * 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. */ void pcibios_fixup (void) { - return pci_ops->pcibios_fixup(); + pci_ops->pcibios_fixup(); } int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, @@ -88,11 +88,6 @@ __initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) { -} - -__initfunc(char *pcibios_setup(char *str)) -{ - return str; } #endif /* defined(CONFIG_PCI) */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.2.10/linux/arch/mips/kernel/process.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/process.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.11 1998/08/17 12:14:53 ralf Exp $ +/* $Id: process.c,v 1.11 1999/01/03 17:50:51 ralf Exp $ * * 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 @@ -144,4 +144,41 @@ (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT; memcpy(&dump->regs[0], regs, sizeof(struct pt_regs)); memcpy(&dump->regs[EF_SIZE/4], ¤t->tss.fpu, sizeof(current->tss.fpu)); +} + +/* + * Create a kernel thread + */ +pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "move\t$6,$sp\n\t" + "move\t$4,%5\n\t" + "li\t$2,%1\n\t" + "syscall\n\t" + "beq\t$6,$sp,1f\n\t" + "subu\t$sp,32\n\t" /* delay slot */ + "jalr\t%4\n\t" + "move\t$4,%3\n\t" /* delay slot */ + "move\t$4,$2\n\t" + "li\t$2,%2\n\t" + "syscall\n" + "1:\taddiu\t$sp,32\n\t" + "move\t%0,$2\n\t" + ".set\treorder" + :"=r" (retval) + :"i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "r" (fn), + "r" (flags | CLONE_VM) + /* + * The called subroutine might have destroyed any of the + * at, result, argument or temporary registers ... + */ + :"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$9","$10","$11","$12","$13","$14","$15","$24","$25"); + + return retval; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.2.10/linux/arch/mips/kernel/ptrace.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/ptrace.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: ptrace.c,v 1.11 1998/10/19 16:26:31 ralf Exp $ +/* $Id: ptrace.c,v 1.12 1999/06/13 16:30:32 ralf Exp $ * * 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 @@ -259,6 +259,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; + unsigned int flags; int res; lock_kernel(); @@ -297,22 +298,26 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && - !capable(CAP_SYS_PTRACE)) { + (current->gid != child->gid) || + (!cap_issubset(child->cap_permitted, + current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)){ res = -EPERM; goto out; } /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) { - res = -EPERM; + if (child->flags & PF_PTRACED) goto out; - } child->flags |= PF_PTRACED; + + write_lock_irqsave(&tasklist_lock, flags); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } + write_unlock_irqrestore(&tasklist_lock, flags); + send_sig(SIGSTOP, child, 1); res = 0; goto out; @@ -337,15 +342,16 @@ case PTRACE_PEEKDATA: { unsigned long tmp; + down(&child->mm->mmap_sem); res = read_long(child, addr, &tmp); + up(&child->mm->mmap_sem); if (res < 0) goto out; res = put_user(tmp,(unsigned long *) data); goto out; } - /* read the word at location addr in the USER area. */ -/* #define DEBUG_PEEKUSR */ + /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; unsigned long tmp; @@ -353,12 +359,15 @@ regs = (struct pt_regs *) ((unsigned long) child + KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); tmp = 0; /* Default return value. */ - if (addr < 32 && addr >= 0) - tmp = regs->regs[addr]; - else if (addr >= 32 && addr < 64) { - unsigned long long *fregs; + switch(addr) { + case 0 ... 31: + tmp = regs->regs[addr]; + break; + case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { + unsigned long long *fregs; + if (last_task_used_math == child) { enable_cp1(); r4xx0_save_fp(child); @@ -371,35 +380,32 @@ } else { tmp = -1; /* FP not yet used */ } - } else { - addr -= 64; - switch(addr) { - case 0: - tmp = regs->cp0_epc; - break; - case 1: - tmp = regs->cp0_cause; - break; - case 2: - tmp = regs->cp0_badvaddr; - break; - case 3: - tmp = regs->lo; - break; - case 4: - tmp = regs->hi; - break; - case 5: - tmp = child->tss.fpu.hard.control; - break; - case 6: /* implementation / version register */ - tmp = 0; /* XXX */ - break; - default: - tmp = 0; - res = -EIO; - goto out; - } + break; + case PC: + tmp = regs->cp0_epc; + break; + case CAUSE: + tmp = regs->cp0_cause; + break; + case BADVADDR: + tmp = regs->cp0_badvaddr; + break; + case MMHI: + tmp = regs->hi; + break; + case MMLO: + tmp = regs->lo; + break; + case FPC_CSR: + tmp = child->tss.fpu.hard.control; + break; + case FPC_EIR: /* implementation / version register */ + tmp = 0; /* XXX */ + break; + default: + tmp = 0; + res = -EIO; + goto out; } res = put_user(tmp, (unsigned long *) data); goto out; @@ -407,20 +413,22 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: + down(&child->mm->mmap_sem); res = write_long(child,addr,data); + up(&child->mm->mmap_sem); goto out; case PTRACE_POKEUSR: { + unsigned long long *fregs; struct pt_regs *regs; int res = 0; - regs = (struct pt_regs *) ((unsigned long) child + - KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); - if (addr < 32 && addr >= 0) - regs->regs[addr] = data; - else if (addr >= 32 && addr < 64) { - unsigned long long *fregs; - + switch (addr) { + case 0 ... 31: + regs = (struct pt_regs *) ((unsigned long) child + + KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); + break; + case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { if (last_task_used_math == child) { enable_cp1(); @@ -437,26 +445,23 @@ fregs = (unsigned long long *) &child->tss.fpu.hard.fp_regs[0]; fregs[(addr - 32)] = (unsigned long long) data; - } else { - addr -= 64; - switch (addr) { - case 0: - regs->cp0_epc = data; - break; - case 3: - regs->lo = data; - break; - case 4: - regs->hi = data; - break; - case 5: - child->tss.fpu.hard.control = data; - break; - default: - /* The rest are not allowed. */ - res = -EIO; - break; - }; + break; + case PC: + regs->cp0_epc = data; + break; + case MMHI: + regs->hi = data; + break; + case MMLO: + regs->lo = data; + break; + case FPC_CSR: + child->tss.fpu.hard.control = data; + break; + default: + /* The rest are not allowed. */ + res = -EIO; + break; } goto out; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S --- v2.2.10/linux/arch/mips/kernel/r2300_fpu.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r2300_fpu.S Mon Aug 9 12:04:38 1999 @@ -1,16 +1,17 @@ -/* +/* $Id: r2300_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $ * r2300_fpu.S: Save/restore floating point context for signal handlers. * * 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. * - * Copyright (C) 1996 by Ralf Baechle + * Copyright (C) 1996, 1998 by Ralf Baechle * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r2300_fpu.S,v 1.3 1997/12/01 16:54:20 ralf Exp $ + * Further modifications to make this work: + * Copyright (c) 1998 Harald Koerfgen */ #include #include @@ -18,123 +19,103 @@ #include #include - .set mips3 +#define EX(a,b) \ +9: a,##b; \ + .section __ex_table,"a"; \ + PTR 9b,bad_stack; \ + .previous + .set noreorder + .set mips1 /* Save floating point context */ - .align 5 - LEAF(r2300_save_fp_context) - mfc0 t0,CP0_STATUS - sll t0,t0,2 - - bgez t0,1f - nop - - cfc1 t0,fcr31 - /* Store the 32 single precision registers */ - swc1 $f0,(SC_FPREGS+0)(a0) - swc1 $f1,(SC_FPREGS+8)(a0) - swc1 $f2,(SC_FPREGS+16)(a0) - swc1 $f3,(SC_FPREGS+24)(a0) - swc1 $f4,(SC_FPREGS+32)(a0) - swc1 $f5,(SC_FPREGS+40)(a0) - swc1 $f6,(SC_FPREGS+48)(a0) - swc1 $f7,(SC_FPREGS+56)(a0) - swc1 $f8,(SC_FPREGS+64)(a0) - swc1 $f9,(SC_FPREGS+72)(a0) - swc1 $f10,(SC_FPREGS+80)(a0) - swc1 $f11,(SC_FPREGS+88)(a0) - swc1 $f12,(SC_FPREGS+96)(a0) - swc1 $f13,(SC_FPREGS+104)(a0) - swc1 $f14,(SC_FPREGS+112)(a0) - swc1 $f15,(SC_FPREGS+120)(a0) - swc1 $f16,(SC_FPREGS+128)(a0) - swc1 $f17,(SC_FPREGS+136)(a0) - swc1 $f18,(SC_FPREGS+144)(a0) - swc1 $f19,(SC_FPREGS+152)(a0) - swc1 $f20,(SC_FPREGS+160)(a0) - swc1 $f21,(SC_FPREGS+168)(a0) - swc1 $f22,(SC_FPREGS+176)(a0) - swc1 $f23,(SC_FPREGS+184)(a0) - swc1 $f24,(SC_FPREGS+192)(a0) - swc1 $f25,(SC_FPREGS+200)(a0) - swc1 $f26,(SC_FPREGS+208)(a0) - swc1 $f27,(SC_FPREGS+216)(a0) - swc1 $f28,(SC_FPREGS+224)(a0) - swc1 $f29,(SC_FPREGS+232)(a0) - swc1 $f30,(SC_FPREGS+240)(a0) - swc1 $f31,(SC_FPREGS+248)(a0) - sw t0,SC_FPC_CSR(a0) +LEAF(r2300_save_fp_context) + + cfc1 t1,fcr31 + EX(swc1 $f0,(SC_FPREGS+0)(a0)) + EX(swc1 $f1,(SC_FPREGS+8)(a0)) + EX(swc1 $f2,(SC_FPREGS+16)(a0)) + EX(swc1 $f3,(SC_FPREGS+24)(a0)) + EX(swc1 $f4,(SC_FPREGS+32)(a0)) + EX(swc1 $f5,(SC_FPREGS+40)(a0)) + EX(swc1 $f6,(SC_FPREGS+48)(a0)) + EX(swc1 $f7,(SC_FPREGS+56)(a0)) + EX(swc1 $f8,(SC_FPREGS+64)(a0)) + EX(swc1 $f9,(SC_FPREGS+72)(a0)) + EX(swc1 $f10,(SC_FPREGS+80)(a0)) + EX(swc1 $f11,(SC_FPREGS+88)(a0)) + EX(swc1 $f12,(SC_FPREGS+96)(a0)) + EX(swc1 $f13,(SC_FPREGS+104)(a0)) + EX(swc1 $f14,(SC_FPREGS+112)(a0)) + EX(swc1 $f15,(SC_FPREGS+120)(a0)) + EX(swc1 $f16,(SC_FPREGS+128)(a0)) + EX(swc1 $f17,(SC_FPREGS+136)(a0)) + EX(swc1 $f18,(SC_FPREGS+144)(a0)) + EX(swc1 $f19,(SC_FPREGS+152)(a0)) + EX(swc1 $f20,(SC_FPREGS+160)(a0)) + EX(swc1 $f21,(SC_FPREGS+168)(a0)) + EX(swc1 $f22,(SC_FPREGS+176)(a0)) + EX(swc1 $f23,(SC_FPREGS+184)(a0)) + EX(swc1 $f24,(SC_FPREGS+192)(a0)) + EX(swc1 $f25,(SC_FPREGS+200)(a0)) + EX(swc1 $f26,(SC_FPREGS+208)(a0)) + EX(swc1 $f27,(SC_FPREGS+216)(a0)) + EX(swc1 $f28,(SC_FPREGS+224)(a0)) + EX(swc1 $f29,(SC_FPREGS+232)(a0)) + EX(swc1 $f30,(SC_FPREGS+240)(a0)) + EX(swc1 $f31,(SC_FPREGS+248)(a0)) + EX(sw t1,SC_FPC_CSR(a0)) cfc1 t0,$0 # implementation/version jr ra .set nomacro - sw t0,SC_FPC_EIR(a0) - .set macro -1: - jr ra - .set nomacro - nop + EX(sw t0,SC_FPC_EIR(a0)) .set macro 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. */ - LEAF(r2300_restore_fp_context) - mfc0 t0,CP0_STATUS - sll t0,t0,2 - - bgez t0,1f - nop - - lw t0,SC_FPC_CSR(a0) - /* Restore the 16 odd double precision registers only - * when enabled in the cp0 status register. - */ - ldc1 $f0,(SC_FPREGS+0)(a0) - ldc1 $f1,(SC_FPREGS+8)(a0) - ldc1 $f2,(SC_FPREGS+16)(a0) - ldc1 $f3,(SC_FPREGS+24)(a0) - ldc1 $f4,(SC_FPREGS+32)(a0) - ldc1 $f5,(SC_FPREGS+40)(a0) - ldc1 $f6,(SC_FPREGS+48)(a0) - ldc1 $f7,(SC_FPREGS+56)(a0) - ldc1 $f8,(SC_FPREGS+64)(a0) - ldc1 $f9,(SC_FPREGS+72)(a0) - ldc1 $f10,(SC_FPREGS+80)(a0) - ldc1 $f11,(SC_FPREGS+88)(a0) - ldc1 $f12,(SC_FPREGS+96)(a0) - ldc1 $f13,(SC_FPREGS+104)(a0) - ldc1 $f14,(SC_FPREGS+112)(a0) - ldc1 $f15,(SC_FPREGS+120)(a0) - ldc1 $f16,(SC_FPREGS+128)(a0) - ldc1 $f17,(SC_FPREGS+136)(a0) - ldc1 $f18,(SC_FPREGS+144)(a0) - ldc1 $f19,(SC_FPREGS+152)(a0) - ldc1 $f20,(SC_FPREGS+160)(a0) - ldc1 $f21,(SC_FPREGS+168)(a0) - ldc1 $f22,(SC_FPREGS+176)(a0) - ldc1 $f23,(SC_FPREGS+184)(a0) - ldc1 $f24,(SC_FPREGS+192)(a0) - ldc1 $f25,(SC_FPREGS+200)(a0) - ldc1 $f26,(SC_FPREGS+208)(a0) - ldc1 $f27,(SC_FPREGS+216)(a0) - ldc1 $f28,(SC_FPREGS+224)(a0) - ldc1 $f29,(SC_FPREGS+232)(a0) - ldc1 $f30,(SC_FPREGS+240)(a0) - ldc1 $f31,(SC_FPREGS+248)(a0) +LEAF(r2300_restore_fp_context) + EX(lw t0,SC_FPC_CSR(a0)) + EX(lwc1 $f0,(SC_FPREGS+0)(a0)) + EX(lwc1 $f1,(SC_FPREGS+8)(a0)) + EX(lwc1 $f2,(SC_FPREGS+16)(a0)) + EX(lwc1 $f3,(SC_FPREGS+24)(a0)) + EX(lwc1 $f4,(SC_FPREGS+32)(a0)) + EX(lwc1 $f5,(SC_FPREGS+40)(a0)) + EX(lwc1 $f6,(SC_FPREGS+48)(a0)) + EX(lwc1 $f7,(SC_FPREGS+56)(a0)) + EX(lwc1 $f8,(SC_FPREGS+64)(a0)) + EX(lwc1 $f9,(SC_FPREGS+72)(a0)) + EX(lwc1 $f10,(SC_FPREGS+80)(a0)) + EX(lwc1 $f11,(SC_FPREGS+88)(a0)) + EX(lwc1 $f12,(SC_FPREGS+96)(a0)) + EX(lwc1 $f13,(SC_FPREGS+104)(a0)) + EX(lwc1 $f14,(SC_FPREGS+112)(a0)) + EX(lwc1 $f15,(SC_FPREGS+120)(a0)) + EX(lwc1 $f16,(SC_FPREGS+128)(a0)) + EX(lwc1 $f17,(SC_FPREGS+136)(a0)) + EX(lwc1 $f18,(SC_FPREGS+144)(a0)) + EX(lwc1 $f19,(SC_FPREGS+152)(a0)) + EX(lwc1 $f20,(SC_FPREGS+160)(a0)) + EX(lwc1 $f21,(SC_FPREGS+168)(a0)) + EX(lwc1 $f22,(SC_FPREGS+176)(a0)) + EX(lwc1 $f23,(SC_FPREGS+184)(a0)) + EX(lwc1 $f24,(SC_FPREGS+192)(a0)) + EX(lwc1 $f25,(SC_FPREGS+200)(a0)) + EX(lwc1 $f26,(SC_FPREGS+208)(a0)) + EX(lwc1 $f27,(SC_FPREGS+216)(a0)) + EX(lwc1 $f28,(SC_FPREGS+224)(a0)) + EX(lwc1 $f29,(SC_FPREGS+232)(a0)) + EX(lwc1 $f30,(SC_FPREGS+240)(a0)) + EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra - .set nomacro ctc1 t0,fcr31 - .set macro -1: - jr ra - .set nomacro - nop - .set macro END(r2300_restore_fp_context) + + diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S --- v2.2.10/linux/arch/mips/kernel/r2300_misc.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r2300_misc.S Mon Aug 9 12:04:38 1999 @@ -1,14 +1,17 @@ -/* $Id: r2300_misc.S,v 1.1.1.1 1997/06/01 03:16:42 ralf Exp $ +/* $Id: r2300_misc.S,v 1.3 1999/05/01 22:40:36 ralf Exp $ * r2300_misc.S: Misc. exception handling code for R3000/R2000. * * 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) + * + * Further modifications to make this work: + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 1998 Gleb Raiko & Vladimir Roganov */ -#include - #include +#include #include #include #include @@ -18,380 +21,175 @@ #include #include #include +#include #include .text .set mips1 .set noreorder - .align 5 - NESTED(r2300_handle_tlbl, PT_SIZE, sp) - .set noat - /* Check whether this is a refill or an invalid exception */ - mfc0 k0,CP0_BADVADDR - mfc0 k1,CP0_ENTRYHI - ori k0,0xfff # clear ASID... - xori k0,0xfff # in BadVAddr - andi k1,0xfc0 # get current ASID - or k0,k1 # make new entryhi - mfc0 k1,CP0_ENTRYHI - mtc0 k0,CP0_ENTRYHI - nop # for pipeline - nop - nop - tlbp - nop # for pipeline - nop - mfc0 k0,CP0_INDEX - - bgez k0,invalid_tlbl # bad addr in c0_badvaddr - mtc0 k1,CP0_ENTRYHI - - /* Damn... The next nop is required on the R4400PC V5.0, but - * I don't know why - at least there is no documented - * reason as for the others :-( - * And I haven't tested it as being necessary on R3000 - PMA. - * (The R3000 pipeline has only 5 stages, so it's probably not - * required -- Ralf) - */ - nop - -#ifdef CONF_DEBUG_TLB - /* OK, this is a double fault. Let's see whether this is - * due to an invalid entry in the page_table. - */ - /* used to be dmfc0 */ - mfc0 k0,CP0_BADVADDR - /* FIXME: This srl/sll sequence is as it is for the R4xx0, - * and I suspect that it should be different for - * the R[23]000. PMA - * (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 - * switching to 64 bit ... -- Ralf) - */ - srl k0,12 # get PFN? - sll k0,2 - lui k1,%HI(TLBMAP) - addu k0,k1 - lw k1,(k0) - andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED) - bnez k1,reload_pgd_entries - nop - - .set noat - SAVE_ALL - .set at - PRINT("Double fault caused by invalid entries in pgd:\n") - mfc0 a1,CP0_BADVADDR - PRINT("Double fault address : %08lx\n") - mfc0 a1,CP0_EPC - PRINT("c0_epc : %08lx\n") - - jal show_regs - move a0,sp +#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */ - jal dump_tlb_nonwired - nop + /* ABUSE of CPP macros 101. */ - mfc0 a0,CP0_BADVADDR + /* After this macro runs, the pte faulted on is + * in register PTE, a ptr into the table in which + * the pte belongs is in PTR. + */ +#define LOAD_PTE(pte, ptr) \ + mfc0 pte, CP0_BADVADDR; \ + _GET_CURRENT(ptr); \ + srl pte, pte, 22; \ + lw ptr, THREAD_PGDIR(ptr); \ + sll pte, pte, 2; \ + addu ptr, pte, ptr; \ + mfc0 pte, CP0_CONTEXT; \ + lw ptr, (ptr); \ + andi pte, pte, 0xffc; \ + addu ptr, ptr, pte; \ + lw pte, (ptr); \ + nop; + + /* This places the even/odd pte pair in the page + * table at PTR into ENTRYLO0 and ENTRYLO1 using + * TMP as a scratch register. + */ +#define PTE_RELOAD(ptr) \ + lw ptr, (ptr) ; \ + nop ; \ + mtc0 ptr, CP0_ENTRYLO0; \ + nop; + +#define DO_FAULT(write) \ + .set noat; \ + .set macro; \ + SAVE_ALL; \ + mfc0 a2, CP0_BADVADDR; \ + STI; \ + .set at; \ + move a0, sp; \ + jal do_page_fault; \ + li a1, write; \ + j ret_from_sys_call; \ + nop; \ + .set noat; \ + .set nomacro; + + /* Check is PTE is present, if not then jump to LABEL. + * PTR points to the page table where this PTE is located, + * when the macro is done executing PTE will be restored + * with it's original value. + */ +#define PTE_PRESENT(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_READ); \ + bnez pte, label; \ + .set push; \ + .set reorder; \ + lw pte, (ptr); \ + .set pop; + + /* Make PTE valid, store result in PTR. */ +#define PTE_MAKEVALID(pte, ptr) \ + ori pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \ + sw pte, (ptr); + + /* Check if PTE can be written to, if not branch to LABEL. + * Regardless restore PTE with value from PTR when done. + */ +#define PTE_WRITABLE(pte, ptr, label) \ + andi pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + xori pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \ + bnez pte, label; \ + .set push; \ + .set reorder; \ + lw pte, (ptr); \ + .set pop; + + + /* Make PTE writable, update software status bits as well, + * then store at PTR. + */ +#define PTE_MAKEWRITE(pte, ptr) \ + ori pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \ + _PAGE_VALID | _PAGE_DIRTY); \ + sw pte, (ptr); - jal dump_list_current - nop + .set noreorder + .align 5 +NESTED(r2300_handle_tlbl, PT_SIZE, sp) .set noat - STI - .set at - PANIC("Corrupted pagedir") - .set noat - -reload_pgd_entries: -#endif /* CONF_DEBUG_TLB */ - /* Load missing pair of entries from the pgd and return. */ - mfc0 k1,CP0_CONTEXT - lw k0,(k1) # Never causes nested exception - mfc0 k1,CP0_EPC # get the return PC - srl k0,12 # Convert to EntryLo format - mtc0 k0,CP0_ENTRYLO0 - nop # for pipeline - tlbwr - nop # for pipeline +#ifndef NOTLB_OPTIMIZE + /* Test present bit in entry. */ + LOAD_PTE(k0, k1) + tlbp nop + PTE_PRESENT(k0, k1, nopage_tlbl) + PTE_MAKEVALID(k0, k1) + PTE_RELOAD(k1) + tlbwi nop - /* We don't know whether the original access was read or - * write, so return and see what happens... - */ - jr k1 - rfe - - /* Handle invalid exception - * - * There are two possible causes for an invalid (tlbl) - * exception: - * 1) pages with present bit set but the valid bit clear - * 2) nonexistant pages - * Case one needs fast handling, therefore don't save - * registers yet. - * - * k0 contains c0_index. - */ -invalid_tlbl: -#ifdef CONFIG_TLB_SHUTDOWN - /* Remove entry so we don't need to care later - * For sake of the pipeline the tlbwi insn has been moved down. - * Moving it around is juggling with explosives... - */ - /* FIXME: Why is Ralf setting bit 3 of k1? This may need to - * be changed for R[236]000! PMA - * (The new ENTRYHI value will then point represent a - * inique virtual address outside the 32 bit address - * limit. This is just paranoia to avoid a tlb - * shutdown. This whole part of the routine is probably - * no longer required and can be removed -- Ralf) - */ - lui k1,0x0008 - or k0,k1 - sll k0,12 # make it EntryHi format - mtc0 k0,CP0_ENTRYHI - mtc0 zero,CP0_ENTRYLO0 -#endif - /* Test present bit in entry */ - mfc0 k0,CP0_BADVADDR - /* FIXME: This srl/sll sequence is as it is for the R4xx0, - * and I suspect that it should be different for - * the R[23]000. PMA - * (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 - * switching to 64 bit ... -- Ralf) - */ - srl k0,12 - sll k0,2 -#ifdef CONFIG_TLB_SHUTDOWN - tlbwi # do not move! -#endif - lui k1,%HI(TLBMAP) - addu k0,k1 - lw k1,(k0) - andi k1,(_PAGE_PRESENT|_PAGE_READ) - xori k1,(_PAGE_PRESENT|_PAGE_READ) - - bnez k1,nopage_tlbl - lw k1,(k0) - - /* Present and read bits are set -> set valid and accessed bits */ - ori k1,(_PAGE_VALID|_PAGE_ACCESSED) - sw k1,(k0) - mfc0 k1,CP0_EPC + mfc0 k0, CP0_EPC nop - - jr k1 + jr k0 rfe - - /* Page doesn't exist. Lots of work which is less important - * for speed needs to be done, so hand it all over to the - * kernel memory management routines. - */ nopage_tlbl: - SAVE_ALL - mfc0 a2,CP0_BADVADDR - STI - .set at - /* a0 (struct pt_regs *) regs - * a1 (unsigned long) 0 for read access - * a2 (unsigned long) faulting virtual address - */ - move a0,sp - jal do_page_fault - li a1,0 - - j ret_from_sys_call - nop - END(r2300_handle_tlbl) +#endif + DO_FAULT(0) +END(r2300_handle_tlbl) - .text - .align 5 - NESTED(r2300_handle_tlbs, PT_SIZE, sp) +NESTED(r2300_handle_tlbs, PT_SIZE, sp) .set noat - /* It is impossible that is a nested reload exception. - * Therefore this must be a invalid exception. - * Two possible cases: - * 1) Page exists but not dirty. - * 2) Page doesn't exist yet. Hand over to the kernel. - * - * Test whether present bit in entry is set - */ - /* used to be dmfc0 */ - mfc0 k0,CP0_BADVADDR - /* FIXME: This srl/sll sequence is as it is for the R4xx0, - * and I suspect that it should be different for - * the R[23]000. PMA - */ - srl k0,12 - sll k0,2 - lui k1,%HI(TLBMAP) - addu k0,k1 - lw k1,(k0) - tlbp # find faulting entry - andi k1,(_PAGE_PRESENT|_PAGE_WRITE) - xori k1,(_PAGE_PRESENT|_PAGE_WRITE) - bnez k1,nopage_tlbs - lw k1,(k0) - - /* Present and writable bits set: set accessed and dirty bits. */ - ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \ - _PAGE_VALID|_PAGE_DIRTY) - sw k1,(k0) - /* Now reload the entry into the TLB */ - /* FIXME: Why has Ralf set bit 2? Should it be different for - * 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 - * has always an address with bit 2 set to zero. -- Ralf) - */ - ori k0,0x0004 - xori k0,0x0004 - lw k0,(k0) - srl k0,12 - mtc0 k0,CP0_ENTRYLO0 - mfc0 k1,CP0_EPC - nop # for pipeline +#ifndef NOTLB_OPTIMIZE + LOAD_PTE(k0, k1) + tlbp # find faulting entry + nop + PTE_WRITABLE(k0, k1, nopage_tlbs) + PTE_MAKEWRITE(k0, k1) + PTE_RELOAD(k1) tlbwi - nop # for pipeline nop + mfc0 k0, CP0_EPC nop - - jr k1 + jr k0 rfe - - /* Page doesn't exist. Lots of work which is less important - * for speed needs to be done, so hand it all over to the - * kernel memory management routines. - */ nopage_tlbs: -nowrite_mod: -#ifdef CONFIG_TLB_SHUTDOWN - /* Remove entry so we don't need to care later */ - mfc0 k0,CP0_INDEX -#ifdef CONF_DEBUG_TLB - bgez k0,2f - nop - /* We got a tlbs exception but found no matching entry in - * the tlb. This should never happen. Paranoia makes us - * check it, though. - */ - SAVE_ALL - jal show_regs - move a0,sp - .set at - mfc0 a1,CP0_BADVADDR - PRINT("c0_badvaddr == %08lx\n") - mfc0 a1,CP0_INDEX - PRINT("c0_index == %08x\n") - mfc0 a1,CP0_ENTRYHI - PRINT("c0_entryhi == %08x\n") - .set noat - STI - .set at - PANIC("Tlbs or tlbm exception with no matching entry in tlb") -1: - j 1b - nop -2: -#endif /* CONF_DEBUG_TLB */ - /* FIXME: Why is Ralf setting bit 3 of k1? This may need to - * be changed for R[236]000! PMA - * (The new ENTRYHI value will then point represent a - * inique virtual address outside the 32 bit address - * limit. This is just paranoia to avoid a tlb - * shutdown. This whole part of the routine is probably - * no longer required and can be removed -- Ralf) - */ - lui k1,0x0008 - or k0,k1 - sll k0,12 - mtc0 k0,CP0_ENTRYHI - mtc0 zero,CP0_ENTRYLO0 - nop # for pipeline - nop # R4000 V2.2 requires 4 NOPs - nop - nop - tlbwi -#endif /* CONFIG_TLB_SHUTDOWN */ - .set noat - SAVE_ALL - mfc0 a2,CP0_BADVADDR - STI - .set at - /* a0 (struct pt_regs *) regs - * a1 (unsigned long) 1 for write access - * a2 (unsigned long) faulting virtual address - */ - move a0,sp - jal do_page_fault - li a1,1 - - j ret_from_sys_call - nop - END(r2300_handle_tlbs) +#endif + DO_FAULT(1) +END(r2300_handle_tlbs) .align 5 - NESTED(r2300_handle_mod, PT_SIZE, sp) +NESTED(r2300_handle_mod, PT_SIZE, sp) .set noat - /* Two possible cases: - * 1) Page is writable but not dirty -> set dirty and return - * 2) Page is not writable -> call C handler - */ - /* used to be dmfc0 */ - mfc0 k0,CP0_BADVADDR - /* FIXME: This srl/sll sequence is as it is for the R4xx0, - * and I suspect that it should be different for - * the R[23]000. PMA - */ - srl k0,12 - sll k0,2 - lui k1,%HI(TLBMAP) - addu k0,k1 - lw k1,(k0) +#ifndef NOTLB_OPTIMIZE + LOAD_PTE(k0, k1) tlbp # find faulting entry - andi k1,_PAGE_WRITE + andi k0, k0, _PAGE_WRITE + beqz k0, nowrite_mod + .set push + .set reorder + lw k0, (k1) + .set pop - beqz k1,nowrite_mod - lw k1,(k0) + /* Present and writable bits set, set accessed and dirty bits. */ + PTE_MAKEWRITE(k0, k1) - /* Present and writable bits set: set accessed and dirty bits. */ - ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY) - sw k1,(k0) - /* Now reload the entry into the tlb */ - /* FIXME: Why has Ralf set bit 2? Should it be different for - * 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 - * has always an address with bit 2 set to zero. -- Ralf) - */ - ori k0,0x0004 - xori k0,0x0004 - lw k0,(k0) - srl k0,12 - mtc0 k0,CP0_ENTRYLO0 - mfc0 k1,CP0_EPC - nop # for pipeline - nop + /* Now reload the entry into the tlb. */ + PTE_RELOAD(k1) nop tlbwi - nop # for pipeline nop + mfc0 k0, CP0_EPC nop - - jr k1 + jr k0 rfe - END(r2300_handle_mod) - .set at +#endif + +nowrite_mod: + DO_FAULT(1) +END(r2300_handle_mod) diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S --- v2.2.10/linux/arch/mips/kernel/r2300_switch.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r2300_switch.S Mon Aug 9 12:04:38 1999 @@ -1,12 +1,15 @@ -/* - * r2300_switch.S: R3000/R2000 specific task switching code. +/* $Id: r2300_switch.S,v 1.6 1999/06/13 16:30:32 ralf Exp $ + * + * r2300_switch.S: R2300 specific task switching code. * - * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse + * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle + * Copyright (C) 1994, 1995, 1996 by Andreas Busse * * Multi-cpu abstraction and macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r2300_switch.S,v 1.4 1998/04/04 13:59:38 ralf Exp $ + * Further modifications to make this work: + * Copyright (c) 1998 Harald Koerfgen */ #include #include @@ -15,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -23,68 +27,137 @@ #include -/* XXX The following is fucking losing... find a better way dave. */ -MODE_ALIAS = 0x00e0 # uncachable, dirty, valid - - .text .set mips1 - .set noreorder + .align 5 + /* - * Code necessary to switch tasks on an Linux/MIPS machine. - * FIXME: We don't need to disable interrupts anymore. + * task_struct *r4xx0_resume(task_struct *prev, + * task_struct *next) */ - .align 5 - LEAF(r2300_resume) - mfc0 t1,CP0_STATUS # Save status register - sw t1,THREAD_STATUS($28) - ori t2,t1,0x1f # Disable interrupts - xori t2,0x1e - mtc0 t2,CP0_STATUS - CPU_SAVE_NONSCRATCH($28) - sll t2,t1,2 # Save floating point state - bgez t2,1f - sw ra,THREAD_REG31($28) - FPU_SAVE($28, t0) -1: - move $28, a0 - lw t0,THREAD_PGDIR($28) # Switch the root pointer - li t1,TLB_ROOT # get PFN - mtc0 t1,CP0_ENTRYHI - mtc0 zero,CP0_INDEX - srl t0,12 # PFN is 12 bits west - ori t0,MODE_ALIAS # want uncachable, dirty, valid - mtc0 t0,CP0_ENTRYLO0 - lw a2,THREAD_STATUS($28) - tlbwi - - /* Flush TLB. */ - mfc0 t3,CP0_STATUS # disable interrupts... - ori t4,t3,1 - xori t4,1 - mtc0 t4,CP0_STATUS - lw t0,mips_tlb_entries - mtc0 zero,CP0_ENTRYLO0 -1: - subu t0,1 - mtc0 t0,CP0_INDEX - lui t1,0x0008 - or t1,t0,t1 - sll t1,12 - mtc0 t1,CP0_ENTRYHI - bne t2,t0,1b - tlbwi - - ori t1,a2,1 # Restore FPU, pipeline magic - xori t1,1 - mtc0 t1,CP0_STATUS - sll t0,a2,2 - bgez t0,1f - lw ra,THREAD_REG31($28) - FPU_RESTORE($28, t0) -1: +LEAF(r2300_resume) + .set reorder + mfc0 t1, CP0_STATUS + .set noreorder + sw t1, THREAD_STATUS(a0) + CPU_SAVE_NONSCRATCH(a0) + sw ra, THREAD_REG31(a0) + + /* + * The order of restoring the registers takes care of the race + * updating $28, $29 and kernelsp without disabling ints. + */ + move $28, a1 CPU_RESTORE_NONSCRATCH($28) addiu t0, $28, KERNEL_STACK_SIZE-32 - sw t0,kernelsp + sw t0, kernelsp + mfc0 t1, CP0_STATUS /* Do we really need this? */ + li a3, 0xff00 + and t1, a3 + lw a2, THREAD_STATUS($28) + nor a3, $0, a3 + and a2, a3 + lw a3, TASK_MM($28) + or a2, t1 + lw a3, MM_CONTEXT(a3) + mtc0 a2, CP0_STATUS + andi a3, 0xfc0 + mtc0 a3, CP0_ENTRYHI jr ra - mtc0 a2,CP0_STATUS # Restore status register + move v0, a0 END(r2300_resume) + +/* + * Do lazy fpu context switch. Saves FPU context to the process in a0 + * and loads the new context of the current process. + */ + +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +LEAF(r2300_lazy_fpu_switch) + mfc0 t0, CP0_STATUS # enable cp1 + li t3, 0x20000000 + or t0, t3 + mtc0 t0, CP0_STATUS + + beqz a0, 2f # Save floating point state + nor t3, zero, t3 + .set reorder + lw t1, ST_OFF(a0) # last thread looses fpu + .set noreorder + and t1, t3 + sw t1, ST_OFF(a0) + swc1 $f0, (THREAD_FPU + 0x00)(a0) + FPU_SAVE(a0, t1) # clobbers t1 + +2: + lwc1 $f0, (THREAD_FPU + 0x00)($28) + .set reorder + FPU_RESTORE($28, t0) # clobbers t0 + jr ra + END(r2300_lazy_fpu_switch) + +/* + * Save a thread's fp context. + */ + .set noreorder +LEAF(r2300_save_fp) + FPU_SAVE(a0, t1) # clobbers t1 + jr ra + swc1 $f0, (THREAD_FPU + 0x00)(a0) + END(r2300_save_fp) + +/* + * 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. + * + * We initialize fcr31 to rounding to nearest, no exceptions. + */ + +#define FPU_DEFAULT 0x00000000 + +LEAF(r2300_init_fpu) + mfc0 t0, CP0_STATUS + li t1, 0x20000000 + or t0, t1 + mtc0 t0, CP0_STATUS + + li t1, FPU_DEFAULT + ctc1 t1, fcr31 + + li t0, -1 + + mtc1 t0, $f0 + mtc1 t0, $f1 + mtc1 t0, $f2 + mtc1 t0, $f3 + mtc1 t0, $f4 + mtc1 t0, $f5 + mtc1 t0, $f6 + mtc1 t0, $f7 + mtc1 t0, $f8 + mtc1 t0, $f9 + mtc1 t0, $f10 + mtc1 t0, $f11 + mtc1 t0, $f12 + mtc1 t0, $f13 + mtc1 t0, $f14 + mtc1 t0, $f15 + mtc1 t0, $f16 + mtc1 t0, $f17 + mtc1 t0, $f18 + mtc1 t0, $f19 + mtc1 t0, $f20 + mtc1 t0, $f21 + mtc1 t0, $f22 + mtc1 t0, $f23 + mtc1 t0, $f24 + mtc1 t0, $f25 + mtc1 t0, $f26 + mtc1 t0, $f27 + mtc1 t0, $f28 + mtc1 t0, $f29 + mtc1 t0, $f30 + jr ra + mtc1 t0, $f31 + END(r2300_init_fpu) diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S --- v2.2.10/linux/arch/mips/kernel/r4k_fpu.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r4k_fpu.S Mon Aug 9 12:04:38 1999 @@ -10,7 +10,7 @@ * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r4k_fpu.S,v 1.4 1998/04/04 13:59:38 ralf Exp $ + * $Id: r4k_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $ */ #include #include @@ -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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S --- v2.2.10/linux/arch/mips/kernel/r4k_misc.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r4k_misc.S Mon Aug 9 12:04:38 1999 @@ -6,14 +6,13 @@ * Multi-cpu abstraction and reworking: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r4k_misc.S,v 1.3 1997/09/07 04:51:07 ralf Exp $ + * $Id: r4k_misc.S,v 1.4 1997/12/01 17:57:30 ralf Exp $ */ #include #include #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/r4k_switch.S linux/arch/mips/kernel/r4k_switch.S --- v2.2.10/linux/arch/mips/kernel/r4k_switch.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r4k_switch.S Mon Aug 9 12:04:38 1999 @@ -1,10 +1,10 @@ -/* $Id: r4k_switch.S,v 1.4 1998/07/14 09:15:33 ralf Exp $ +/* $Id: r4k_switch.S,v 1.7 1999/06/13 16:30:32 ralf Exp $ * * 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. * - * Copyright (C) 1994, 1995, 1996, 1998 by Ralf Baechle + * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1994, 1995, 1996, by Andreas Busse */ @@ -24,30 +24,41 @@ #include +/* + * task_struct *r4xx0_resume(task_struct *prev, + * task_struct *next) + */ .set noreorder .set mips3 .align 5 LEAF(r4xx0_resume) mfc0 t1, CP0_STATUS - sw t1, THREAD_STATUS($28) - CPU_SAVE_NONSCRATCH($28) - sw ra, THREAD_REG31($28) + sw t1, THREAD_STATUS(a0) + CPU_SAVE_NONSCRATCH(a0) + sw ra, THREAD_REG31(a0) /* * The order of restoring the registers takes care of the race * updating $28, $29 and kernelsp without disabling ints. */ - move $28, a0 + move $28, a1 CPU_RESTORE_NONSCRATCH($28) addiu t0, $28, KERNEL_STACK_SIZE-32 sw t0, kernelsp - lw a3, TASK_MM($28) + mfc0 t1, CP0_STATUS /* Do we really need this? */ + li a3, 0xff00 + and t1, a3 lw a2, THREAD_STATUS($28) + nor a3, $0, a3 + and a2, a3 + lw a3, TASK_MM($28) + or a2, t1 lw a3, MM_CONTEXT(a3) mtc0 a2, CP0_STATUS andi a3, a3, 0xff + mtc0 a3, CP0_ENTRYHI jr ra - mtc0 a3, CP0_ENTRYHI + move v0, a0 END(r4xx0_resume) /* @@ -104,8 +115,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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S --- v2.2.10/linux/arch/mips/kernel/r6000_fpu.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/r6000_fpu.S Mon Aug 9 12:04:38 1999 @@ -10,7 +10,7 @@ * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r6000_fpu.S,v 1.3 1997/12/01 16:56:56 ralf Exp $ + * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $ */ #include #include @@ -19,6 +19,7 @@ #include .set noreorder + .set mips2 /* Save floating point context */ LEAF(r6000_save_fp_context) mfc0 t0,CP0_STATUS @@ -50,11 +51,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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/scall_o32.S linux/arch/mips/kernel/scall_o32.S --- v2.2.10/linux/arch/mips/kernel/scall_o32.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/scall_o32.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: scall_o32.S,v 1.5 1998/08/19 21:53:50 ralf Exp $ +/* $Id: scall_o32.S,v 1.4 1998/06/25 20:01:01 ralf Exp $ * * 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 @@ -44,6 +44,7 @@ beqz t2, illegal_syscall; subu t0, t3, 5 # 5 or more arguments? + sw a3, PT_R26(sp) # save a3 for syscall restarting bgez t0, stackargs stack_done: diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.2.10/linux/arch/mips/kernel/setup.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/setup.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.12 1998/08/18 20:45:06 ralf Exp $ +/* $Id: setup.c,v 1.15.2.2 1999/06/17 12:06:39 ralf Exp $ * * 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 @@ -29,7 +29,6 @@ #include #endif #ifdef CONFIG_RTC -#include #include #endif @@ -76,7 +75,6 @@ * information is being use to continue the screen output just below * the BIOS printed text and with the same text resolution. */ -struct drive_info_struct drive_info = DEFAULT_DRIVE_INFO; struct screen_info screen_info = DEFAULT_SCREEN_INFO; #ifdef CONFIG_BLK_DEV_FD @@ -92,39 +90,25 @@ extern struct rtc_ops no_rtc_ops; struct rtc_ops *rtc_ops; +extern struct kbd_ops no_kbd_ops; +struct kbd_ops *kbd_ops; + /* * 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; unsigned long mips_machtype = MACH_UNKNOWN; unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; -unsigned long mips_tlb_entries = 48; /* Guess which CPU I've got :) */ -unsigned long mips_vram_base = KSEG0; unsigned char aux_device_present; -extern int root_mountflags; extern int _end; -extern char empty_zero_page[PAGE_SIZE]; - -/* - * This is set up by the setup-routine at boot-time - */ -#define PARAM empty_zero_page -#if 0 -#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC)) -#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) -#endif -#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) -#define KERNEL_START (*(unsigned long *) (PARAM+0x214)) -#define INITRD_START (*(unsigned long *) (PARAM+0x218)) -#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) - static char command_line[CL_SIZE] = { 0, }; char saved_command_line[CL_SIZE]; +extern char arcs_cmdline[CL_SIZE]; /* * The board specific setup routine sets irq_setup to point to a board @@ -153,7 +137,11 @@ unsigned long * memory_start_p, unsigned long * memory_end_p)) { unsigned long memory_end; - tag* atag; +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long *initrd_header; +#endif + void baget_setup(void); void cobalt_setup(void); void decstation_setup(void); void deskstation_setup(void); @@ -161,18 +149,6 @@ void sni_rm200_pci_setup(void); void sgi_setup(void); - /* Perhaps a lot of tags are not getting 'snarfed' - */ - /* please help yourself */ - - atag = bi_TagFind(tag_machtype); - memcpy(&mips_machtype, TAGVALPTR(atag), atag->size); - - atag = bi_TagFind(tag_machgroup); - memcpy(&mips_machgroup, TAGVALPTR(atag), atag->size); - - atag = bi_TagFind(tag_vram_base); - memcpy(&mips_vram_base, TAGVALPTR(atag), atag->size); - /* Save defaults for configuration-dependent routines. */ irq_setup = default_irq_setup; @@ -185,14 +161,25 @@ #endif rtc_ops = &no_rtc_ops; + kbd_ops = &no_kbd_ops; switch(mips_machgroup) { +#ifdef CONFIG_BAGET_MIPS + case MACH_GROUP_UNKNOWN: + baget_setup(); + break; +#endif #ifdef CONFIG_COBALT_MICRO_SERVER case MACH_GROUP_COBALT: cobalt_setup(); break; #endif +#ifdef CONFIG_DECSTATION + case MACH_GROUP_DEC: + decstation_setup(); + break; +#endif #ifdef CONFIG_MIPS_JAZZ case MACH_GROUP_JAZZ: jazz_setup(); @@ -212,9 +199,6 @@ panic("Unsupported architecture"); } - atag = bi_TagFind(tag_drive_info); - memcpy(&drive_info, TAGVALPTR(atag), atag->size); - memory_end = mips_memory_upper; /* * Due to prefetching and similar mechanism the CPU sometimes @@ -225,20 +209,7 @@ memory_end -= 128; memory_end &= PAGE_MASK; -#ifdef CONFIG_BLK_DEV_RAM - rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; - rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); - rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); -#endif - - atag = bi_TagFind(tag_mount_root_rdonly); - if (atag) - root_mountflags |= MS_RDONLY; - - atag = bi_TagFind(tag_command_line); - if (atag) - memcpy(&command_line, TAGVALPTR(atag), atag->size); - + strncpy (command_line, arcs_cmdline, CL_SIZE); memcpy(saved_command_line, command_line, CL_SIZE); saved_command_line[CL_SIZE-1] = '\0'; @@ -247,15 +218,21 @@ *memory_end_p = memory_end; #ifdef CONFIG_BLK_DEV_INITRD - if (LOADER_TYPE) { - initrd_start = INITRD_START; - initrd_end = INITRD_START+INITRD_SIZE; + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + initrd_below_start_ok = 1; if (initrd_end > memory_end) { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", initrd_end,memory_end); - initrd_start = 0; - } + initrd_start = 0; + } else + *memory_start_p = initrd_end; } #endif } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.2.10/linux/arch/mips/kernel/signal.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/signal.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.24 1998/09/16 22:50:42 ralf Exp $ +/* $Id: signal.c,v 1.18.2.1 1999/06/17 12:06:40 ralf Exp $ * * linux/arch/mips/kernel/signal.c * @@ -392,6 +392,7 @@ } /* fallthrough */ case ERESTARTNOINTR: /* Userland will reload $v0. */ + regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 8; } @@ -491,6 +492,7 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: lock_kernel(); if (current->binfmt && current->binfmt->core_dump @@ -502,6 +504,7 @@ default: lock_kernel(); sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ @@ -524,6 +527,7 @@ if (regs->regs[2] == ERESTARTNOHAND || regs->regs[2] == ERESTARTSYS || regs->regs[2] == ERESTARTNOINTR) { + regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 8; } } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/softfp.S linux/arch/mips/kernel/softfp.S --- v2.2.10/linux/arch/mips/kernel/softfp.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/softfp.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: softfp.S,v 1.1 1998/07/14 09:33:48 ralf Exp $ +/* $Id: softfp.S,v 1.1 1998/07/16 19:10:02 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c --- v2.2.10/linux/arch/mips/kernel/syscall.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/syscall.c Mon Aug 9 12:04:38 1999 @@ -1,10 +1,10 @@ -/* $Id: syscall.c,v 1.10 1998/08/20 14:38:40 ralf Exp $ +/* $Id: syscall.c,v 1.10 1999/02/15 02:16:52 ralf Exp $ * * 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. * - * Copyright (C) 1995 - 1998 by Ralf Baechle + * Copyright (C) 1995 - 1999 by Ralf Baechle * * TODO: Implement the compatibility syscalls. * Don't waste that much memory for empty entries in the syscall @@ -80,11 +80,10 @@ asmlinkage int sys_idle(void) { unsigned long start_idle = 0; - int ret = -EPERM; - lock_kernel(); if (current->pid != 0) - goto out; + return -EPERM; + /* endless idle loop with no priority at all */ current->priority = 0; current->counter = 0; @@ -110,10 +109,8 @@ start_idle = 0; schedule(); } - ret = 0; -out: - unlock_kernel(); - return ret; + + return 0; } asmlinkage int sys_fork(struct pt_regs regs) @@ -121,9 +118,7 @@ int res; save_static(®s); - lock_kernel(); res = do_fork(SIGCHLD, regs.regs[29], ®s); - unlock_kernel(); return res; } @@ -134,13 +129,11 @@ int res; save_static(®s); - lock_kernel(); clone_flags = regs.regs[4]; newsp = regs.regs[5]; if (!newsp) newsp = regs.regs[29]; res = do_fork(clone_flags, newsp, ®s); - unlock_kernel(); return res; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h --- v2.2.10/linux/arch/mips/kernel/syscalls.h Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/syscalls.h Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: syscalls.h,v 1.16 1998/09/16 22:50:43 ralf Exp $ +/* $Id: syscalls.h,v 1.15 1998/09/19 19:16:17 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.2.10/linux/arch/mips/kernel/sysirix.c Sat May 8 11:14:01 1999 +++ linux/arch/mips/kernel/sysirix.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: sysirix.c,v 1.12 1998/08/17 10:16:27 ralf Exp $ +/* $Id: sysirix.c,v 1.19 1999/06/13 16:30:33 ralf Exp $ * * sysirix.c: IRIX system call emulation. * @@ -172,7 +172,7 @@ case PR_RESIDENT: printk("irix_prctl[%s:%ld]: Wants PR_RESIDENT\n", current->comm, current->pid); - error = 0; /* Compatability indeed. */ + error = 0; /* Compatibility indeed. */ break; case PR_ATTACHADDR: @@ -734,8 +734,9 @@ struct statfs kbuf; int error, i; - /* We don't support this feature yet. */ lock_kernel(); + + /* We don't support this feature yet. */ if(fs_type) { error = -EINVAL; goto out; @@ -1622,8 +1623,7 @@ __put_user(0, &buf->f_basetype[i]); __put_user(0, &buf->f_flag); __put_user(kbuf.f_namelen, &buf->f_namemax); - for(i = 0; i < 32; i++) - __put_user(0, &buf->f_fstr[i]); + __clear_user(&buf->f_fstr, sizeof(buf->f_fstr)); out_f: fput(file); @@ -1917,8 +1917,8 @@ __put_user(0, &buf->f_basetype[i]); __put_user(0, &buf->f_flag); __put_user(kbuf.f_namelen, &buf->f_namemax); - for(i = 0; i < 32; i++) - __put_user(0, &buf->f_fstr[i]); + __clear_user(buf->f_fstr, sizeof(buf->f_fstr[i])); + out_f: fput(file); out: @@ -1983,22 +1983,21 @@ #define NAME_OFFSET32(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) -static int irix_filldir32(void *__buf, const char *name, int namlen, off_t offset, ino_t ino) +static int irix_filldir32(void *__buf, const char *name, int namlen, + off_t offset, ino_t ino) { struct irix_dirent32 *dirent; - struct irix_dirent32_callback *buf = (struct irix_dirent32_callback *)__buf; + struct irix_dirent32_callback *buf = + (struct irix_dirent32_callback *)__buf; unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); - int retval; #ifdef DEBUG_GETDENTS printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", reclen, namlen, buf->count); #endif buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) { - retval = -EINVAL; - goto out; - } + if (reclen > buf->count) + return -EINVAL; dirent = buf->previous; if (dirent) __put_user(offset, &dirent->d_off); @@ -2012,10 +2011,7 @@ buf->current_dir = dirent; buf->count -= reclen; - retval = 0; - -out: - return retval; + return 0; } asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) @@ -2040,10 +2036,6 @@ if (!inode) goto out_putf; - inode = dentry->d_inode; - if (!inode) - goto out_putf; - buf.current_dir = (struct irix_dirent32 *) dirent; buf.previous = NULL; buf.count = count; @@ -2111,13 +2103,10 @@ struct irix_dirent64_callback * buf = (struct irix_dirent64_callback *) __buf; unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1); - int retval; buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) { - retval = -EINVAL; - goto out; - } + if (reclen > buf->count) + return -EINVAL; dirent = buf->previous; if (dirent) __put_user(offset, &dirent->d_off); @@ -2125,15 +2114,13 @@ buf->previous = dirent; __put_user(ino, &dirent->d_ino); __put_user(reclen, &dirent->d_reclen); - copy_to_user(dirent->d_name, name, namlen); + __copy_to_user(dirent->d_name, name, namlen); __put_user(0, &dirent->d_name[namlen]); ((char *) dirent) += reclen; buf->curr = dirent; buf->count -= reclen; - retval = 0; -out: - return retval; + return 0; } asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) @@ -2437,3 +2424,4 @@ return -ENOSYS; } + diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c --- v2.2.10/linux/arch/mips/kernel/sysmips.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/sysmips.c Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (C) 1995, 1996, 1997 by Ralf Baechle * - * $Id: sysmips.c,v 1.4 1998/05/07 15:20:05 ralf Exp $ + * $Id: sysmips.c,v 1.6 1998/08/25 09:14:42 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c --- v2.2.10/linux/arch/mips/kernel/time.c Thu Mar 11 23:25:19 1999 +++ linux/arch/mips/kernel/time.c Mon Aug 9 12:04:38 1999 @@ -1,16 +1,12 @@ -/* - * linux/arch/mips/kernel/time.c +/* $Id: time.c,v 1.12 1999/06/13 16:30:34 ralf Exp $ * * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1996, 1997, 1998 Ralf Baechle * * This file contains the time handling details for PC-style clocks as * found in some MIPS systems. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * - * $Id: time.c,v 1.6 1998/08/17 13:57:44 ralf Exp $ */ +#include #include #include #include @@ -67,7 +63,7 @@ quotient = cached_quotient; - if (last_jiffies != tmp) { + if (tmp && last_jiffies != tmp) { last_jiffies = tmp; __asm__(".set\tnoreorder\n\t" ".set\tnoat\n\t" @@ -340,6 +336,25 @@ static void inline timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { +#ifdef CONFIG_PROFILE + if(!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long pc = regs->cp0_epc; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Dont ignore out-of-bounds pc values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len-1) + pc = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } + } +#endif do_timer(regs); /* @@ -375,6 +390,16 @@ timerlo = count; timer_interrupt(irq, dev_id, regs); + + if (!jiffies) + { + /* + * If jiffies has overflowed in this timer_interrupt we must + * update the timer[hi]/[lo] to make do_fast_gettimeoffset() + * quotient calc still valid. -arca + */ + timerhi = timerlo = 0; + } } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -456,7 +481,7 @@ __initfunc(void time_init(void)) { - unsigned int year, mon, day, hour, min, sec; + unsigned int epoch, year, mon, day, hour, min, sec; int i; /* The Linux interpretation of the CMOS clock register contents: @@ -488,13 +513,17 @@ BCD_TO_BIN(mon); BCD_TO_BIN(year); } -#if 0 /* the IBM way */ - if ((year += 1900) < 1970) - year += 100; -#else - /* Acer PICA clock starts from 1980. True for all MIPS machines? */ - year += 1980; -#endif + + /* Attempt to guess the epoch. This is the same heuristic as in rtc.c so + no stupid things will happen to timekeeping. Who knows, maybe Ultrix + also uses 1952 as epoch ... */ + if (year > 10 && year < 44) { + epoch = 1980; + } else if (year < 96) { + epoch = 1952; + } + year += epoch; + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c --- v2.2.10/linux/arch/mips/kernel/traps.c Tue Jan 5 11:13:56 1999 +++ linux/arch/mips/kernel/traps.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.20 1998/10/14 20:26:26 ralf Exp $ +/* $Id: traps.c,v 1.20 1999/06/13 16:30:34 ralf Exp $ * * 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 @@ -202,17 +202,16 @@ * Assume it would be too dangerous to continue ... */ force_sig(SIGBUS, current); +show_regs(regs); while(1); } void do_ibe(struct pt_regs *regs) { -show_regs(regs); while(1); ibe_board_handler(regs); } void do_dbe(struct pt_regs *regs) { -show_regs(regs); while(1); dbe_board_handler(regs); } @@ -325,7 +324,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); } @@ -341,7 +340,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); } @@ -465,8 +464,8 @@ extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc); extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc); -extern asmlinkage void r4xx0_resume(void *tsk); -extern asmlinkage void r2300_resume(void *tsk); +extern asmlinkage void *r4xx0_resume(void *last, void *next); +extern asmlinkage void *r2300_resume(void *last, void *next); __initfunc(void trap_init(void)) { diff -u --recursive --new-file v2.2.10/linux/arch/mips/kernel/unaligned.c linux/arch/mips/kernel/unaligned.c --- v2.2.10/linux/arch/mips/kernel/unaligned.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/unaligned.c Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (C) 1996, 1998 by Ralf Baechle * - * $Id: unaligned.c,v 1.5 1998/08/17 13:57:44 ralf Exp $ + * $Id: unaligned.c,v 1.5 1999/05/01 22:40:39 ralf Exp $ * * This file contains exception handler for address error exception with the * special capability to execute faulting instructions in software. The @@ -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 --recursive --new-file v2.2.10/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile --- v2.2.10/linux/arch/mips/lib/Makefile Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/Makefile Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.12 1998/05/28 03:17:57 ralf Exp $ +# $Id: Makefile,v 1.9 1999/01/04 16:03:50 ralf Exp $ # # Makefile for MIPS-specific library files.. # @@ -10,7 +10,7 @@ L_TARGET = lib.a L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ - floppy-no.o ide-std.o ide-no.o rtc-std.o rtc-no.o memset.o memcpy.o \ - strlen_user.o strncpy_user.o tags.o watch.o + floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ + rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o watch.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/csum_partial.S linux/arch/mips/lib/csum_partial.S --- v2.2.10/linux/arch/mips/lib/csum_partial.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/csum_partial.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: csum_partial.S,v 1.3 1998/05/07 14:17:45 ralf Exp $ +/* $Id: csum_partial.S,v 1.2 1998/05/07 23:44:01 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/lib/csum_partial_copy.c linux/arch/mips/lib/csum_partial_copy.c --- v2.2.10/linux/arch/mips/lib/csum_partial_copy.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/csum_partial_copy.c Mon Aug 9 12:04:38 1999 @@ -14,7 +14,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $ + * $Id: csum_partial_copy.c,v 1.2 1998/09/19 19:16:17 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/floppy-std.c linux/arch/mips/lib/floppy-std.c --- v2.2.10/linux/arch/mips/lib/floppy-std.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/floppy-std.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: floppy-std.c,v 1.2 1998/05/28 03:17:57 ralf Exp $ +/* $Id: floppy-std.c,v 1.3 1998/10/28 12:38:13 ralf Exp $ * * 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 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/ide-no.c linux/arch/mips/lib/ide-no.c --- v2.2.10/linux/arch/mips/lib/ide-no.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/ide-no.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: ide-no.c,v 1.2 1998/05/28 03:17:57 ralf Exp $ +/* $Id: ide-no.c,v 1.2.2.2 1999/06/17 12:06:40 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/lib/ide-std.c linux/arch/mips/lib/ide-std.c --- v2.2.10/linux/arch/mips/lib/ide-std.c Tue Aug 4 16:06:57 1998 +++ linux/arch/mips/lib/ide-std.c Mon Aug 9 12:04:38 1999 @@ -1,5 +1,4 @@ -/* - * include/asm-mips/types.h +/* $Id: ide-std.c,v 1.3.2.2 1999/06/17 12:06:41 ralf Exp $ * * 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 @@ -9,6 +8,8 @@ * * Copyright (C) 1998 by Ralf Baechle */ +#include +#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/kbd-no.c linux/arch/mips/lib/kbd-no.c --- v2.2.10/linux/arch/mips/lib/kbd-no.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/lib/kbd-no.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,63 @@ +/* $Id: kbd-no.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ + * + * 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. + * + * Stub keyboard and psaux routines to keep Linux from crashing on machines + * without a keyboard. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include + +static void no_kbd_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int no_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static int no_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static void no_aux_free_irq(void) +{ +} + +static unsigned char no_kbd_read_input(void) +{ + return 0; +} + +static void no_kbd_write_output(unsigned char val) +{ +} + +static void no_kbd_write_command(unsigned char val) +{ +} + +static unsigned char no_kbd_read_status(void) +{ + return 0; +} + +struct kbd_ops no_kbd_ops = { + no_kbd_request_region, + no_kbd_request_irq, + + no_aux_request_irq, + no_aux_free_irq, + + no_kbd_read_input, + no_kbd_write_output, + no_kbd_write_command, + no_kbd_read_status +}; diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/kbd-std.c linux/arch/mips/lib/kbd-std.c --- v2.2.10/linux/arch/mips/lib/kbd-std.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/lib/kbd-std.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,81 @@ +/* $Id: kbd-std.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ + * + * 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. + * + * Routines for standard PC style keyboards accessible via I/O ports. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include +#include +#include +#include + +#define KEYBOARD_IRQ 1 +#define AUX_IRQ 12 + +static void std_kbd_request_region(void) +{ + request_region(0x60, 16, "keyboard"); +} + +static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int std_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(AUX_IRQ, handler, 0, "PS/2 Mouse", NULL); +} + +static void std_aux_free_irq(void) +{ + free_irq(AUX_IRQ, NULL); +} + +static unsigned char std_kbd_read_input(void) +{ + return inb(KBD_DATA_REG); +} + +static void std_kbd_write_output(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_DATA_REG); +} + +static void std_kbd_write_command(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_CNTL_REG); +} + +static unsigned char std_kbd_read_status(void) +{ + return inb(KBD_STATUS_REG); +} + +struct kbd_ops std_kbd_ops = { + std_kbd_request_region, + std_kbd_request_irq, + + std_aux_request_irq, + std_aux_free_irq, + + std_kbd_read_input, + std_kbd_write_output, + std_kbd_write_command, + std_kbd_read_status +}; diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/memcpy.S linux/arch/mips/lib/memcpy.S --- v2.2.10/linux/arch/mips/lib/memcpy.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/memcpy.S Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * $Id: memcpy.S,v 1.4 1998/07/03 14:05:33 ralf Exp $ + * $Id: memcpy.S,v 1.3 1998/07/10 01:14:49 ralf Exp $ * * Unified implementation of memcpy, memmove and the __copy_user backend. * For __rmemcpy and memmove an exception is always a kernel bug, therefore diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/memset.S linux/arch/mips/lib/memset.S --- v2.2.10/linux/arch/mips/lib/memset.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/memset.S Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (C) 1998 by Ralf Baechle * - * $Id: memset.S,v 1.2 1998/04/25 17:01:45 ralf Exp $ + * $Id: memset.S,v 1.1 1998/05/04 09:12:54 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/strlen_user.S linux/arch/mips/lib/strlen_user.S --- v2.2.10/linux/arch/mips/lib/strlen_user.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/strlen_user.S Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (c) 1996, 1998 by Ralf Baechle * - * $Id: strlen_user.S,v 1.3 1998/05/03 11:13:45 ralf Exp $ + * $Id: strlen_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/strncpy_user.S linux/arch/mips/lib/strncpy_user.S --- v2.2.10/linux/arch/mips/lib/strncpy_user.S Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/strncpy_user.S Mon Aug 9 12:04:38 1999 @@ -7,7 +7,7 @@ * * Copyright (c) 1996 by Ralf Baechle * - * $Id: strncpy_user.S,v 1.3 1998/05/03 11:13:45 ralf Exp $ + * $Id: strncpy_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/tags.c linux/arch/mips/lib/tags.c --- v2.2.10/linux/arch/mips/lib/tags.c Thu Jun 26 12:33:37 1997 +++ linux/arch/mips/lib/tags.c Wed Dec 31 16:00:00 1969 @@ -1,75 +0,0 @@ -/* - * linux/arch/mips/lib/tags.c - * - * Copyright (C) 1996 Stoned Elipot - */ -#include -#include -#include -#include -#include - -/* - * Parse the tags present in upper memory to find out - * a pecular one. - * - * Parameter: type - tag type to find - * - * returns : NULL - failure - * !NULL - pointer on the tag structure found - */ -tag * -bi_TagFind(enum bi_tag type) -{ - tag* t = (tag*)(mips_memory_upper - sizeof(tag)); - - while((t->tag != tag_dummy) && (t->tag != type)) - t = (tag*)(NEXTTAGPTR(t)); - - if (t->tag == tag_dummy) /* tag not found */ - return (tag*)NULL; - - return t; -} - -/* - * Snarf from the tag list in memory end some tags needed - * before the kernel reachs 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 - * in .data section of the kernel, so initialized in to whatever - * value in the kernel's sources. - */ -void bi_EarlySnarf(void) -{ - tag* atag; - - /* for wire_mappings() */ - atag = bi_TagFind(tag_machgroup); - if (atag) - memcpy(&mips_machgroup, TAGVALPTR(atag), atag->size); - else { - /* useless for boxes without text video mode but....*/ - panic("machine group not specified by bootloader"); - } - - atag = bi_TagFind(tag_machtype); - if (atag) - memcpy(&mips_machtype, TAGVALPTR(atag), atag->size); - else { - /* useless for boxes without text video mode but....*/ - panic("machine type not specified by bootloader"); - } - - /* for tlbflush() */ - atag = bi_TagFind(tag_tlb_entries); - if (atag) - memcpy(&mips_tlb_entries, TAGVALPTR(atag), atag->size); - else { - /* useless for boxes without text video mode but....*/ - panic("number of TLB entries not specified by bootloader"); - } - - return; -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/lib/watch.S linux/arch/mips/lib/watch.S --- v2.2.10/linux/arch/mips/lib/watch.S Thu Jun 26 12:33:37 1997 +++ linux/arch/mips/lib/watch.S Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile --- v2.2.10/linux/arch/mips/mm/Makefile Sat Aug 16 09:51:07 1997 +++ linux/arch/mips/mm/Makefile Mon Aug 9 12:04:38 1999 @@ -15,4 +15,8 @@ O_OBJS += umap.o endif +ifdef CONFIG_BAGET_MIPS +O_OBJS += umap.o +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c --- v2.2.10/linux/arch/mips/mm/andes.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/mm/andes.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: andes.c,v 1.6 1998/10/16 19:22:42 ralf Exp $ +/* $Id: andes.c,v 1.6 1999/01/04 16:03:52 ralf Exp $ * * andes.c: MMU and cache operations for the R10000 (ANDES). * diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.2.10/linux/arch/mips/mm/fault.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/mm/fault.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.12 1998/10/19 21:27:37 ralf Exp $ +/* $Id: fault.c,v 1.9 1999/01/04 16:03:53 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.2.10/linux/arch/mips/mm/init.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/mm/init.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.13 1998/10/16 19:22:42 ralf Exp $ +/* $Id: init.c,v 1.13 1999/05/01 22:40:40 ralf Exp $ * * 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 @@ -35,12 +35,6 @@ #endif #include -/* - * Define this to effectivly disable the userpage colouring shit. - */ -#define CONF_GIVE_A_SHIT_ABOUT_COLOURS - -extern void deskstation_tyne_dma_init(void); extern void show_net_buffers(void); void __bad_pte_kernel(pmd_t *pmd) @@ -59,7 +53,7 @@ { pte_t *page; - page = (pte_t *) __get_free_page(GFP_KERNEL); + page = (pte_t *) __get_free_page(GFP_USER); if (pmd_none(*pmd)) { if (page) { clear_page((unsigned long)page); @@ -126,6 +120,7 @@ case CPU_R4400SC: case CPU_R4400MC: order = 3; + break; default: order = 0; } @@ -137,6 +132,7 @@ pg = MAP_NR(empty_zero_page); while(pg < MAP_NR(empty_zero_page) + (1 << order)) { set_bit(PG_reserved, &mem_map[pg].flags); + atomic_set(&mem_map[pg].count, 0); pg++; } @@ -243,83 +239,6 @@ return pte_mkdirty(mk_pte(page, PAGE_SHARED)); } -#ifdef __SMP__ -spinlock_t user_page_lock = SPIN_LOCK_UNLOCKED; -#endif -struct upcache user_page_cache[8] __attribute__((aligned(32))); -static unsigned long user_page_order; -unsigned long user_page_colours; - -unsigned long get_user_page_slow(int which) -{ - unsigned long chunk; - struct upcache *up = &user_page_cache[0]; - struct page *p, *res; - int i; - - do { - chunk = __get_free_pages(GFP_KERNEL, user_page_order); - } while(chunk==0); - - p = mem_map + MAP_NR(chunk); - res = p + which; - spin_lock(&user_page_lock); - for (i=user_page_colours; i>=0; i--,p++,up++,chunk+=PAGE_SIZE) { - atomic_set(&p->count, 1); - p->age = PAGE_INITIAL_AGE; - - if (p != res) { - if(up->count < USER_PAGE_WATER) { - p->next = up->list; - up->list = p; - up->count++; - } else - free_pages(chunk, 0); - } - } - spin_unlock(&user_page_lock); - - return page_address(res); -} - -static inline void user_page_setup(void) -{ - unsigned long assoc = 0; - unsigned long dcache_log, icache_log, cache_log; - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - - switch(mips_cputype) { - case CPU_R4000SC: - case CPU_R4000MC: - case CPU_R4400SC: - case CPU_R4400MC: - cache_log = 3; /* => 32k, sucks */ - break; - - case CPU_R4600: /* two way set associative caches? */ - case CPU_R4700: - case CPU_R5000: - case CPU_NEVADA: - assoc = 1; - /* fall through */ - default: - /* use bigger cache */ - icache_log = (config >> 9) & 7; - dcache_log = (config >> 6) & 7; - if (dcache_log > icache_log) - cache_log = dcache_log; - else - cache_log = icache_log; - } - -#ifdef CONF_GIVE_A_SHIT_ABOUT_COLOURS - cache_log = assoc = 0; -#endif - - user_page_order = cache_log - assoc; - user_page_colours = (1 << (cache_log - assoc)) - 1; -} - void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -375,8 +294,9 @@ #endif end_mem &= PAGE_MASK; - max_mapnr = num_physpages = MAP_NR(end_mem); + max_mapnr = MAP_NR(end_mem); high_memory = (void *)end_mem; + num_physpages = 0; /* mark usable pages in the mem_map[] */ start_mem = PAGE_ALIGN(start_mem); @@ -384,15 +304,12 @@ for(tmp = MAP_NR(start_mem);tmp < max_mapnr;tmp++) clear_bit(PG_reserved, &mem_map[tmp].flags); - -#ifdef CONFIG_SGI prom_fixup_mem_map(start_mem, (unsigned long)high_memory); -#endif 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) @@ -406,6 +323,7 @@ datapages++; continue; } + num_physpages++; atomic_set(&mem_map[MAP_NR(tmp)].count, 1); #ifdef CONFIG_BLK_DEV_INITRD if (!initrd_start || (tmp < initrd_start || tmp >= @@ -423,9 +341,6 @@ max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); - - /* Initialize allocator for colour matched mapped pages. */ - user_page_setup(); } extern char __init_begin, __init_end; @@ -433,7 +348,9 @@ void free_initmem(void) { unsigned long addr; - + + prom_free_prom_memory (); + addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c --- v2.2.10/linux/arch/mips/mm/loadmmu.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/mm/loadmmu.c Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: loadmmu.c,v 1.7 1998/03/27 08:53:41 ralf Exp $ + * $Id: loadmmu.c,v 1.9.2.2 1999/06/17 12:06:42 ralf Exp $ */ #include #include @@ -53,7 +53,7 @@ int (*user_mode)(struct pt_regs *); -asmlinkage void (*resume)(void *tsk); +asmlinkage void *(*resume)(void *last, void *next); extern void ld_mmu_r2300(void); extern void ld_mmu_r4xx0(void); @@ -66,6 +66,7 @@ switch(mips_cputype) { case CPU_R2000: case CPU_R3000: + case CPU_R3000A: printk("Loading R[23]00 MMU routines.\n"); ld_mmu_r2300(); break; diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c --- v2.2.10/linux/arch/mips/mm/r2300.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/mm/r2300.c Mon Aug 9 12:04:38 1999 @@ -1,8 +1,13 @@ -/* $Id: r2300.c,v 1.7 1998/10/16 19:22:43 ralf Exp $ - * +/* * r2300.c: R2000 and R3000 specific mmu/cache code. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * with a lot of changes to make this thing work for R3000s + * Copyright (C) 1998 Harald Koerfgen + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + * + * $Id: r2300.c,v 1.8 1999/04/11 17:13:56 harald Exp $ */ #include #include @@ -11,12 +16,40 @@ #include #include +#include #include #include -#include +#include +#include +/* + * Temporarily disabled + * +#include + */ + +/* + * According to the paper written by D. Miller about Linux cache & TLB + * flush implementation, DMA/Driver coherence should be done at the + * driver layer. Thus, normally, we don't need flush dcache for R3000. + * Define this if driver does not handle cache consistency during DMA ops. + */ +#undef DO_DCACHE_FLUSH + +/* + * Unified cache space description structure + */ +static struct cache_space { + unsigned long ca_flags; /* Cache space access flags */ + int size; /* Cache space size */ +} icache, dcache; + +#undef DEBUG_TLB +#undef DEBUG_CACHE extern unsigned long mips_tlb_entries; +#define NTLB_ENTRIES 64 /* Fixed on all R23000 variants... */ + /* page functions */ void r2300_clear_page(unsigned long page) { @@ -94,80 +127,425 @@ "I" (PAGE_SIZE)); } -/* Cache operations. */ -static inline void r2300_flush_cache_all(void) { } -static void r2300_flush_cache_mm(struct mm_struct *mm) { } +__initfunc(static unsigned long size_cache(unsigned long ca_flags)) +{ + unsigned long flags, status, dummy, size; + volatile unsigned long *p; + + p = (volatile unsigned long *) KSEG0; + + save_and_cli(flags); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); + + *p = 0xa5a55a5a; + dummy = *p; + status = read_32bit_cp0_register(CP0_STATUS); + + if (dummy != 0xa5a55a5a || (status & (1<<19))) { + size = 0; + } else { + for (size = 512; size <= 0x40000; size <<= 1) + *(p + size) = 0; + *p = -1; + for (size = 512; + (size <= 0x40000) && (*(p + size) == 0); + size <<= 1) + ; + if (size > 0x40000) + size = 0; + } + restore_flags(flags); + + return size * sizeof(*p); +} + +__initfunc(static void probe_dcache(void)) +{ + dcache.size = size_cache(dcache.ca_flags = ST0_DE); + printk("Data cache %dkb\n", dcache.size >> 10); +} + +__initfunc(static void probe_icache(void)) +{ + icache.size = size_cache(icache.ca_flags = ST0_DE|ST0_CE); + printk("Instruction cache %dkb\n", icache.size >> 10); +} + +static inline unsigned long get_phys_page (unsigned long page, + struct mm_struct *mm) +{ + page &= PAGE_MASK; + if (page >= KSEG0 && page < KSEG1) { + /* + * We already have physical address + */ + return page; + } else { + if (!mm) { + printk ("get_phys_page: vaddr without mm\n"); + return 0; + } else { + /* + * Find a physical page using mm_struct + */ + pgd_t *page_dir; + pmd_t *page_middle; + pte_t *page_table, pte; + + unsigned long address = page; + + page_dir = pgd_offset(mm, address); + if (pgd_none(*page_dir)) + return 0; + page_middle = pmd_offset(page_dir, address); + if (pmd_none(*page_middle)) + return 0; + page_table = pte_offset(page_middle, address); + pte = *page_table; + if (!pte_present(pte)) + return 0; + return pte_page(pte); + } + } +} + +static inline void flush_cache_space_page(struct cache_space *space, + unsigned long page) +{ + register unsigned long i, flags, size = space->size; + register volatile unsigned char *p = (volatile unsigned char*) page; + +#ifndef DO_DCACHE_FLUSH + if (space == &dcache) + return; +#endif + if (size > PAGE_SIZE) + size = PAGE_SIZE; + + save_and_cli(flags); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (space->ca_flags|flags)&~ST0_IEC); + + for (i = 0; i < size; i += 64) { + asm ( "sb\t$0,(%0)\n\t" + "sb\t$0,4(%0)\n\t" + "sb\t$0,8(%0)\n\t" + "sb\t$0,12(%0)\n\t" + "sb\t$0,16(%0)\n\t" + "sb\t$0,20(%0)\n\t" + "sb\t$0,24(%0)\n\t" + "sb\t$0,28(%0)\n\t" + "sb\t$0,32(%0)\n\t" + "sb\t$0,36(%0)\n\t" + "sb\t$0,40(%0)\n\t" + "sb\t$0,44(%0)\n\t" + "sb\t$0,48(%0)\n\t" + "sb\t$0,52(%0)\n\t" + "sb\t$0,56(%0)\n\t" + "sb\t$0,60(%0)\n\t" + : : "r" (p) ); + p += 64; + } + + restore_flags(flags); +} + +static inline void flush_cache_space_all(struct cache_space *space) +{ + unsigned long page = KSEG0; + int size = space->size; + +#ifndef DO_DCACHE_FLUSH + if (space == &dcache) + return; +#endif + while(size > 0) { + flush_cache_space_page(space, page); + page += PAGE_SIZE; size -= PAGE_SIZE; + } +} + +static inline void r2300_flush_cache_all(void) +{ + flush_cache_space_all(&dcache); + flush_cache_space_all(&icache); +} + +static void r2300_flush_cache_mm(struct mm_struct *mm) +{ + if(mm->context == 0) + return; +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + /* + * This function is called not offen, so it looks + * enough good to flush all caches than scan mm_struct, + * count pages to flush (and, very probably, flush more + * than cache space size :-) + */ + flush_cache_all(); +} + static void r2300_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) { + /* + * In general, we need to flush both i- & d- caches here. + * Optimization: if cache space is less than given range, + * it is more quickly to flush all cache than all pages in range. + */ + + unsigned long page; + int icache_done = 0, dcache_done = 0; + + if(mm->context == 0) + return; +#ifdef DEBUG_CACHE + printk("crange[%d]", (int)mm->context); +#endif + if (end - start >= icache.size) { + flush_cache_space_all(&icache); + icache_done = 1; + } + if (end - start >= dcache.size) { + flush_cache_space_all(&dcache); + dcache_done = 1; + } + if (icache_done && dcache_done) + return; + + for (page = start; page < end; page += PAGE_SIZE) { + unsigned long phys_page = get_phys_page(page, mm); + + if (phys_page) { + if (!icache_done) + flush_cache_space_page(&icache, phys_page); + if (!dcache_done) + flush_cache_space_page(&dcache, phys_page); + } + } } static void r2300_flush_cache_page(struct vm_area_struct *vma, unsigned long page) { + struct mm_struct *mm = vma->vm_mm; + + if(mm->context == 0) + return; +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + /* + * User changes page, so we need to check: + * is icache page flush needed ? + * It looks we don't need to flush dcache, + * due it is write-transparent on R3000 + */ + if (vma->vm_flags & VM_EXEC) { + unsigned long phys_page = get_phys_page(page, vma->vm_mm); + if (phys_page) + flush_cache_space_page(&icache, phys_page); + } } static void r2300_flush_page_to_ram(unsigned long page) { - /* XXX What we want to do here is perform a displacement - * XXX flush because there are circumstances where you do - * XXX indeed want to remove stale data from the cache. - * XXX (DMA operations for example, where the cache cannot - * XXX "see" this data get changed.) + /* + * We need to flush both i- & d- caches :-( */ + unsigned long phys_page = get_phys_page(page, NULL); +#ifdef DEBUG_CACHE + printk("cram[%08lx]", page); +#endif + if (phys_page) { + flush_cache_space_page(&icache, phys_page); + flush_cache_space_page(&dcache, phys_page); + } +} + +static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) +{ + register unsigned long i, flags; + register volatile unsigned char *p = (volatile unsigned char*) start; + +/* + * Temporarily disabled + wbflush(); + */ + + /* + * Invalidate dcache + */ + if (size < 64) + size = 64; + + if (size > dcache.size) + size = dcache.size; + + save_and_cli(flags); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ST0_DE|flags)&~ST0_IEC); + + for (i = 0; i < size; i += 64) { + asm ( "sb\t$0,(%0)\n\t" + "sb\t$0,4(%0)\n\t" + "sb\t$0,8(%0)\n\t" + "sb\t$0,12(%0)\n\t" + "sb\t$0,16(%0)\n\t" + "sb\t$0,20(%0)\n\t" + "sb\t$0,24(%0)\n\t" + "sb\t$0,28(%0)\n\t" + "sb\t$0,32(%0)\n\t" + "sb\t$0,36(%0)\n\t" + "sb\t$0,40(%0)\n\t" + "sb\t$0,44(%0)\n\t" + "sb\t$0,48(%0)\n\t" + "sb\t$0,52(%0)\n\t" + "sb\t$0,56(%0)\n\t" + "sb\t$0,60(%0)\n\t" + : : "r" (p) ); + p += 64; + } + + restore_flags(flags); } static void r2300_flush_cache_sigtramp(unsigned long page) { + /* + * We need only flush i-cache here + * + * This function receives virtual address (from signal.c), + * but this moment we have needed mm_struct in 'current' + */ + unsigned long phys_page = get_phys_page(page, current->mm); +#ifdef DEBUG_CACHE + printk("csigtramp[%08lx]", page); +#endif + if (phys_page) + flush_cache_space_page(&icache, phys_page); } /* TLB operations. */ static inline void r2300_flush_tlb_all(void) { unsigned long flags; + unsigned long old_ctx; int entry; +#ifdef DEBUG_TLB + printk("[tlball]"); +#endif + save_and_cli(flags); + old_ctx = (get_entryhi() & 0xfc0); write_32bit_cp0_register(CP0_ENTRYLO0, 0); - for(entry = 0; entry < mips_tlb_entries; entry++) { - write_32bit_cp0_register(CP0_INDEX, entry); - write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x8) << 12)); + for(entry = 0; entry < NTLB_ENTRIES; entry++) { + write_32bit_cp0_register(CP0_INDEX, entry << 8); + write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12)); __asm__ __volatile__("tlbwi"); } + set_entryhi(old_ctx); restore_flags(flags); } static void r2300_flush_tlb_mm(struct mm_struct *mm) { + if(mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlbmm<%d>]", mm->context); +#endif + save_and_cli(flags); + get_new_mmu_context(mm, asid_cache); if(mm == current->mm) - r2300_flush_tlb_all(); + set_entryhi(mm->context & 0xfc0); + restore_flags(flags); + } } static void r2300_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { + if(mm->context != 0) { + unsigned long flags; + int size; + +#ifdef DEBUG_TLB + printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xfc0), + start, end); +#endif + save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if(size <= NTLB_ENTRIES) { + int oldpid = (get_entryhi() & 0xfc0); + int newpid = (mm->context & 0xfc0); + + start &= PAGE_MASK; + end += (PAGE_SIZE - 1); + end &= PAGE_MASK; + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += PAGE_SIZE; + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entryhi(KSEG0); + if(idx < 0) + continue; + tlb_write_indexed(); + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, asid_cache); if(mm == current->mm) - r2300_flush_tlb_all(); + set_entryhi(mm->context & 0xfc0); + } + restore_flags(flags); + } } static void r2300_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - if(vma->vm_mm == current->mm) - r2300_flush_tlb_all(); + if(vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); +#endif + newpid = (vma->vm_mm->context & 0xfc0); + page &= PAGE_MASK; + save_and_cli(flags); + oldpid = (get_entryhi() & 0xfc0); + set_entryhi(page | newpid); + tlb_probe(); + idx = get_index(); + set_entrylo0(0); + set_entryhi(KSEG0); + if(idx < 0) + goto finish; + tlb_write_indexed(); + +finish: + set_entryhi(oldpid); + restore_flags(flags); + } } /* Load a new root pointer into the TLB. */ static void r2300_load_pgd(unsigned long pg_dir) { - unsigned long flags; - - save_and_cli(flags); - write_32bit_cp0_register(CP0_ENTRYHI, TLB_ROOT); - write_32bit_cp0_register(CP0_INDEX, 0); - write_32bit_cp0_register(CP0_ENTRYLO0, ((pg_dir >> 6) | 0x00e0)); - __asm__ __volatile__("tlbwi"); - restore_flags(flags); } /* @@ -199,17 +577,63 @@ "=r" (dummy2) :"r" ((unsigned long) invalid_pte_table), "0" (page), - "1" (USER_PTRS_PER_PGD/8)); + "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); } static void r2300_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { - r2300_flush_tlb_page(vma, address); - /* - * FIXME: We should also reload a new entry into the TLB to - * avoid unnecessary exceptions. - */ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + pid = (get_entryhi() & 0xfc0); + +#ifdef DEBUG_TLB + if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (vma->vm_mm->context & 0xfc0), pid); + } +#endif + + save_and_cli(flags); + address &= PAGE_MASK; + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + tlb_probe(); + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + set_entrylo0(pte_val(*ptep)); + set_entryhi(address | (pid)); + if(idx < 0) { + tlb_write_random(); +#if 0 + printk("[MISS]"); +#endif + } else { + tlb_write_indexed(); +#if 0 + printk("[HIT]"); +#endif + } +#if 0 + if(!strcmp(current->comm, "args")) { + printk("<"); + for(idx = 0; idx < NTLB_ENTRIES; idx++) { + set_index(idx); + tlb_read(); + address = get_entryhi(); + if((address & 0xfc0) != 0) + printk("[%08lx]", address); + } + printk(">\n"); + } +#endif + set_entryhi(pid); + restore_flags(flags); } static void r2300_show_regs(struct pt_regs * regs) @@ -248,6 +672,7 @@ static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { +printk("r2300_add_wired_entry"); /* * FIXME, to be done */ @@ -255,14 +680,19 @@ static int r2300_user_mode(struct pt_regs *regs) { - return !(regs->cp0_status & 0x4); + return !(regs->cp0_status & ST0_KUP); } __initfunc(void ld_mmu_r2300(void)) { + printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); + clear_page = r2300_clear_page; copy_page = r2300_copy_page; + probe_icache(); + probe_dcache(); + flush_cache_all = r2300_flush_cache_all; flush_cache_mm = r2300_flush_cache_mm; flush_cache_range = r2300_flush_cache_range; @@ -274,16 +704,19 @@ flush_tlb_mm = r2300_flush_tlb_mm; flush_tlb_range = r2300_flush_tlb_range; flush_tlb_page = r2300_flush_tlb_page; - r3000_asid_setup(); + + dma_cache_wback_inv = r3k_dma_cache_wback_inv; load_pgd = r2300_load_pgd; pgd_init = r2300_pgd_init; update_mmu_cache = r2300_update_mmu_cache; + r3000_asid_setup(); show_regs = r2300_show_regs; add_wired_entry = r2300_add_wired_entry; user_mode = r2300_user_mode; + flush_tlb_all(); } diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c --- v2.2.10/linux/arch/mips/mm/r4xx0.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/mm/r4xx0.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.30 1998/10/16 19:22:43 ralf Exp $ +/* $Id: r4xx0.c,v 1.21.2.2 1999/06/17 12:06:42 ralf Exp $ * * 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 --recursive --new-file v2.2.10/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c --- v2.2.10/linux/arch/mips/mm/r6000.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/mm/r6000.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: r6000.c,v 1.6 1998/10/16 19:22:44 ralf Exp $ +/* $Id: r6000.c,v 1.6 1999/01/04 16:03:54 ralf Exp $ * * r6000.c: MMU and cache routines for the R6000 processors. * diff -u --recursive --new-file v2.2.10/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c --- v2.2.10/linux/arch/mips/mm/tfp.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/mm/tfp.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: tfp.c,v 1.6 1998/10/16 19:22:44 ralf Exp $ +/* $Id: tfp.c,v 1.6 1999/01/04 16:03:55 ralf Exp $ * * tfp.c: MMU and cache routines specific to the r8000 (TFP). * diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile --- v2.2.10/linux/arch/mips/sgi/kernel/Makefile Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/Makefile Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 1998/06/25 20:19:17 ralf Exp $ +# $Id: Makefile,v 1.7 1999/05/07 18:00:16 ulfc Exp $ # Makefile for the SGI specific kernel interface routines # under Linux. # @@ -13,8 +13,11 @@ .S.o: $(CC) $(CFLAGS) -c $< -o $*.o -OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \ - indy_timer.o indyIRQ.o reset.o setup.o time.o +OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \ + system.o indy_timer.o indyIRQ.o reset.o setup.o time.o +ifdef CONFIG_SGI_PROM_CONSOLE +OBJS += promcon.o +endif all: sgikern.a diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indyIRQ.S linux/arch/mips/sgi/kernel/indyIRQ.S --- v2.2.10/linux/arch/mips/sgi/kernel/indyIRQ.S Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/indyIRQ.S Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: indyIRQ.S,v 1.3 1998/03/21 22:39:53 ralf Exp $ +/* $Id: indyIRQ.S,v 1.3 1998/03/22 23:27:17 ralf Exp $ * indyIRQ.S: Interrupt exception dispatch code for FullHouse and * Guiness. * diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indy_hpc.c linux/arch/mips/sgi/kernel/indy_hpc.c --- v2.2.10/linux/arch/mips/sgi/kernel/indy_hpc.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/indy_hpc.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: indy_hpc.c,v 1.4 1998/07/14 09:12:27 ralf Exp $ +/* $Id: indy_hpc.c,v 1.6 1999/05/07 22:34:31 ulfc Exp $ * * indy_hpc.c: Routines for generic manipulation of the HPC controllers. * @@ -43,7 +43,8 @@ prom_printf("sgihpc_init: "); #endif - if(sid & 1) { + /* This test works now thanks to William J. Earl */ + if ((sid & 1) == 0 ) { #ifdef DEBUG_SGIHPC prom_printf("GUINESS "); #endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c --- v2.2.10/linux/arch/mips/sgi/kernel/indy_int.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/indy_int.c Mon Aug 9 12:04:38 1999 @@ -1,12 +1,14 @@ -/* $Id: indy_int.c,v 1.9 1998/05/28 03:18:00 ralf Exp $ +/* $Id: indy_int.c,v 1.13 1999/06/12 17:26:15 ulfc Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) + * - Indigo2 changes + * - Interrupt handling fixes */ -#include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include /* #define DEBUG_SGINT */ @@ -51,10 +54,6 @@ extern asmlinkage void indyIRQ(void); -#ifdef CONFIG_REMOTE_DEBUG -extern void rs_kgdb_hook(int); -#endif - unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; unsigned long spurious_count = 0; @@ -274,7 +273,7 @@ int do_random, cpu; cpu = smp_processor_id(); - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("Got irq %d, press a key.", irq); @@ -310,7 +309,7 @@ add_interrupt_randomness(irq); __cli(); } - irq_exit(cpu, irq); + hardirq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } @@ -448,10 +447,23 @@ action = local_irq_action[irq]; } - irq_enter(cpu, irq); + /* if irq == 0, then the interrupt has already been cleared */ + if ( irq == 0 ) { goto end; } + /* if action == NULL, then we do have a handler for the irq */ + if ( action == NULL ) { goto no_handler; } + + hardirq_enter(cpu); kstat.irqs[0][irq + 16]++; action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); + hardirq_exit(cpu); + goto end; + +no_handler: + printk("No handler for local0 irq: %i\n", irq); + +end: + return; + } void indy_local1_irqdispatch(struct pt_regs *regs) @@ -472,10 +484,23 @@ irq = lc1msk_to_irqnr[mask]; action = local_irq_action[irq]; } - irq_enter(cpu, irq); + /* if irq == 0, then the interrupt has already been cleared */ + /* not sure if it is needed here, but it is needed for local0 */ + if ( irq == 0 ) { goto end; } + /* if action == NULL, then we do have a handler for the irq */ + if ( action == NULL ) { goto no_handler; } + + hardirq_enter(cpu); kstat.irqs[0][irq + 24]++; action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); + hardirq_exit(cpu); + goto end; + +no_handler: + printk("No handler for local1 irq: %i\n", irq); + +end: + return; } void indy_buserror_irq(struct pt_regs *regs) @@ -483,13 +508,13 @@ int cpu = smp_processor_id(); int irq = 6; - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("Got a bus error IRQ, shouldn't happen yet\n"); show_regs(regs); printk("Spinning...\n"); while(1); - irq_exit(cpu, irq); + hardirq_exit(cpu); } /* Misc. crap just to keep the kernel linking... */ @@ -506,9 +531,6 @@ __initfunc(void sgint_init(void)) { int i; -#ifdef CONFIG_REMOTE_DEBUG - char *ctype; -#endif sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE); sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE); @@ -563,9 +585,16 @@ } } - ioc_icontrol = &sgi_i3regs->ints; - ioc_timers = &sgi_i3regs->timers; - ioc_tclear = &sgi_i3regs->tclear; + /* Indy uses an INT3, Indigo2 uses an INT2 */ + if (sgi_guiness) { + ioc_icontrol = &sgi_i3regs->ints; + ioc_timers = &sgi_i3regs->timers; + ioc_tclear = &sgi_i3regs->tclear; + } else { + ioc_icontrol = &sgi_i2regs->ints; + ioc_timers = &sgi_i2regs->timers; + ioc_tclear = &sgi_i2regs->tclear; + } /* Mask out all interrupts. */ ioc_icontrol->imask0 = 0; @@ -575,28 +604,4 @@ /* Now safe to set the exception vector. */ set_except_vector(0, indyIRQ); - -#ifdef CONFIG_REMOTE_DEBUG - ctype = prom_getcmdline(); - for(i = 0; i < strlen(ctype); i++) { - if(ctype[i]=='k' && ctype[i+1]=='g' && - ctype[i+2]=='d' && ctype[i+3]=='b' && - ctype[i+4]=='=' && ctype[i+5]=='t' && - ctype[i+6]=='t' && ctype[i+7]=='y' && - ctype[i+8]=='d' && - (ctype[i+9] == '1' || ctype[i+9] == '2')) { - printk("KGDB: Using serial line /dev/ttyd%d for " - "session\n", (ctype[i+9] - '0')); - if(ctype[i+9]=='1') - rs_kgdb_hook(1); - else if(ctype[i+9]=='2') - rs_kgdb_hook(0); - else { - printk("KGDB: whoops bogon tty line " - "requested, disabling session\n"); - } - - } - } -#endif } diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indy_mc.c linux/arch/mips/sgi/kernel/indy_mc.c --- v2.2.10/linux/arch/mips/sgi/kernel/indy_mc.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/indy_mc.c Mon Aug 9 12:04:38 1999 @@ -2,8 +2,9 @@ * indy_mc.c: Routines for manipulating the INDY memory controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes * - * $Id: indy_mc.c,v 1.3 1998/04/25 15:43:32 ralf Exp $ + * $Id: indy_mc.c,v 1.4 1999/05/07 22:34:32 ulfc Exp $ */ #include #include @@ -150,6 +151,8 @@ tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */ tmpreg |= SGIMC_GIOPARM_PLINEEXP1; tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */ + /* someone forgot this poor little guy... */ + tmpreg |= SGIMC_GIOPARM_GFX64; /* GFX at 64 bits */ } } mcmisc_regs->gioparm = tmpreg; /* poof */ diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.2.10/linux/arch/mips/sgi/kernel/indy_sc.c Mon Oct 26 09:57:55 1998 +++ linux/arch/mips/sgi/kernel/indy_sc.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: indy_sc.c,v 1.9 1998/08/17 12:14:55 ralf Exp $ +/* $Id: indy_sc.c,v 1.9 1999/05/12 21:57:49 ulfc Exp $ * * indy_sc.c: Indy cache managment functions. * @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -38,6 +37,7 @@ .set noreorder .set mips3 .set noat + mfc0 $2, $12 li $1, 0x80 # Go 64 bit mtc0 $1, $12 @@ -50,12 +50,12 @@ bne %0, %1, 1b daddu %0, 32 - mtc0 $0, $12 # Back to 32 bit + mtc0 $2, $12 # Back to 32 bit nop; nop; nop; nop; .set mips0 .set reorder" - : "=r" (first), "=r" (last) - : "0" (first), "1" (last) + : /* no output */ + : "r" (first), "r" (last) : "$1"); } @@ -69,7 +69,10 @@ #endif /* Which lines to flush? */ first_line = SC_INDEX(addr); - last_line = SC_INDEX(SC_ROUND(addr + size)); + if (size <= SC_LINE) + last_line = SC_INDEX(addr); + else + last_line = SC_INDEX(addr + size - 1); __save_and_cli(flags); if (first_line <= last_line) { @@ -80,8 +83,8 @@ /* Cache index wrap around. Due to the way the buddy system works this case should not happen. We're prepared to handle it, though. */ - indy_sc_wipe(last_line, SC_SIZE); - indy_sc_wipe(0, first_line); + indy_sc_wipe(first_line, SC_SIZE - SC_LINE); + indy_sc_wipe(0, last_line); out: __restore_flags(flags); } diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c --- v2.2.10/linux/arch/mips/sgi/kernel/indy_timer.c Thu Mar 11 23:25:24 1999 +++ linux/arch/mips/sgi/kernel/indy_timer.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: indy_timer.c,v 1.9 1998/06/25 20:15:02 ralf Exp $ +/* $Id: indy_timer.c,v 1.12 1999/06/13 16:30:36 ralf Exp $ * * indy_timer.c: Setting up the clock on the INDY 8254 controller. * @@ -262,12 +262,12 @@ int cpu = smp_processor_id(); int irq = 4; - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); prom_getchar(); prom_imode(); - irq_exit(cpu, irq); + hardirq_exit(cpu); } void do_gettimeofday(struct timeval *tv) diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/promcon.c linux/arch/mips/sgi/kernel/promcon.c --- v2.2.10/linux/arch/mips/sgi/kernel/promcon.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/sgi/kernel/promcon.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,73 @@ +/* + * Wrap-around code for a console using the + * SGI PROM io-routines. + * + * Copyright (c) 1999 Ulf Carlsson + * + * Derived from DECstation promcon.c + * Copyright (c) 1998 Harald Koerfgen + */ + +#include +#include +#include +#include +#include +#include + +#include + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + unsigned i; + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} + +static int prom_console_wait_key(struct console *co) +{ + return prom_getchar(); +} + +__initfunc(static int prom_console_setup(struct console *co, char *options)) +{ + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console sercons = +{ + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +__initfunc(long sgi_prom_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/reset.c linux/arch/mips/sgi/kernel/reset.c --- v2.2.10/linux/arch/mips/sgi/kernel/reset.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/reset.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: reset.c,v 1.6 1998/07/09 19:57:47 ralf Exp $ +/* $Id: reset.c,v 1.6 1999/04/10 12:21:30 ulfc Exp $ * * Reset a SGI. * @@ -33,7 +33,9 @@ #define POWERDOWN_FREQ (HZ / 4) #define PANIC_FREQ (HZ / 8) -static struct timer_list power_timer, blink_timer, debounce_timer; +static unsigned char sgi_volume; + +static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer; static int shuting_down, has_paniced; static void sgi_machine_restart(char *command) __attribute__((noreturn)); @@ -129,14 +131,50 @@ add_timer(&power_timer); } -static inline void volume_up_button(void) +void inline sgi_volume_set(unsigned char volume) +{ + sgi_volume = volume; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; +} + +void inline sgi_volume_get(unsigned char *volume) { - /* Later when we have sound support ... */ + *volume = sgi_volume; } -static inline void volume_down_button(void) +static inline void volume_up_button(unsigned long data) { - /* Later when we have sound support ... */ + del_timer(&volume_timer); + + if (sgi_volume < 0xff) + sgi_volume++; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; + + if (ioc_icontrol->istat1 & 2) { + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } + +} + +static inline void volume_down_button(unsigned long data) +{ + del_timer(&volume_timer); + + if (sgi_volume > 0) + sgi_volume--; + + hpc3c0->pbus_extregs[2][0] = sgi_volume; + hpc3c0->pbus_extregs[2][1] = sgi_volume; + + if (ioc_icontrol->istat1 & 2) { + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } } static void panel_int(int irq, void *dev_id, struct pt_regs *regs) @@ -156,10 +194,18 @@ if (!(buttons & 2)) /* Power button was pressed */ power_button(); - if (!(buttons & 0x40)) /* Volume up button was pressed */ - volume_up_button(); - if (!(buttons & 0x10)) /* Volume down button was pressed */ - volume_down_button(); + if (!(buttons & 0x40)) { /* Volume up button was pressed */ + init_timer(&volume_timer); + volume_timer.function = volume_up_button; + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } + if (!(buttons & 0x10)) { /* Volume down button was pressed */ + init_timer(&volume_timer); + volume_timer.function = volume_down_button; + volume_timer.expires = jiffies + 1; + add_timer(&volume_timer); + } } static int panic_event(struct notifier_block *this, unsigned long event, diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c --- v2.2.10/linux/arch/mips/sgi/kernel/setup.c Mon Oct 26 09:57:55 1998 +++ linux/arch/mips/sgi/kernel/setup.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.13 1998/09/16 22:50:46 ralf Exp $ +/* $Id: setup.c,v 1.24 1999/06/12 17:26:15 ulfc Exp $ * * setup.c: SGI specific setup, including init of the feature struct. * @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -25,16 +26,55 @@ #include #include #include +#include -extern int serial_console; /* in sgiserial.c */ +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) +extern void console_setup(char *, int *); +#endif extern struct rtc_ops indy_rtc_ops; void indy_reboot_setup(void); +void sgi_volume_set(unsigned char); -static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64); +static int remote_debug = 0; + +#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64)) #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +static void sgi_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Dirty hack, this get's called as a callback from the keyboard + driver. We piggyback the initialization of the front panel + button handling on it even though they're technically not + related with the keyboard driver in any way. Doing it from + indy_setup wouldn't work since kmalloc isn't initialized yet. */ + indy_reboot_setup(); + + return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ + return 0; +} + +static void sgi_aux_free_irq(void) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ +} + static unsigned char sgi_read_input(void) { return sgi_kh->data; @@ -65,27 +105,28 @@ return sgi_kh->command; } -__initfunc(static void sgi_keyboard_setup(void)) -{ - kbd_read_input = sgi_read_input; - kbd_write_output = sgi_write_output; - kbd_write_command = sgi_write_command; - kbd_read_status = sgi_read_status; - - request_irq(SGI_KEYBOARD_IRQ, keyboard_interrupt, - 0, "keyboard", NULL); - - /* Dirty hack, this get's called as a callback from the keyboard - driver. We piggyback the initialization of the front panel - button handling on it even though they're technically not - related with the keyboard driver in any way. Doing it from - indy_setup wouldn't work since kmalloc isn't initialized yet. */ - indy_reboot_setup(); -} +struct kbd_ops sgi_kbd_ops = { + sgi_request_region, + sgi_request_irq, + + sgi_aux_request_irq, + sgi_aux_free_irq, + + sgi_read_input, + sgi_write_output, + sgi_write_command, + sgi_read_status +}; __initfunc(static void sgi_irq_setup(void)) { sgint_init(); + +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ +#endif } __initfunc(void sgi_setup(void)) @@ -93,9 +134,12 @@ #ifdef CONFIG_SERIAL_CONSOLE char *ctype; #endif +#ifdef CONFIG_REMOTE_DEBUG + char *kgdb_ttyd; +#endif + irq_setup = sgi_irq_setup; - keyboard_setup = sgi_keyboard_setup; /* Init the INDY HPC I/O controller. Need to call this before * fucking with the memory controller because it needs to know the @@ -115,23 +159,55 @@ * line and "d2" for the second serial line. */ ctype = prom_getenv("console"); - serial_console = 0; if(*ctype == 'd') { if(*(ctype+1)=='2') - serial_console = 1; + console_setup ("ttyS1", NULL); else - serial_console = 2; - if(!serial_console) { - prom_printf("Weird console env setting %s\n", ctype); - prom_printf("Press a key to reboot.\n"); - prom_getchar(); - prom_imode(); - } + console_setup ("ttyS0", NULL); + } +#endif + +#ifdef CONFIG_REMOTE_DEBUG + kgdb_ttyd = prom_getcmdline(); + if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) { + int line; + kgdb_ttyd += strlen("kgdb=ttyd"); + if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2') + printk("KGDB: Uknown serial line /dev/ttyd%c, " + "falling back to /dev/ttyd1\n", *kgdb_ttyd); + line = *kgdb_ttyd == '2' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyd%d for session\n", + line ? 1 : 2); + rs_kgdb_hook(line); + + prom_printf("KGDB: Using serial line /dev/ttyd%d for session, " + "please connect your debugger\n", line ? 1 : 2); + + remote_debug = 1; + /* Breakpoints and stuff are in sgi_irq_setup() */ } #endif +#ifdef CONFIG_SGI_PROM_CONSOLE + console_setup("ttyS0", NULL); +#endif + + sgi_volume_set(simple_strtoul(prom_getenv("volume"), NULL, 10)); + #ifdef CONFIG_VT +#ifdef CONFIG_SGI_NEWPORT_CONSOLE conswitchp = &newport_con; +#else + conswitchp = &dummy_con; +#endif #endif + rtc_ops = &indy_rtc_ops; + kbd_ops = &sgi_kbd_ops; +#ifdef CONFIG_PSMOUSE + aux_device_present = 0xaa; +#endif +#ifdef CONFIG_VIDEO_VINO + init_vino(); +#endif } diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/system.c linux/arch/mips/sgi/kernel/system.c --- v2.2.10/linux/arch/mips/sgi/kernel/system.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/system.c Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: system.c,v 1.4 1998/03/27 08:53:45 ralf Exp $ + * $Id: system.c,v 1.7 1998/10/18 22:55:34 tsbogend Exp $ */ #include #include @@ -21,28 +21,6 @@ int type; }; -static struct smatch sgi_mtable[] = { - { "SGI-IP4", ip4 }, - { "SGI-IP5", ip5 }, - { "SGI-IP6", ip6 }, - { "SGI-IP7", ip7 }, - { "SGI-IP9", ip9 }, - { "SGI-IP12", ip12 }, - { "SGI-IP15", ip15 }, - { "SGI-IP17", ip17 }, - { "SGI-IP19", ip19 }, - { "SGI-IP20", ip20 }, - { "SGI-IP21", ip21 }, - { "SGI-IP22", ip22 }, - { "SGI-IP25", ip25 }, - { "SGI-IP26", ip26 }, - { "SGI-IP28", ip28 }, - { "SGI-IP30", ip30 }, - { "SGI-IP32", ip32 } -}; - -#define NUM_MACHS 17 /* for now */ - static struct smatch sgi_cputable[] = { { "MIPS-R2000", CPU_R2000 }, { "MIPS-R3000", CPU_R3000 }, @@ -57,28 +35,13 @@ #define NUM_CPUS 9 /* for now */ -__initfunc(static enum sgi_mach string_to_mach(char *s)) -{ - int i; - - for(i = 0; i < NUM_MACHS; i++) { - if(!strcmp(s, sgi_mtable[i].name)) - return (enum sgi_mach) sgi_mtable[i].type; - } - prom_printf("\nYeee, could not determine SGI architecture type <%s>\n", s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - romvec->imode(); - return (enum sgi_mach) 0; -} - __initfunc(static int string_to_cpu(char *s)) { int i; for(i = 0; i < NUM_CPUS; i++) { if(!strcmp(s, sgi_cputable[i].name)) - return sgi_mtable[i].type; + return sgi_cputable[i].type; } prom_printf("\nYeee, could not determine MIPS cpu type <%s>\n", s); prom_printf("press a key to reboot\n"); @@ -101,8 +64,6 @@ * have here. */ p = prom_getchild(PROM_NULL_COMPONENT); - printk("ARCH: %s\n", p->iname); - sgimach = string_to_mach(p->iname); /* Now scan for cpu(s). */ toplev = p = prom_getchild(p); diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/kernel/time.c linux/arch/mips/sgi/kernel/time.c --- v2.2.10/linux/arch/mips/sgi/kernel/time.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/time.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.2 1998/03/27 08:53:45 ralf Exp $ +/* $Id: time.c,v 1.2 1998/04/05 11:24:00 ralf Exp $ * time.c: Generic SGI time_init() code, this will dispatch to the * appropriate per-architecture time/counter init code. * diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/Makefile linux/arch/mips/sgi/prom/Makefile --- v2.2.10/linux/arch/mips/sgi/prom/Makefile Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/Makefile Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -# $Id: Makefile,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $ -# Makefile for the SGI arcs prom monitor library routines -# under Linux. -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile... - -OBJS = console.o init.o printf.o memory.o tree.o tags.o env.o \ - cmdline.o misc.o time.o file.o - -all: promlib.a - -promlib.a: $(OBJS) - $(AR) rcs promlib.a $(OBJS) - sync - -dep: - $(CPP) -M *.c > .depend - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/cmdline.c linux/arch/mips/sgi/prom/cmdline.c --- v2.2.10/linux/arch/mips/sgi/prom/cmdline.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/cmdline.c Wed Dec 31 16:00:00 1969 @@ -1,64 +0,0 @@ -/* - * cmdline.c: Kernel command line creation using ARCS argc/argv. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: cmdline.c,v 1.3 1998/03/27 08:53:46 ralf Exp $ - */ -#include -#include -#include - -#include -#include - -/* #define DEBUG_CMDLINE */ - -extern char arcs_cmdline[CL_SIZE]; - -__initfunc(char *prom_getcmdline(void)) -{ - return &(arcs_cmdline[0]); -} - -static char *ignored[] = { - "ConsoleIn=", - "ConsoleOut=", - "SystemPartition=", - "OSLoader=", - "OSLoadPartition=", - "OSLoadFilename=" -}; -#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) - -__initfunc(void prom_init_cmdline(void)) -{ - char *cp; - int actr, i; - - actr = 1; /* Always ignore argv[0] */ - - cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - for(i = 0; i < NENTS(ignored); i++) { - int len = strlen(ignored[i]); - - if(!strncmp(prom_argv[actr], ignored[i], len)) - goto pic_cont; - } - /* Ok, we want it. */ - strcpy(cp, prom_argv[actr]); - cp += strlen(prom_argv[actr]); - *cp++ = ' '; - - pic_cont: - actr++; - } - if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ - --cp; - *cp = '\0'; - -#ifdef DEBUG_CMDLINE - prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0])); -#endif -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/console.c linux/arch/mips/sgi/prom/console.c --- v2.2.10/linux/arch/mips/sgi/prom/console.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/console.c Wed Dec 31 16:00:00 1969 @@ -1,26 +0,0 @@ -/* - * console.c: SGI arcs console code. - * - * Copyright (C) 1996 David S. Miller (dm@sgi.com) - * - * $Id: console.c,v 1.2 1998/03/27 08:53:46 ralf Exp $ - */ -#include -#include - -__initfunc(void prom_putchar(char c)) -{ - long cnt; - char it = c; - - romvec->write(1, &it, 1, &cnt); -} - -__initfunc(char prom_getchar(void)) -{ - long cnt; - char c; - - romvec->read(0, &c, 1, &cnt); - return c; -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/env.c linux/arch/mips/sgi/prom/env.c --- v2.2.10/linux/arch/mips/sgi/prom/env.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/env.c Wed Dec 31 16:00:00 1969 @@ -1,22 +0,0 @@ -/* - * env.c: ARCS environment variable routines. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: env.c,v 1.2 1998/03/27 08:53:46 ralf Exp $ - */ -#include -#include -#include - -#include - -__initfunc(char *prom_getenv(char *name)) -{ - return romvec->get_evar(name); -} - -__initfunc(long prom_setenv(char *name, char *value)) -{ - return romvec->set_evar(name, value); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/file.c linux/arch/mips/sgi/prom/file.c --- v2.2.10/linux/arch/mips/sgi/prom/file.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/file.c Wed Dec 31 16:00:00 1969 @@ -1,59 +0,0 @@ -/* - * file.c: ARCS firmware interface to files. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: file.c,v 1.2 1998/03/27 08:53:47 ralf Exp $ - */ -#include -#include - -__initfunc(long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt)) -{ - return romvec->get_vdirent(fd, ent, num, cnt); -} - -__initfunc(long prom_open(char *name, enum linux_omode md, unsigned long *fd)) -{ - return romvec->open(name, md, fd); -} - -__initfunc(long prom_close(unsigned long fd)) -{ - return romvec->close(fd); -} - -__initfunc(long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) -{ - return romvec->read(fd, buf, num, cnt); -} - -__initfunc(long prom_getrstatus(unsigned long fd)) -{ - return romvec->get_rstatus(fd); -} - -__initfunc(long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt)) -{ - return romvec->write(fd, buf, num, cnt); -} - -__initfunc(long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm)) -{ - return romvec->seek(fd, off, sm); -} - -__initfunc(long prom_mount(char *name, enum linux_mountops op)) -{ - return romvec->mount(name, op); -} - -__initfunc(long prom_getfinfo(unsigned long fd, struct linux_finfo *buf)) -{ - return romvec->get_finfo(fd, buf); -} - -__initfunc(long prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk)) -{ - return romvec->set_finfo(fd, flags, msk); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/init.c linux/arch/mips/sgi/prom/init.c --- v2.2.10/linux/arch/mips/sgi/prom/init.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/init.c Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -/* - * init.c: PROM library initialisation code. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: init.c,v 1.2 1998/03/27 08:53:47 ralf Exp $ - */ -#include -#include - -#include - -/* #define DEBUG_PROM_INIT */ - -/* Master romvec interface. */ -struct linux_romvec *romvec; -struct linux_promblock *sgi_pblock; -int prom_argc; -char **prom_argv, **prom_envp; -unsigned short prom_vers, prom_rev; - -extern void prom_testtree(void); - -__initfunc(int prom_init(int argc, char **argv, char **envp)) -{ - struct linux_promblock *pb; - - romvec = ROMVECTOR; - pb = sgi_pblock = PROMBLOCK; - prom_argc = argc; - prom_argv = argv; - prom_envp = envp; - - if(pb->magic != 0x53435241) { - prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); - while(1) - ; - } - - prom_init_cmdline(); - - prom_vers = pb->ver; - prom_rev = pb->rev; - printk("PROMLIB: SGI ARCS firmware Version %d Revision %d\n", - prom_vers, prom_rev); - prom_meminit(); - prom_setup_archtags(); - -#if 0 - prom_testtree(); -#endif - -#ifdef DEBUG_PROM_INIT - { - prom_printf("Press a key to reboot\n"); - (void) prom_getchar(); - romvec->imode(); - } -#endif - return 0; -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/memory.c linux/arch/mips/sgi/prom/memory.c --- v2.2.10/linux/arch/mips/sgi/prom/memory.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/memory.c Wed Dec 31 16:00:00 1969 @@ -1,131 +0,0 @@ -/* - * memory.c: PROM library functions for acquiring/using memory descriptors - * given to us from the ARCS firmware. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: memory.c,v 1.2 1998/03/27 08:53:47 ralf Exp $ - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* #define DEBUG */ - -__initfunc(struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr)) -{ - return romvec->get_mdesc(curr); -} - -#ifdef DEBUG /* convenient for debugging */ -static char *mtypes[8] = { - "Exception Block", - "ARCS Romvec Page", - "Free/Contig RAM", - "Generic Free RAM", - "Bad Memory", - "Standlong Program Pages", - "ARCS Temp Storage Area", - "ARCS Permanent Storage Area" -}; -#endif - -static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS]; - -__initfunc(struct prom_pmemblock *prom_getpblock_array(void)) -{ - return &prom_pblocks[0]; -} - -__initfunc(static void prom_setup_memupper(void)) -{ - struct prom_pmemblock *p, *highest; - - for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) { - if(p->base == 0xdeadbeef) - prom_printf("WHEEE, bogus pmemblock\n"); - if(!highest || p->base > highest->base) - highest = p; - } - mips_memory_upper = highest->base + highest->size; -#ifdef DEBUG - prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n", - mips_memory_upper); -#endif -} - -__initfunc(void prom_meminit(void)) -{ - struct linux_mdesc *p; - int totram; - int i = 0; - - p = prom_getmdesc(PROM_NULL_MDESC); -#ifdef DEBUG - prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); - while(p) { - prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", - i, p, p->base, p->pages, mtypes[p->type]); - p = prom_getmdesc(p); - i++; - } -#endif - p = prom_getmdesc(PROM_NULL_MDESC); - totram = 0; - i = 0; - while(p) { - if(p->type == free || p->type == fcontig) { - prom_pblocks[i].base = - ((p->base<pages << PAGE_SHIFT; - totram += prom_pblocks[i].size; -#ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%d\n", - i, prom_pblocks[i].base, - prom_pblocks[i].size); -#endif - i++; - } - p = prom_getmdesc(p); - } - prom_pblocks[i].base = 0xdeadbeef; - prom_pblocks[i].size = 0; /* indicates last elem. of array */ - printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n", - totram, (totram/1024), (totram/1024/1024)); - - /* Setup upper physical memory bound. */ - prom_setup_memupper(); -} - -/* Called from mem_init() to fixup the mem_map page settings. */ -__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end)) -{ - struct prom_pmemblock *p; - int i, nents; - - /* Determine number of pblockarray entries. */ - p = prom_getpblock_array(); - for(i = 0; p[i].size; i++) - ; - nents = i; - while(start < end) { - for(i = 0; i < nents; i++) { - if((start >= (p[i].base)) && - (start < (p[i].base + p[i].size))) { - start = p[i].base + p[i].size; - start &= PAGE_MASK; - continue; - } - } - set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags); - start += PAGE_SIZE; - } -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/misc.c linux/arch/mips/sgi/prom/misc.c --- v2.2.10/linux/arch/mips/sgi/prom/misc.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/misc.c Wed Dec 31 16:00:00 1969 @@ -1,84 +0,0 @@ -/* $Id: misc.c,v 1.6 1998/07/08 15:59:13 ralf Exp $ - * - * misc.c: Miscellaneous ARCS PROM routines. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include -#include -#include - -#include -#include -#include -#include - -extern unsigned long mips_cputype; -extern void *sgiwd93_host; -extern void reset_wd33c93(void *instance); - -void prom_halt(void) -{ - bcops->bc_disable(); - cli(); -#if CONFIG_SCSI_SGIWD93 - reset_wd33c93(sgiwd93_host); -#endif - romvec->halt(); -} - -void prom_powerdown(void) -{ - bcops->bc_disable(); - cli(); -#if CONFIG_SCSI_SGIWD93 - reset_wd33c93(sgiwd93_host); -#endif - romvec->pdown(); -} - -/* XXX is this a soft reset basically? XXX */ -void prom_restart(void) -{ - bcops->bc_disable(); - cli(); -#if CONFIG_SCSI_SGIWD93 - reset_wd33c93(sgiwd93_host); -#endif - romvec->restart(); -} - -void prom_reboot(void) -{ - bcops->bc_disable(); - cli(); -#if CONFIG_SCSI_SGIWD93 - reset_wd33c93(sgiwd93_host); -#endif - romvec->reboot(); -} - -void prom_imode(void) -{ - bcops->bc_disable(); - cli(); -#if CONFIG_SCSI_SGIWD93 - reset_wd33c93(sgiwd93_host); -#endif - romvec->imode(); -} - -long prom_cfgsave(void) -{ - return romvec->cfg_save(); -} - -struct linux_sysid *prom_getsysid(void) -{ - return romvec->get_sysid(); -} - -__initfunc(void prom_cacheflush(void)) -{ - romvec->cache_flush(); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/printf.c linux/arch/mips/sgi/prom/printf.c --- v2.2.10/linux/arch/mips/sgi/prom/printf.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/printf.c Wed Dec 31 16:00:00 1969 @@ -1,35 +0,0 @@ -/* - * printf.c: Putting things on the screen using SGI arcs - * PROM facilities. - * - * Copyright (C) 1996 David S. Miller (dm@sgi.com) - * - * $Id: printf.c,v 1.2 1998/03/27 08:53:48 ralf Exp $ - */ -#include -#include - -#include - -static char ppbuf[1024]; - -__initfunc(void prom_printf(char *fmt, ...)) -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/salone.c linux/arch/mips/sgi/prom/salone.c --- v2.2.10/linux/arch/mips/sgi/prom/salone.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/salone.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* - * salone.c: Routines to load into memory and execute stand-along - * program images using ARCS PROM firmware. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: salone.c,v 1.2 1998/03/27 08:53:48 ralf Exp $ - */ -#include -#include - -__initfunc(long prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr)) -{ - return romvec->load(name, end, pc, eaddr); -} - -__initfunc(long prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp)) -{ - return romvec->invoke(pc, sp, argc, argv, envp); -} - -__initfunc(long prom_exec(char *name, long argc, char **argv, char **envp)) -{ - return romvec->exec(name, argc, argv, envp); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/tags.c linux/arch/mips/sgi/prom/tags.c --- v2.2.10/linux/arch/mips/sgi/prom/tags.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/tags.c Wed Dec 31 16:00:00 1969 @@ -1,69 +0,0 @@ -/* - * tags.c: Initialize the arch tags the way the MIPS kernel setup - * expects. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: tags.c,v 1.2 1998/03/27 08:53:48 ralf Exp $ - */ -#include -#include -#include - -#include -#include -#include -#include - -/* XXX This tag thing is a fucking rats nest, I'm very inclined to completely - * XXX rework the MIPS people's multi-arch code _NOW_. - */ - -static unsigned long machtype_SGI_INDY = MACH_SGI_INDY; -static unsigned long machgroup_SGI = MACH_GROUP_SGI; -static unsigned long memlower_SGI_INDY = (KSEG0 + SGIMC_SEG0_BADDR); -static unsigned long cputype_SGI_INDY = CPU_R4400SC; -static unsigned long tlb_entries_SGI_INDY = 48; -static unsigned long dummy_SGI_INDY = 0; -static struct drive_info_struct dummy_dinfo_SGI_INDY = { { 0, }, }; -char arcs_cmdline[CL_SIZE]; - -#define TAG(t,l) {tag_##t,(l)} /* XXX RATS NEST CODE!!! XXX */ -#define TAGVAL(v) (void*)&(v) /* XXX FUCKING LOSING!!! XXX */ - -tag_def taglist_sgi_indy[] = { - {TAG(machtype, ULONGSIZE), TAGVAL(machtype_SGI_INDY)}, - {TAG(machgroup, ULONGSIZE), TAGVAL(machgroup_SGI)}, - {TAG(memlower, ULONGSIZE), TAGVAL(memlower_SGI_INDY)}, - {TAG(cputype, ULONGSIZE), TAGVAL(cputype_SGI_INDY)}, - {TAG(tlb_entries, ULONGSIZE), TAGVAL(tlb_entries_SGI_INDY)}, - {TAG(vram_base, ULONGSIZE), TAGVAL(dummy_SGI_INDY)}, - {TAG(drive_info, DRVINFOSIZE), TAGVAL(dummy_dinfo_SGI_INDY)}, - {TAG(mount_root_rdonly, ULONGSIZE), TAGVAL(dummy_SGI_INDY)}, - {TAG(command_line, CL_SIZE), TAGVAL(arcs_cmdline[0])}, - {TAG(dummy, 0), NULL} - /* XXX COLOSTOMY BAG!!!! XXX */ -}; - -__initfunc(void prom_setup_archtags(void)) -{ - tag_def *tdp = &taglist_sgi_indy[0]; - tag *tp; - - tp = (tag *) (mips_memory_upper - sizeof(tag)); - while(tdp->t.tag != tag_dummy) { - unsigned long size; - char *d; - - *tp = tdp->t; - size = tp->size; - d = (char *) tdp->d; - tp = (tag *)(((unsigned long)tp) - (tp->size)); - if(size) - memcpy(tp, d, size); - - tp--; - tdp++; - } - *tp = tdp->t; /* copy last dummy element over */ -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/time.c linux/arch/mips/sgi/prom/time.c --- v2.2.10/linux/arch/mips/sgi/prom/time.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/time.c Wed Dec 31 16:00:00 1969 @@ -1,19 +0,0 @@ -/* - * time.c: Extracting time information from ARCS prom. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: time.c,v 1.2 1998/03/27 08:53:49 ralf Exp $ - */ -#include -#include - -__initfunc(struct linux_tinfo *prom_gettinfo(void)) -{ - return romvec->get_tinfo(); -} - -__initfunc(unsigned long prom_getrtime(void)) -{ - return romvec->get_rtime(); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sgi/prom/tree.c linux/arch/mips/sgi/prom/tree.c --- v2.2.10/linux/arch/mips/sgi/prom/tree.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/prom/tree.c Wed Dec 31 16:00:00 1969 @@ -1,109 +0,0 @@ -/* - * tree.c: PROM component device tree code. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: tree.c,v 1.2 1998/03/27 08:53:49 ralf Exp $ - */ -#include -#include - -#define DEBUG_PROM_TREE - -__initfunc(pcomponent *prom_getsibling(pcomponent *this)) -{ - if(this == PROM_NULL_COMPONENT) - return PROM_NULL_COMPONENT; - return romvec->next_component(this); -} - -__initfunc(pcomponent *prom_getchild(pcomponent *this)) -{ - return romvec->child_component(this); -} - -__initfunc(pcomponent *prom_getparent(pcomponent *child)) -{ - if(child == PROM_NULL_COMPONENT) - return PROM_NULL_COMPONENT; - return romvec->parent_component(child); -} - -__initfunc(long prom_getcdata(void *buffer, pcomponent *this)) -{ - return romvec->component_data(buffer, this); -} - -__initfunc(pcomponent *prom_childadd(pcomponent *this, pcomponent *tmp, void *data)) -{ - return romvec->child_add(this, tmp, data); -} - -__initfunc(long prom_delcomponent(pcomponent *this)) -{ - return romvec->comp_del(this); -} - -__initfunc(pcomponent *prom_componentbypath(char *path)) -{ - return romvec->component_by_path(path); -} - -#ifdef DEBUG_PROM_TREE -static char *classes[] = { - "system", "processor", "cache", "adapter", "controller", "peripheral", - "memory" -}; - -static char *types[] = { - "arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", "sccache", - "memdev", "eisa adapter", "tc adapter", "scsi adapter", "dti adapter", - "multi-func adapter", "disk controller", "tp controller", - "cdrom controller", "worm controller", "serial controller", - "net controller", "display controller", "parallel controller", - "pointer controller", "keyboard controller", "audio controller", - "misc controller", "disk peripheral", "floppy peripheral", - "tp peripheral", "modem peripheral", "monitor peripheral", - "printer peripheral", "pointer peripheral", "keyboard peripheral", - "terminal peripheral", "line peripheral", "net peripheral", - "misc peripheral", "anonymous" -}; - -static char *iflags[] = { - "bogus", "read only", "removable", "console in", "console out", - "input", "output" -}; - -__initfunc(static void dump_component(pcomponent *p)) -{ - prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>", - p, classes[p->class], types[p->type], - iflags[p->iflags], p->vers, p->rev); - prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n", - p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); -} - -__initfunc(static void traverse(pcomponent *p, int op)) -{ - dump_component(p); - if(prom_getchild(p)) - traverse(prom_getchild(p), 1); - if(prom_getsibling(p) && op) - traverse(prom_getsibling(p), 1); -} - -__initfunc(void prom_testtree(void)) -{ - pcomponent *p; - - p = prom_getchild(PROM_NULL_COMPONENT); - dump_component(p); - p = prom_getchild(p); - while(p) { - dump_component(p); - p = prom_getsibling(p); - } - prom_printf("press a key\n"); - prom_getchar(); -} -#endif diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/Makefile linux/arch/mips/sni/Makefile --- v2.2.10/linux/arch/mips/sni/Makefile Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/Makefile Mon Aug 9 12:04:38 1999 @@ -1,3 +1,4 @@ +# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $ # # Makefile for the SNI specific part of the kernel # @@ -5,8 +6,6 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # -# $Id: Makefile,v 1.2 1997/12/20 13:27:14 ralf Exp $ -# .S.s: $(CPP) $(CFLAGS) $< -o $*.s @@ -15,7 +14,7 @@ all: sni.o O_TARGET := sni.o -O_OBJS := hw-access.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o +O_OBJS := int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o int-handler.o: int-handler.S diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/hw-access.c linux/arch/mips/sni/hw-access.c --- v2.2.10/linux/arch/mips/sni/hw-access.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/hw-access.c Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -/* $Id: hw-access.c,v 1.8 1998/09/16 22:50:46 ralf Exp $ - * - * Low-level hardware access stuff for SNI RM200 PCI - * - * 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. - * - * Copyright (C) 1996, 1997, 1998 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ - -static unsigned char sni_read_input(void) -{ - return inb(KBD_DATA_REG); -} - -static void sni_write_output(unsigned char val) -{ - int status; - - do { - status = inb(KBD_CNTL_REG); - } while (status & KBD_STAT_IBF); - outb(val, KBD_DATA_REG); -} - -static void sni_write_command(unsigned char val) -{ - int status; - - do { - status = inb(KBD_CNTL_REG); - } while (status & KBD_STAT_IBF); - outb(val, KBD_CNTL_REG); -} - -static unsigned char sni_read_status(void) -{ - return inb(KBD_STATUS_REG); -} - -__initfunc(void sni_rm200_keyboard_setup(void)) -{ - kbd_read_input = sni_read_input; - kbd_write_output = sni_write_output; - kbd_write_command = sni_write_command; - kbd_read_status = sni_read_status; - request_irq(PCIMT_KEYBOARD_IRQ, keyboard_interrupt, - 0, "keyboard", NULL); - request_region(0x60, 16, "keyboard"); -} diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/int-handler.S linux/arch/mips/sni/int-handler.S --- v2.2.10/linux/arch/mips/sni/int-handler.S Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/int-handler.S Mon Aug 9 12:04:38 1999 @@ -1,17 +1,22 @@ -/* $Id: int-handler.S,v 1.4 1998/05/07 14:17:47 ralf Exp $ +/* $Id: int-handler.S,v 1.4 1999/01/04 16:03:58 ralf Exp $ * * SNI RM200 PCI specific interrupt handler code. * * Copyright (C) 1994 - 1997 by Ralf Baechle */ #include -#include #include #include #include #include #include +/* The PCI ASIC has the nasty property that it may delay writes if it is busy. + As a consequence from writes that have not graduated when we exit from the + interrupt handler we might catch a spurious interrupt. To avoid this we + force the PCI ASIC to graduate all writes by executing a read from the + PCI bus. */ + .set noreorder .set noat .align 5 @@ -20,34 +25,38 @@ CLI .set at - lb t0,led_cache - addiu t0,1 - sb t0,led_cache - sb t0,PCIMT_CSLED + /* Blinken light ... */ + lb t0, led_cache + addiu t0, 1 + sb t0, led_cache + sb t0, PCIMT_CSLED # write only register .data led_cache: .byte 0 .text - mfc0 t0,CP0_STATUS - mfc0 t1,CP0_CAUSE - and t0,t1 - - andi t1,t0,0x0800 # hardware interrupt 1 - bnez t1,hwint1 - andi t1,t0,0x4000 # hardware interrupt 4 - bnez t1,eth_int - - andi t1,t0,0x1000 # hardware interrupt 2 - bnez t1,hwint2 - andi t1,t0,0x2000 # hardware interrupt 3 - bnez t1,hwint3 - andi t1,t0,0x8000 # hardware interrupt 5 - bnez t1,hwint5 - andi t1,t0,0x0400 # hardware interrupt 0 - bnez t1,hwint0 + mfc0 t0, CP0_STATUS + mfc0 t1, CP0_CAUSE + and t0, t1 + + /* The following interrupt dispatch tests for hwint 1 / + EISA bridge first such that the timer interrupt get the + highest priority. */ + andi t1, t0, 0x0800 # hardware interrupt 1 + bnez t1, hwint1 + andi t1, t0, 0x4000 # hardware interrupt 4 + bnez t1, hwint4 + + andi t1, t0, 0x1000 # hardware interrupt 2 + bnez t1, hwint2 + andi t1, t0, 0x2000 # hardware interrupt 3 + bnez t1, hwint3 + andi t1, t0, 0x8000 # hardware interrupt 5 + bnez t1, hwint5 + andi t1, t0, 0x0400 # hardware interrupt 0 + bnez t1, hwint0 nop - j spurious_interrupt # Nothing up ... + j return # spurious interrupt nop ############################################################################## @@ -57,146 +66,61 @@ /* ------------------------------------------------------------------------ */ -hwint1: lbu t0,PCIMT_CSITPEND - - andi t1,t0,0x20 - bnez t1,eisa_int - -#ifdef CONFIG_SCSI_NCR53C8XX - andi t1,t0,0x40 - beqz t1,scsi_int -#endif - nop - - j spurious_interrupt - nop - - /* ------------------------------------------------------------------------ */ - -hwint0: lbu t0,PCIMT_CSITPEND - - andi t1,t0,0x01 - beqz t1,int2 +/* hwint1 deals with EISA and SCSI interrupts. */ +hwint1: lbu s0, PCIMT_CSITPEND -go_spurious: j spurious_interrupt # we got fooled + andi t1, s0, 0x20 + beqz t1, 1f + andi s1, s0, 0x40 + lbu a0, PCIMT_INT_ACKNOWLEDGE # IACK cycle + xori t0, a0, 0xff + beqz t0, 1f # spurious interrupt? nop + jal i8259_do_irq # call real handler + move a1, sp -eisa_int: lui s0,%hi(SNI_PORT_BASE) - li a0,0x0f - sb a0,%lo(SNI_PORT_BASE+0x20)(s0) # poll command - lb a0,%lo(SNI_PORT_BASE+0x20)(s0) # read result - bgtz a0,poll_second - andi a0,7 - beq a0,2,poll_second # cascade? - li s1,1 - /* - * Acknowledge first pic - */ - lb t2,%lo(SNI_PORT_BASE+0x21)(s0) - lui s4,%hi(cache_21) - lb t0,%lo(cache_21)(s4) - sllv s1,s1,a0 - or t0,s1 - sb t0,%lo(cache_21)(s4) - sb t0,%lo(SNI_PORT_BASE+0x21)(s0) - li t2,0x20 - sb t2,%lo(SNI_PORT_BASE+0x20)(s0) - /* - * Now call the real handler - */ +1: bnez s1, 1f + li a0, PCIMT_IRQ_SCSI jal do_IRQ - move a1,sp - /* - * Unblock first pic - */ - lbu t1,%lo(SNI_PORT_BASE+0x21)(s0) - lb t1,%lo(cache_21)(s4) - nor s1,zero,s1 - and t1,s1 - sb t1,%lo(cache_21)(s4) - j ret_from_irq - sb t1,%lo(SNI_PORT_BASE+0x21)(s0) + move a1, sp - /* - * Cascade interrupt from second PIC - */ - .align 5 -poll_second: li a0,0x0f - sb a0,%lo(SNI_PORT_BASE+0xa0)(s0) # poll command - lb a0,%lo(SNI_PORT_BASE+0xa0)(s0) # read result - bgtz a0,go_spurious - andi a0,7 - /* - * Acknowledge second pic - */ - lbu t2,%lo(SNI_PORT_BASE+0xa1)(s0) - lui s4,%hi(cache_A1) - lb t3,%lo(cache_A1)(s4) - sllv s1,s1,a0 - or t3,s1 - sb t3,%lo(cache_A1)(s4) - sb t3,%lo(SNI_PORT_BASE+0xa1)(s0) - li t3,0x20 - sb t3,%lo(SNI_PORT_BASE+0xa0)(s0) - sb t3,%lo(SNI_PORT_BASE+0x20)(s0) - /* - * Now call the real handler - */ - addiu a0,8 - jal do_IRQ - move a1,sp - /* - * Unblock second pic - */ - lb t1,%lo(SNI_PORT_BASE+0xa1)(s0) - lb t1,%lo(cache_A1)(s4) - subu t0,1 - nor s1,zero,s1 - and t1,t1,s1 - sb t1,%lo(cache_A1)(s4) +1: lui t0, %hi(PCIMT_CSITPEND) j ret_from_irq - sb t1,%lo(SNI_PORT_BASE+0xa1)(s0) - -/* - * ... check if we were interrupted by the Lance ... - */ -eth_int: mfc0 s0,CP0_STATUS - ori t0,s0,0x4000 - xori t0,0x4000 - mtc0 t0,CP0_STATUS + lbu zero, %lo(PCIMT_CSITPEND)(t0) - li a0,PCIMT_IRQ_ETHERNET - jal do_IRQ - move a1,sp + /* ------------------------------------------------------------------------ */ - mtc0 s0,CP0_STATUS +/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug + button interrupts. */ +hwint0: PANIC("Received int0 but no handler yet ...\n") +1: j 1b + nop - j ret_from_irq +go_spurious: j spurious_interrupt # we got fooled nop -#ifdef CONFIG_SCSI_NCR53C8XX +/* hwint4 is used for only the onboard PCnet 32. */ +hwint4: mfc0 s0, CP0_STATUS + ori t0, s0, 0x4000 + xori t0, 0x4000 + mtc0 t0, CP0_STATUS -/* - * ... check if we were interrupted by the NCR ... - */ -scsi_int: li a0,PCIMT_IRQ_SCSI + li a0, PCIMT_IRQ_ETHERNET jal do_IRQ - move a1,sp - j ret_from_irq - nop - -#endif /* CONFIG_SCSI_NCR53C8XX */ + move a1, sp -pci_int: PANIC("Received PCI interrupt but no handler yet ...\n") -1: j 1b - nop + mtc0 s0, CP0_STATUS -int2: PANIC("Received int2 but no handler yet ...\n") -1: j 1b + j ret_from_irq nop +/* This interrupt was used for the com1 console on the first prototypes. */ hwint2: PANIC("hwint2 and no handler yet") + +/* hwint3 should deal with the PCI A - D interrupts. */ hwint3: PANIC("hwint3 and no handler yet") + +/* hwint5 is the r4k count / compare interrupt */ hwint5: PANIC("hwint5 and no handler yet") END(sni_rm200_pci_handle_int) diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/io.c linux/arch/mips/sni/io.c --- v2.2.10/linux/arch/mips/sni/io.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/io.c Mon Aug 9 12:04:38 1999 @@ -1,11 +1,10 @@ -/* +/* $Id: io.c,v 1.3 1999/01/04 16:03:58 ralf Exp $ + * * 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. * * Low level I/O functions for SNI. - * - * $Id: io.c,v 1.2 1998/03/27 08:53:50 ralf Exp $ */ #include #include @@ -14,46 +13,42 @@ #include #include -unsigned char sni_map_isa_cache; - -#define unused __attribute__((unused)) - -/* - * The PCIMT_CSMAPISA is shared by all processors; we need locking. - * - * XXX It's legal to use all the I/O memory access functions in interrupt - * code, so we need to use the _irq locking stuff which may result in - * significant IRQ latencies. - */ -static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED; - /* * Urgs... We only can see a 16mb window of the 4gb EISA address space * at PCIMT_EISA_BASE. Maladia segmentitis ... * - * XXX Check out if accessing PCIMT_CSMAPISA really is slow. - * For now assume so. + * To avoid locking and all the related headacke we implement this such + * that accessing the bus address space nests, so we're treating this + * correctly even for interrupts. This is going to suck seriously for + * the SMP members of the RM family. + * + * Making things worse the PCIMT_CSMAPISA register resides on the X bus with + * it's unbeatable 1.4 mb/s transfer rate. */ -static inline void update_isa_cache(unsigned long address) + +static inline void eisa_map(unsigned long address) { unsigned char upper; upper = address >> 24; - if (sni_map_isa_cache != upper) { - sni_map_isa_cache = upper; - *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper; - } + *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper; } +#define save_eisa_map() \ + (*(volatile unsigned char *)PCIMT_CSMAPISA) +#define restore_eisa_map(val) \ + do { (*(volatile unsigned char *)PCIMT_CSMAPISA) = val; } while(0) + static unsigned char sni_readb(unsigned long addr) { unsigned char res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } @@ -61,12 +56,13 @@ static unsigned short sni_readw(unsigned long addr) { unsigned short res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } @@ -74,101 +70,111 @@ static unsigned int sni_readl(unsigned long addr) { unsigned int res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } static void sni_writeb(unsigned char val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_writew(unsigned short val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_writel(unsigned int val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memset_io(unsigned long addr, int val, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (addr & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~addr + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(addr); + eisa_map(addr); memset((char *)waddr, val, fraglen); addr += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (from & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~from + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(from); + eisa_map(from); memcpy((void *)to, (void *)waddr, fraglen); to += fraglen; from += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (to & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~to + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(to); + eisa_map(to); memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen); to += fraglen; from += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c --- v2.2.10/linux/arch/mips/sni/pci.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/pci.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.6 1998/05/07 14:17:48 ralf Exp $ +/* $Id: pci.c,v 1.7 1999/01/04 16:03:58 ralf Exp $ * * 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 @@ -9,6 +9,7 @@ * Copyright (C) 1997, 1998 Ralf Baechle */ #include +#include #include #include #include @@ -28,13 +29,37 @@ static void sni_rm200_pcibios_fixup (void) { - /* - * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards. - * Take care of RM300 revision D boards for where the network - * slot became an ordinary PCI slot. - */ - pcibios_write_config_byte(0, PCI_DEVFN(1, 0), PCI_INTERRUPT_LINE, - PCIMT_IRQ_SCSI); + struct pci_dev *dev; + + for (dev=pci_devices; dev; dev=dev->next) { + /* + * TODO: Take care of RM300 revision D boards for where the + * network slot became an ordinary PCI slot. + */ + if (dev->devfn == PCI_DEVFN(1, 0)) { + /* Evil hack ... */ + set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NO_WA); + dev->irq = PCIMT_IRQ_SCSI; + continue; + } + if (dev->devfn == PCI_DEVFN(2, 0)) { + dev->irq = PCIMT_IRQ_ETHERNET; + continue; + } + + switch(dev->irq) { + case 1 ... 4: + dev->irq += PCIMT_IRQ_INTA - 1; + break; + case 0: + break; + default: + printk("PCI device on bus %d, dev %d, function %d " + "impossible interrupt configured.\n", + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_SLOT(dev->devfn)); + } + } } /* diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/pcimt_scache.c linux/arch/mips/sni/pcimt_scache.c --- v2.2.10/linux/arch/mips/sni/pcimt_scache.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/pcimt_scache.c Mon Aug 9 12:04:38 1999 @@ -1,35 +1,38 @@ -/* +/* $Id: pcimt_scache.c,v 1.4 1999/01/04 16:03:59 ralf Exp $ + * * arch/mips/sni/pcimt_scache.c * * 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. * - * Copyright (c) 1997 by Ralf Baechle - * - * $Id: pcimt_scache.c,v 1.2 1998/05/28 03:18:02 ralf Exp $ + * Copyright (c) 1997, 1998 by Ralf Baechle */ #include #include #include #include +#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF) +#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE) + __initfunc(void sni_pcimt_sc_init(void)) { - unsigned int cacheconf, sc_size; + unsigned int scsiz, sc_size; - cacheconf = *(volatile unsigned int *)PCIMT_CACHECONF; - if ((cacheconf & 7) == 0) { - printk("No second level cache detected\n"); - printk("WARNING: not activating second level cache, " - "tell ralf@gnu.org\n"); + scsiz = cacheconf & 7; + if (scsiz == 0) { + printk("Second level cache is deactived.\n"); return; } - if ((cacheconf & 7) >= 6) { - printk("Invalid second level cache size detected\n"); + if (scsiz >= 6) { + printk("Invalid second level cache size configured, " + "deactivating second level cache.\n"); + cacheconf = 0; return; } - - sc_size = 128 << (cacheconf & 7); - printk("%dkb second level cache detected.\n", sc_size); + + sc_size = 128 << scsiz; + printk("%dkb second level cache detected, deactivating.\n", sc_size); + cacheconf = 0; } diff -u --recursive --new-file v2.2.10/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c --- v2.2.10/linux/arch/mips/sni/setup.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sni/setup.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.13 1998/08/17 13:57:45 ralf Exp $ +/* $Id: setup.c,v 1.10 1999/01/04 16:03:59 ralf Exp $ * * Setup pointers to hardware-dependent routines. * @@ -17,6 +17,11 @@ #include #include #include +#include +#include +#include +#include + #include #include #include @@ -39,7 +44,6 @@ static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; extern asmlinkage void sni_rm200_pci_handle_int(void); -extern void sni_rm200_keyboard_setup(void); extern void sni_machine_restart(char *command); extern void sni_machine_halt(void); @@ -47,19 +51,20 @@ extern struct ide_ops std_ide_ops; extern struct rtc_ops std_rtc_ops; +extern struct kbd_ops std_kbd_ops; __initfunc(static void sni_irq_setup(void)) { set_except_vector(0, sni_rm200_pci_handle_int); request_region(0x20,0x20, "pic1"); request_region(0xa0,0x20, "pic2"); - setup_x86_irq(2, &irq2); + i8259_setup_irq(2, &irq2); /* * IRQ0 seems to be the irq for PC style stuff. * I don't know how to handle the debug button interrupt, so * don't use this button yet or bad things happen ... */ - set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ4); + set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ3 | IE_IRQ4); } void (*board_time_init)(struct irqaction *irq); @@ -70,7 +75,7 @@ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - setup_x86_irq(0, irq); + i8259_setup_irq(0, irq); } unsigned char aux_device_present; @@ -132,7 +137,6 @@ irq_setup = sni_irq_setup; mips_io_port_base = SNI_PORT_BASE; - keyboard_setup = sni_rm200_keyboard_setup; /* * Setup (E)ISA I/O memory access stuff @@ -165,6 +169,10 @@ #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif - + conswitchp = &vga_con; rtc_ops = &std_rtc_ops; + kbd_ops = &std_kbd_ops; +#ifdef CONFIG_PSMOUSE + aux_device_present = 0xaa; +#endif } diff -u --recursive --new-file v2.2.10/linux/arch/mips/tools/Makefile linux/arch/mips/tools/Makefile --- v2.2.10/linux/arch/mips/tools/Makefile Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/tools/Makefile Mon Aug 9 12:04:38 1999 @@ -3,7 +3,7 @@ # Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) # Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu) # -# $Id: Makefile,v 1.2 1997/09/23 06:23:49 ralf Exp $ +# $Id: Makefile,v 1.2 1997/12/01 17:57:41 ralf Exp $ # TARGET := $(TOPDIR)/include/asm-$(ARCH)/offset.h diff -u --recursive --new-file v2.2.10/linux/arch/mips/tools/offset.c linux/arch/mips/tools/offset.c --- v2.2.10/linux/arch/mips/tools/offset.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/tools/offset.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: offset.c,v 1.10 1998/08/19 21:53:53 ralf Exp $ +/* $Id: offset.c,v 1.9 1998/08/25 09:14:52 ralf Exp $ * * offset.c: Calculate pt_regs and task_struct offsets. * diff -u --recursive --new-file v2.2.10/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.2.10/linux/arch/ppc/Makefile Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/Makefile Mon Aug 9 12:04:57 1999 @@ -65,8 +65,7 @@ checks: @$(MAKE) -C arch/$(ARCH)/kernel checks -BOOT_TARGETS = netboot znetboot zImage floppy install \ - vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd +BOOT_TARGETS = zImage znetboot.initrd zImage.initrd ifdef CONFIG_MBX $(BOOT_TARGETS): $(CHECKS) vmlinux @@ -74,6 +73,16 @@ @$(MAKEMBXBOOT) $@ else $(BOOT_TARGETS): $(CHECKS) vmlinux + @$(MAKECOFFBOOT) $@ + @$(MAKEBOOT) $@ + @$(MAKECHRPBOOT) $@ + +znetboot: $(CHECKS) vmlinux +ifdef CONFIG_SMP + cp -f vmlinux /tftpboot/vmlinux.smp +else + cp -f vmlinux /tftpboot/vmlinux +endif @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @$(MAKECHRPBOOT) $@ diff -u --recursive --new-file v2.2.10/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.2.10/linux/arch/ppc/amiga/amiints.c Thu Jan 7 08:46:58 1999 +++ linux/arch/ppc/amiga/amiints.c Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/ppc/amiga/config.c linux/arch/ppc/amiga/config.c --- v2.2.10/linux/arch/ppc/amiga/config.c Mon Dec 21 08:37:20 1998 +++ linux/arch/ppc/amiga/config.c Mon Aug 9 12:04:38 1999 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.2.10/linux/arch/ppc/chrpboot/main.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/chrpboot/main.c Mon Aug 9 12:04:57 1999 @@ -19,12 +19,13 @@ #define RAM_START 0x00000000 #define RAM_END (8<<20) -#define RAM_FREE (6<<20) /* after image of chrpboot */ +#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) #define PROG_START 0x00010000 char *avail_ram; char *end_avail; +extern char _end[]; extern char image_data[]; extern int image_len; extern char initrd_data[]; @@ -47,8 +48,8 @@ initrd_start = (RAM_END - initrd_size) & ~0xFFF; a1 = initrd_start; a2 = initrd_size; - printf("initial ramdisk at 0x%x (%u bytes)\n\r", initrd_start, - initrd_size); + printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start, + initrd_data,initrd_size); memcpy((char *)initrd_start, initrd_data, initrd_size); end_avail = (char *)initrd_start; } else @@ -56,7 +57,6 @@ im = image_data; len = image_len; dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { avail_ram = (char *)RAM_FREE; printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); @@ -71,7 +71,7 @@ sa = *(unsigned long *)PROG_START+PROG_START; printf("start address = 0x%x\n\r", sa); - (*(void (*)())sa)(a1, a2, prom, 0, 0); + (*(void (*)())sa)(0, 0, prom, a1, a2); printf("returned?\n\r"); diff -u --recursive --new-file v2.2.10/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig --- v2.2.10/linux/arch/ppc/common_defconfig Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/common_defconfig Mon Aug 9 12:04:57 1999 @@ -85,7 +85,7 @@ # # Additional Block Devices # -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y @@ -173,7 +173,8 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_OVERRIDE_CMDS is not set +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_ADVANSYS is not set @@ -308,7 +309,7 @@ CONFIG_FB_MATROX=y # CONFIG_FB_MATROX_MILLENIUM is not set CONFIG_FB_MATROX_MYSTIQUE=y -# CONFIG_FB_MATROX_G100 is not set +CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set # CONFIG_FB_ATY is not set # CONFIG_FB_VIRTUAL is not set @@ -378,6 +379,11 @@ # CONFIG_FT_ALT_FDC is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -497,6 +503,6 @@ # # Kernel hacking # -CONFIG_MAGIC_SYSRQ=y +# CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set diff -u --recursive --new-file v2.2.10/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.2.10/linux/arch/ppc/config.in Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/config.in Mon Aug 9 12:04:57 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.92.2.1 1999/05/29 19:09:16 cort Exp $ +# $Id: config.in,v 1.92.2.2 1999/06/17 01:19:06 paulus Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -176,6 +176,7 @@ endmenu source drivers/char/Config.in +source drivers/usb/Config.in source fs/Config.in mainmenu_option next_comment diff -u --recursive --new-file v2.2.10/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.2.10/linux/arch/ppc/defconfig Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/defconfig Mon Aug 9 12:04:57 1999 @@ -7,6 +7,7 @@ # CONFIG_PPC=y CONFIG_6xx=y +# CONFIG_PPC64 is not set # CONFIG_8xx is not set CONFIG_PMAC=y # CONFIG_PREP is not set @@ -14,8 +15,9 @@ # CONFIG_ALL_PPC is not set # CONFIG_APUS is not set # CONFIG_MBX is not set -CONFIG_MACH_SPECIFIC=y # CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_6xx=y # # General setup @@ -35,7 +37,8 @@ CONFIG_KERNEL_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set +CONFIG_PARPORT=m +# CONFIG_PARPORT_PC is not set # CONFIG_VGA_CONSOLE is not set CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y @@ -43,13 +46,12 @@ CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADBMOUSE=y -CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set # # Plug and Play support @@ -73,7 +75,15 @@ # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +CONFIG_BLK_DEV_CMD646=y # CONFIG_BLK_DEV_SL82C105 is not set CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -84,14 +94,16 @@ # # Additional Block Devices # -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_PARIDE_PARPORT=m # CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_HD is not set # @@ -119,7 +131,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set @@ -173,7 +184,8 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_OVERRIDE_CMDS is not set +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_ADVANSYS is not set @@ -189,15 +201,28 @@ # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -212,10 +237,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -225,10 +258,10 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -247,22 +280,36 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set -CONFIG_PPP=y +# CONFIG_PLIP is not set +CONFIG_PPP=m # # CCP compressors for PPP are only built as modules. # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -275,7 +322,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -283,6 +330,7 @@ # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y @@ -319,6 +367,7 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set @@ -334,6 +383,7 @@ # Joystick support # # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver @@ -341,6 +391,11 @@ # CONFIG_FTAPE is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -364,6 +419,7 @@ CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_EFS_FS is not set # # Network File Systems @@ -415,7 +471,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_R is not set # @@ -429,3 +485,10 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_OSS is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.2.10/linux/arch/ppc/kernel/chrp_pci.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/chrp_pci.c Mon Aug 9 12:04:57 1999 @@ -96,7 +96,7 @@ #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000)) #define PYTHON_CFA(b, d, o) (0x80 | ((b<<6) << 8) | ((d) << 16) \ | (((o) & ~3) << 24)) -unsigned int python_busnr = 1; +unsigned int python_busnr = 0; int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) @@ -353,7 +353,8 @@ } else { - if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) ) + if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) || + !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) ) { pci_dram_offset = 0; isa_mem_base = 0x80000000; diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.2.10/linux/arch/ppc/kernel/chrp_setup.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/chrp_setup.c Mon Aug 9 12:04:57 1999 @@ -295,7 +295,7 @@ struct property *p; device = find_devices("rtas"); for ( p = device->properties; - strncmp(p->name, "rtas-event-scan-rate", 20) && p ; + p && strncmp(p->name, "rtas-event-scan-rate", 20); p = p->next ) /* nothing */ ; if ( p && *(unsigned long *)p->value ) @@ -331,12 +331,8 @@ chrp_power_off(void) { /* allow power on only with power button press */ -#define PWR_FIELD(x) (0x8000000000000000 >> ((x)-96)) printk("RTAS power-off returned %d\n", - call_rtas("power-off", 2, 1, NULL, - ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff, - (PWR_FIELD(96)|PWR_FIELD(97))&0xffffffff)); -#undef PWR_FIELD + call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); for (;;); } @@ -475,6 +471,45 @@ /* Should this be here? - Corey */ pmac_nvram_init(); + +#ifdef CONFIG_VT +#ifdef CONFIG_MAC_KEYBOARD + if ( adb_hardware == ADB_NONE ) + { + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif + } + else + { + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; +#endif + } +#else + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif +#endif +#endif } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) @@ -584,10 +619,10 @@ chrp_setup_pci_ptrs(); #ifdef CONFIG_BLK_DEV_INITRD /* take care of initrd if we have one */ - if ( r3 ) + if ( r6 ) { - initrd_start = r3 + KERNELBASE; - initrd_end = r3 + r4 + KERNELBASE; + initrd_start = r6 + KERNELBASE; + initrd_end = r6 + r7 + KERNELBASE; } #endif /* CONFIG_BLK_DEV_INITRD */ @@ -614,44 +649,6 @@ ppc_md.get_rtc_time = chrp_get_rtc_time; ppc_md.calibrate_decr = chrp_calibrate_decr; -#ifdef CONFIG_VT -#ifdef CONFIG_MAC_KEYBOAD - if ( adb_hardware == ADB_NONE ) - { - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif - } - else - { - ppc_md.kbd_setkeycode = mackbd_setkeycode; - ppc_md.kbd_getkeycode = mackbd_getkeycode; - ppc_md.kbd_translate = mackbd_translate; - ppc_md.kbd_unexpected_up = mackbd_unexpected_up; - ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_init_hw = mackbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; -#endif - } -#else - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; -#endif -#endif -#endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = chrp_ide_insw; @@ -675,8 +672,6 @@ void chrp_progress(char *s) { - extern unsigned int rtas_data; - if ( (_machine != _MACH_chrp) || !rtas_data ) return; call_rtas( "display-character", 1, 1, NULL, '\r' ); diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.2.10/linux/arch/ppc/kernel/head.S Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/head.S Mon Aug 9 12:04:57 1999 @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.130.2.1 1999/05/29 19:09:59 cort Exp $ + * $Id: head.S,v 1.130.2.2 1999/06/30 04:53:21 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -300,7 +300,7 @@ oris r21,r11,(KERNELBASE+0x20000000)@h mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ mtspr DBAT2U,r21 /* bit in upper BAT register */ - mtspr IBAT2L,r28 + mtspr IBAT2L,r18 mtspr IBAT2U,r21 #endif /* CONFIG_PPC64 */ #endif diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.2.10/linux/arch/ppc/kernel/idle.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/idle.c Mon Aug 9 12:04:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.61.2.1 1999/05/29 19:10:02 cort Exp $ + * $Id: idle.c,v 1.61.2.2 1999/06/15 16:54:14 cort Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -298,7 +298,7 @@ case 7: /* 603ev */ case 8: /* 750 */ save_flags(msr); - cli(); + __cli(); if (!current->need_resched) { asm("mfspr %0,1008" : "=r" (hid0) :); hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE); diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.2.10/linux/arch/ppc/kernel/irq.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/irq.c Mon Aug 9 12:04:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.105.2.1 1999/05/29 19:10:05 cort Exp $ + * $Id: irq.c,v 1.105.2.2 1999/06/17 01:16:10 paulus Exp $ * * arch/ppc/kernel/irq.c * @@ -187,6 +187,12 @@ void free_irq(unsigned int irq, void *dev_id) { request_irq(irq, NULL, 0, NULL, dev_id); +} + +/* XXX should implement irq disable depth like on intel */ +void disable_irq_nosync(unsigned int irq_nr) +{ + mask_irq(irq_nr); } void disable_irq(unsigned int irq_nr) diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.2.10/linux/arch/ppc/kernel/misc.S Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/misc.S Mon Aug 9 12:04:57 1999 @@ -650,17 +650,19 @@ /* * Create a kernel thread - * __kernel_thread(flags, fn, arg) + * kernel_thread(fn, arg, flags) */ -_GLOBAL(__kernel_thread) +_GLOBAL(kernel_thread) + mr r6,r3 /* function */ + ori r3,r5,CLONE_VM /* flags */ li r0,__NR_clone sc cmpi 0,r3,0 /* parent or child? */ bnelr /* return if parent */ li r0,0 /* clear out p->tss.regs */ stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */ - mtlr r4 /* fn addr in lr */ - mr r3,r5 /* load arg and call fn */ + mtlr r6 /* fn addr in lr */ + mr r3,r4 /* load arg and call fn */ blrl li r0,__NR_exit /* exit after child exits */ li r3,0 @@ -866,7 +868,7 @@ .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll -#ifdef CONFIG_NFS +#ifdef CONFIG_NFSD .long sys_nfsservctl #else .long sys_ni_syscall diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.2.10/linux/arch/ppc/kernel/mk_defs.c Tue May 11 08:24:32 1999 +++ linux/arch/ppc/kernel/mk_defs.c Mon Aug 9 12:04:57 1999 @@ -97,5 +97,6 @@ DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); + DEFINE(CLONE_VM, CLONE_VM); return 0; } diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.2.10/linux/arch/ppc/kernel/pci.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/pci.c Mon Aug 9 12:04:38 1999 @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.2.10/linux/arch/ppc/kernel/pmac_setup.c Tue May 11 08:24:32 1999 +++ linux/arch/ppc/kernel/pmac_setup.c Mon Aug 9 12:04:57 1999 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,7 @@ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); +static void init_p2pbridge(void); __pmac int @@ -254,6 +256,7 @@ ohare_init(); *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + init_p2pbridge(); /* Checks "l2cr-value" property in the registry */ if ( (_get_PVR() >> 16) == 8) { @@ -298,6 +301,31 @@ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); } +/* + * Tweak the PCI-PCI bridge chip on the blue & white G3s. + */ +__initfunc(static void init_p2pbridge(void)) +{ + struct device_node *p2pbridge; + unsigned char bus, devfn; + unsigned short val; + + /* XXX it would be better here to identify the specific + PCI-PCI bridge chip we have. */ + if ((p2pbridge = find_devices("pci-bridge")) == 0 + || p2pbridge->parent == NULL + || strcmp(p2pbridge->parent->name, "pci") != 0) + return; + + if (pci_device_loc(p2pbridge, &bus, &devfn) < 0) + return; + + pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); + val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; + pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val); + pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); +} + __initfunc(static void ohare_init(void)) { /* @@ -487,13 +515,13 @@ void pmac_ide_insw(ide_ioreg_t port, void *buf, int ns) { - ide_insw(port, buf, ns); + ide_insw(port+_IO_BASE, buf, ns); } void pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns) { - ide_outsw(port, buf, ns); + ide_outsw(port+_IO_BASE, buf, ns); } int @@ -600,7 +628,9 @@ ppc_ide_md.fix_driveid = pmac_ide_fix_driveid; ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; - ppc_ide_md.io_base = 0; + /* _IO_BASE isn't set yet, so it's just as well that + ppc_ide_md.io_base isn't used any more. :-) */ + ppc_ide_md.io_base = _IO_BASE; #endif } diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.2.10/linux/arch/ppc/kernel/ppc-stub.c Tue Aug 4 16:06:36 1998 +++ linux/arch/ppc/kernel/ppc-stub.c Mon Aug 9 12:04:38 1999 @@ -107,7 +107,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.2.10/linux/arch/ppc/kernel/ppc_htab.c Mon Dec 21 08:37:20 1998 +++ linux/arch/ppc/kernel/ppc_htab.c Mon Aug 9 12:04:57 1999 @@ -253,6 +253,8 @@ return 0; if (n > strlen(buffer) - *ppos) n = strlen(buffer) - *ppos; + if (n > count) + n = count; copy_to_user(buf, buffer + *ppos, n); *ppos += n; return n; diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.2.10/linux/arch/ppc/kernel/ppc_ksyms.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/ppc_ksyms.c Mon Aug 9 12:04:57 1999 @@ -30,8 +30,8 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include +/* Tell string.h we don't want memcpy etc. as cpp defines */ +#define EXPORT_SYMTAB_STROPS extern void transfer_to_handler(void); extern void int_return(void); @@ -55,7 +55,6 @@ EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(int_return); EXPORT_SYMBOL(do_IRQ); -EXPORT_SYMBOL(init_task_union); EXPORT_SYMBOL(MachineCheckException); EXPORT_SYMBOL(AlignmentException); EXPORT_SYMBOL(ProgramCheckException); @@ -65,6 +64,7 @@ EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(ppc_local_irq_count); EXPORT_SYMBOL(ppc_local_bh_count); @@ -111,11 +111,6 @@ EXPORT_SYMBOL(strspn); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memscan); -EXPORT_SYMBOL(memcmp); /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */ EXPORT_SYMBOL(csum_partial_copy_generic); @@ -152,9 +147,10 @@ EXPORT_SYMBOL(ide_insw); EXPORT_SYMBOL(ide_outsw); +EXPORT_SYMBOL(ppc_ide_md); EXPORT_SYMBOL(start_thread); -EXPORT_SYMBOL(__kernel_thread); +EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__cli); EXPORT_SYMBOL(__sti); @@ -217,8 +213,9 @@ EXPORT_SYMBOL(abs); EXPORT_SYMBOL(device_is_compatible); -/* The following are special because they're not called - explicitly (the C compiler generates them). Fortunately, - their interface isn't gonna change any time soon now, so - it's OK to leave it out of version control. */ EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(memcmp); diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.2.10/linux/arch/ppc/kernel/process.c Tue May 11 08:24:32 1999 +++ linux/arch/ppc/kernel/process.c Mon Aug 9 12:04:38 1999 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.2.10/linux/arch/ppc/kernel/prom.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/prom.c Mon Aug 9 12:04:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.54.2.1 1999/05/29 19:10:12 cort Exp $ + * $Id: prom.c,v 1.54.2.3 1999/07/02 19:58:27 cort Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -338,7 +338,9 @@ */ model = (char *) early_get_property (r4 + bi->deviceTreeOffset, 4, RELOC("model")); - if (model && strcmp(model, RELOC("iMac,1")) == 0) { + if (model + && (strcmp(model, RELOC("iMac,1")) == 0 + || strcmp(model, RELOC("PowerMac1,1")) == 0)) { out_le32((unsigned *)0x80880008, 1); /* XXX */ } } @@ -500,8 +502,8 @@ return; /* copy the holding pattern code to someplace safe (8M) */ - memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 ); - for (i = 8<<20; i < ((8<<20)+0x10000); i += 32) + memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 ); + for (i = 8<<20; i < ((8<<20)+0x100); i += 32) { asm volatile("dcbf 0,%0" : : "r" (i) : "memory"); asm volatile("icbi 0,%0" : : "r" (i) : "memory"); @@ -887,11 +889,11 @@ && (imp = (struct pci_intr_map *) get_property(np->parent, "interrupt-map", &ml)) != 0 && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { - unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00; + unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00; np->n_intrs = 0; np->intrs = (struct interrupt_info *) mem_start; for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) { - if (imp[i].addr.a_hi == busdevfn) { + if (imp[i].addr.a_hi == devfn) { np->intrs[np->n_intrs].line = imp[i].intr; np->intrs[np->n_intrs].sense = 0; ++np->n_intrs; diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.2.10/linux/arch/ppc/kernel/setup.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/setup.c Mon Aug 9 12:04:38 1999 @@ -31,7 +31,6 @@ #endif #include #include -#include extern void pmac_init(unsigned long r3, unsigned long r4, diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.2.10/linux/arch/ppc/kernel/signal.c Thu Apr 29 12:39:01 1999 +++ linux/arch/ppc/kernel/signal.c Mon Aug 9 12:04:57 1999 @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $ + * $Id: signal.c,v 1.24.2.1 1999/06/17 01:18:22 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -455,6 +455,7 @@ default: lock_kernel(); sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.2.10/linux/arch/ppc/kernel/smp.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/smp.c Mon Aug 9 12:04:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.49.2.1 1999/05/29 19:10:20 cort Exp $ + * $Id: smp.c,v 1.49.2.3 1999/06/24 17:12:55 cort Exp $ * * Smp support for ppc. * @@ -243,20 +243,21 @@ { extern struct task_struct *current_set[NR_CPUS]; extern void __secondary_start_psurge(void); - int i; + extern void __secondary_start_chrp(void); + int i, cpu_nr; struct task_struct *p; unsigned long a; printk("Entering SMP Mode...\n"); /* let other processors know to not do certain initialization */ first_cpu_booted = 1; + smp_num_cpus = 1; /* * assume for now that the first cpu booted is * cpu 0, the master -- Cort */ cpu_callin_map[0] = 1; - cpu_callin_map[1] = 0; smp_store_cpu_info(0); active_kernel_processor = 0; current->processor = 0; @@ -282,16 +283,12 @@ { case _MACH_Pmac: /* assume powersurge board - 2 processors -- Cort */ - smp_num_cpus = 2; + cpu_nr = 2; break; case _MACH_chrp: - smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) + cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; - /* get our processor # - we may not be cpu 0 */ - printk("SMP %d processors, boot CPU is %d (should be 0)\n", - smp_num_cpus, - 10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/); break; } @@ -299,7 +296,7 @@ * only check for cpus we know exist. We keep the callin map * with cpus at the bottom -- Cort */ - for ( i = 1 ; i < smp_num_cpus; i++ ) + for ( i = 1 ; i < cpu_nr; i++ ) { int c; @@ -332,6 +329,19 @@ case _MACH_chrp: *(unsigned long *)KERNELBASE = i; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); +#if 0 + device = find_type_devices("cpu"); + /* assume cpu device list is in order, find the ith cpu */ + for ( a = i; device && a; device = device->next, a-- ) + ; + if ( !device ) + break; + printk( "Starting %s (%lu): ", device->full_name, + *(ulong *)get_property(device, "reg", NULL) ); + call_rtas( "start-cpu", 3, 1, NULL, + *(ulong *)get_property(device, "reg", NULL), + __pa(__secondary_start_chrp), i); +#endif break; } @@ -349,6 +359,7 @@ /* this sync's the decr's -- Cort */ if ( _machine == _MACH_Pmac ) set_dec(decrementer_count); + smp_num_cpus++; } else { printk("Processor %d is stuck.\n", i); } @@ -366,7 +377,6 @@ void __init smp_commence(void) { - printk("SMP %d: smp_commence()\n",current->processor); /* * Lets the callin's below out of their loop. */ @@ -381,16 +391,12 @@ /* Activate a secondary processor. */ asmlinkage int __init start_secondary(void *unused) { - printk("SMP %d: start_secondary()\n",current->processor); smp_callin(); return cpu_idle(NULL); } void __init smp_callin(void) { - int i; - - printk("SMP %d: smp_callin()\n",current->processor); smp_store_cpu_info(current->processor); set_dec(decrementer_count); @@ -407,7 +413,6 @@ void __init smp_setup(char *str, int *ints) { - printk("SMP %d: smp_setup()\n",current->processor); } int __init setup_profiling_timer(unsigned int multiplier) diff -u --recursive --new-file v2.2.10/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.2.10/linux/arch/ppc/kernel/syscalls.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/kernel/syscalls.c Mon Aug 9 12:04:38 1999 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.2.10/linux/arch/ppc/mm/init.c Fri Jun 4 13:30:47 1999 +++ linux/arch/ppc/mm/init.c Mon Aug 9 12:04:57 1999 @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.164.2.2 1999/06/03 03:03:53 paulus Exp $ + * $Id: init.c,v 1.164.2.4 1999/06/17 19:05:21 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -268,9 +268,12 @@ { printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ", p->comm,p->pid, - atomic_read(&p->mm->count),p->mm->context, - p->mm->context<<4, p->tss.last_syscall, - user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip, + (p->mm)?atomic_read(&p->mm->count):0, + (p->mm)?p->mm->context:0, + (p->mm)?(p->mm->context<<4):0, + p->tss.last_syscall, + (p->tss.regs)?user_mode(p->tss.regs) ? 'u' : 'k' : '?', + (p->tss.regs)?p->tss.regs->nip:0, (ulong)p); { int iscur = 0; @@ -1301,7 +1304,7 @@ int i; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (768<<20) +#define RAM_LIMIT (256<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { diff -u --recursive --new-file v2.2.10/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig --- v2.2.10/linux/arch/ppc/pmac_defconfig Wed Mar 10 21:30:32 1999 +++ linux/arch/ppc/pmac_defconfig Mon Aug 9 12:04:57 1999 @@ -7,6 +7,7 @@ # CONFIG_PPC=y CONFIG_6xx=y +# CONFIG_PPC64 is not set # CONFIG_8xx is not set CONFIG_PMAC=y # CONFIG_PREP is not set @@ -14,8 +15,9 @@ # CONFIG_ALL_PPC is not set # CONFIG_APUS is not set # CONFIG_MBX is not set -CONFIG_MACH_SPECIFIC=y # CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_6xx=y # # General setup @@ -35,7 +37,8 @@ CONFIG_KERNEL_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set -# CONFIG_PARPORT is not set +CONFIG_PARPORT=m +# CONFIG_PARPORT_PC is not set # CONFIG_VGA_CONSOLE is not set CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y @@ -43,13 +46,12 @@ CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set CONFIG_ADBMOUSE=y -CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y -# CONFIG_KGDB is not set -# CONFIG_XMON is not set # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y +# CONFIG_MOTOROLA_HOTSWAP is not set # # Plug and Play support @@ -73,7 +75,15 @@ # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +CONFIG_BLK_DEV_CMD646=y # CONFIG_BLK_DEV_SL82C105 is not set CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -84,14 +94,16 @@ # # Additional Block Devices # -# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_PARIDE_PARPORT=m # CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_HD is not set # @@ -119,7 +131,6 @@ # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set @@ -173,7 +184,8 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_OVERRIDE_CMDS is not set +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_ADVANSYS is not set @@ -189,15 +201,28 @@ # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_SYM53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -212,10 +237,18 @@ # Network device support # CONFIG_NETDEVICES=y + +# +# ARCnet devices +# # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y @@ -225,10 +258,10 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set -# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y # CONFIG_PCNET32 is not set +# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -247,22 +280,36 @@ # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_DLCI is not set + +# +# Appletalk devices +# # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set -CONFIG_PPP=y +# CONFIG_PLIP is not set +CONFIG_PPP=m # # CCP compressors for PPP are only built as modules. # # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set + +# +# Token ring devices +# # CONFIG_TR is not set +# CONFIG_RCPCI is not set # CONFIG_SHAPER is not set + +# +# Wan interfaces +# # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set -# CONFIG_RCPCI is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set # # Amateur Radio support @@ -275,7 +322,7 @@ # CONFIG_ISDN is not set # -# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# Old CD-ROM drivers (not SCSI, not IDE) # # CONFIG_CD_NO_IDESCSI is not set @@ -283,6 +330,7 @@ # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y @@ -319,6 +367,7 @@ # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set @@ -334,6 +383,7 @@ # Joystick support # # CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set # # Ftape, the floppy tape device driver @@ -341,6 +391,11 @@ # CONFIG_FTAPE is not set # +# USB drivers - not for the faint of heart +# +# CONFIG_USB is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -364,6 +419,7 @@ CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_EFS_FS is not set # # Network File Systems @@ -415,7 +471,7 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_R is not set # @@ -429,3 +485,10 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_OSS is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.2.10/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c --- v2.2.10/linux/arch/sparc/ap1000/aplib.c Tue Aug 4 16:03:34 1998 +++ linux/arch/sparc/ap1000/aplib.c Mon Aug 9 12:04:38 1999 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.2.10/linux/arch/sparc/defconfig Wed Jun 2 09:55:38 1999 +++ linux/arch/sparc/defconfig Mon Aug 9 12:05:09 1999 @@ -243,6 +243,8 @@ CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y +CONFIG_EFS_FS=m +CONFIG_SGI_PARTITION=y # # Network File Systems @@ -254,7 +256,6 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m -CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -u --recursive --new-file v2.2.10/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.2.10/linux/arch/sparc/kernel/pcic.c Tue Mar 16 21:52:05 1999 +++ linux/arch/sparc/kernel/pcic.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $ +/* $Id: pcic.c,v 1.5.2.1 1999/08/07 10:42:43 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.2.10/linux/arch/sparc/kernel/process.c Tue May 11 08:24:31 1999 +++ linux/arch/sparc/kernel/process.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $ +/* $Id: process.c,v 1.137.2.1 1999/08/07 10:42:45 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -37,7 +37,6 @@ #include #include #include -#include #include extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); diff -u --recursive --new-file v2.2.10/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v2.2.10/linux/arch/sparc/kernel/sparc-stub.c Tue Apr 14 17:44:19 1998 +++ linux/arch/sparc/kernel/sparc-stub.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.24 1998/02/08 07:58:44 ecd Exp $ +/* $Id: sparc-stub.c,v 1.24.2.1 1999/08/07 10:42:46 davem Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux @@ -105,7 +105,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.2.10/linux/arch/sparc/kernel/sparc_ksyms.c Sun Mar 21 07:23:38 1999 +++ linux/arch/sparc/kernel/sparc_ksyms.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.77.2.1 1999/08/07 10:42:47 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -40,7 +40,6 @@ #include #endif #include -#include #include struct poll { diff -u --recursive --new-file v2.2.10/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.2.10/linux/arch/sparc/kernel/sys_sunos.c Wed Jun 2 09:55:38 1999 +++ linux/arch/sparc/kernel/sys_sunos.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94.2.1 1999/05/24 19:42:30 davem Exp $ +/* $Id: sys_sunos.c,v 1.94.2.2 1999/08/07 10:42:49 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c --- v2.2.10/linux/arch/sparc/lib/debuglocks.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/lib/debuglocks.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.7 1999/04/21 02:26:58 anton Exp $ +/* $Id: debuglocks.c,v 1.7.2.1 1999/08/05 09:39:27 anton Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -53,7 +53,7 @@ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); for(i = 0; i < NR_CPUS; i++) - printk(" reader[i]=%08lx", lock->reader_pc[i]); + printk(" reader[%d]=%08lx", i, lock->reader_pc[i]); printk("\n"); } diff -u --recursive --new-file v2.2.10/linux/arch/sparc/math-emu/sfp-machine.h linux/arch/sparc/math-emu/sfp-machine.h --- v2.2.10/linux/arch/sparc/math-emu/sfp-machine.h Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/math-emu/sfp-machine.h Mon Aug 9 12:04:57 1999 @@ -91,6 +91,11 @@ #define _FP_NANFRAC_D _FP_QNANBIT_D, 0 #define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0 +/* On some architectures float-to-int conversions return a result + * code. On others (e.g. Sparc) they return 0 + */ +#define _FTOI_RESULT 0 + #define _FP_KEEPNANFRACP 1 /* This macro appears to be called when both X and Y are NaNs, and @@ -104,7 +109,25 @@ _FP_FRAC_COPY_##wc(R,Y); \ R##_c = FP_CLS_NAN; \ } while (0) + +#define _FP_CHOOSENAN_SQRT(fs, wc, R, X) \ + do { \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } while (0) + +#define __FP_UNPACK_DENORM(fs, wc, X) \ + { \ + _FP_I_TYPE _shift; \ + _FP_FRAC_CLZ_##wc(_shift, X); \ + _shift -= _FP_FRACXBITS_##fs; \ + _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ + X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ + X##_c = FP_CLS_NORMAL; \ + } + #define __FP_UNPACK_RAW_1(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ diff -u --recursive --new-file v2.2.10/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.2.10/linux/arch/sparc/mm/fault.c Wed Mar 10 16:53:36 1999 +++ linux/arch/sparc/mm/fault.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $ +/* $Id: fault.c,v 1.101.2.2 1999/08/07 10:42:53 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -383,12 +382,13 @@ if(expand_stack(vma, address)) goto bad_area; good_area: - if(write) + if(write) { if(!(vma->vm_flags & VM_WRITE)) goto bad_area; - else + } else { if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; + } if (!handle_mm_fault(current, vma, address, write)) goto do_sigbus; up(&mm->mmap_sem); diff -u --recursive --new-file v2.2.10/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.2.10/linux/arch/sparc/mm/init.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc/mm/init.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.65 1999/04/09 16:28:03 davem Exp $ +/* $Id: init.c,v 1.65.2.1 1999/08/07 10:42:54 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -245,7 +245,7 @@ struct page *page, *end; /* Saves us work later. */ - memset((void *) ZERO_PAGE, 0, PAGE_SIZE); + memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE); end_mem &= PAGE_MASK; max_mapnr = MAP_NR(end_mem); diff -u --recursive --new-file v2.2.10/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.2.10/linux/arch/sparc/mm/srmmu.c Wed Apr 28 10:58:10 1999 +++ linux/arch/sparc/mm/srmmu.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.187 1999/04/28 17:00:45 davem Exp $ +/* $Id: srmmu.c,v 1.187.2.1 1999/08/07 10:42:55 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -114,6 +114,7 @@ #define srmmu_ahashfn(addr) ((addr) >> 24) int viking_mxcc_present = 0; +static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED; /* Physical memory can be _very_ non-contiguous on the sun4m, especially * the SS10/20 class machines and with the latest openprom revisions. @@ -819,7 +820,9 @@ static void srmmu_switch_to_context(struct task_struct *tsk) { if(tsk->mm->context == NO_CONTEXT) { + spin_lock(&srmmu_context_spinlock); alloc_context(tsk->mm); + spin_unlock(&srmmu_context_spinlock); ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); } srmmu_set_context(tsk->mm->context); @@ -827,7 +830,9 @@ static void srmmu_init_new_context(struct mm_struct *mm) { + spin_lock(&srmmu_context_spinlock); alloc_context(mm); + spin_unlock(&srmmu_context_spinlock); flush_cache_mm(mm); ctxd_set(&srmmu_context_table[mm->context], mm->pgd); @@ -1398,7 +1403,9 @@ if(tsk->mm->context == NO_CONTEXT) { ctxd_t *ctxp; + spin_lock(&srmmu_context_spinlock); alloc_context(tsk->mm); + spin_unlock(&srmmu_context_spinlock); ctxp = &srmmu_context_table[tsk->mm->context]; srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4)))); hypersparc_flush_page_to_ram((unsigned long)ctxp); @@ -1411,7 +1418,9 @@ { ctxd_t *ctxp; + spin_lock(&srmmu_context_spinlock); alloc_context(mm); + spin_unlock(&srmmu_context_spinlock); ctxp = &srmmu_context_table[mm->context]; srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4)))); diff -u --recursive --new-file v2.2.10/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S --- v2.2.10/linux/arch/sparc/mm/tsunami.S Thu May 15 16:48:02 1997 +++ linux/arch/sparc/mm/tsunami.S Mon Aug 9 12:05:45 1999 @@ -1,4 +1,4 @@ -/* $Id: tsunami.S,v 1.1 1997/05/03 05:09:09 davem Exp $ +/* $Id: tsunami.S,v 1.1.6.1 1999/08/09 13:00:16 davem Exp $ * tsunami.S: High speed MicroSparc-I mmu/cache operations. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,11 @@ tsunami_flush_tlb_all: mov 0x400, %o1 sta %g0, [%o1] ASI_M_FLUSH_PROBE + nop + nop + nop + nop + nop tsunami_flush_tlb_out: retl nop @@ -85,6 +90,11 @@ lda [%g1] ASI_M_MMUREGS, %g5 sta %o3, [%g1] ASI_M_MMUREGS sta %g0, [%o1] ASI_M_FLUSH_PROBE + nop + nop + nop + nop + nop tsunami_flush_tlb_page_out: retl sta %g5, [%g1] ASI_M_MMUREGS diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.2.10/linux/arch/sparc64/config.in Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc64/config.in Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.2.10/linux/arch/sparc64/defconfig Wed Jun 2 09:55:38 1999 +++ linux/arch/sparc64/defconfig Mon Aug 9 12:05:09 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 @@ -281,6 +287,8 @@ CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y +CONFIG_EFS_FS=m +CONFIG_SGI_PARTITION=y # # Network File Systems @@ -292,7 +300,6 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m -CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.2.10/linux/arch/sparc64/kernel/binfmt_aout32.c Mon Mar 22 10:06:36 1999 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Mon Aug 9 12:04:38 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 --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.2.10/linux/arch/sparc64/kernel/head.S Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc64/kernel/head.S Mon Aug 9 12:05:45 1999 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.60 1999/04/12 08:08:21 davem Exp $ +/* $Id: head.S,v 1.60.2.1 1999/08/09 13:00:25 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -75,6 +75,16 @@ * PROM entry point is on %o4 */ sparc64_boot: +#if 1 + /* XXX Disable reception of correctable memory errors until + * XXX we code up the proper handler... -DaveM + */ + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g1 + andn %g1, 0x1, %g1 + stxa %g1, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync +#endif + /* Typically PROM has already enabled both MMU's and both on-chip * caches, but we do it here anyway just to be paranoid. */ diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.2.10/linux/arch/sparc64/kernel/psycho.c Thu Apr 22 19:24:51 1999 +++ linux/arch/sparc64/kernel/psycho.c Mon Aug 9 12:05:45 1999 @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $ +/* $Id: psycho.c,v 1.85.2.2 1999/08/09 13:00:21 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -756,14 +756,16 @@ struct pci_dev *pdev; unsigned short stmp; unsigned int itmp; + unsigned char btmp; for(pdev = pci_devices; pdev; pdev = pdev->next) { if(pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); break; } } + for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -800,8 +802,28 @@ * timer settings. But do set primary and secondary * latency timers. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); - pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); + + /* Here is an overview of the behavior of various + * revisions of APB wrt. write buffer full conditions: + * + * Revision 1.0: pre-FCS, always stalls + * Revision 1.1: pre-FCS, always disconnects + * Revision 1.2: same behavior as rev 1.1 + * Revision 1.3: behavior is determined by bit 4 of + * secondary control register + * 0: stall initially, but disconnect + * if PCI latency timer expires + * 1: always disconnect + * + * By setting the bit, since it is reserved in previous + * revisions of APB, we get all FCS hardware to have + * identical behavior when APB's write buffer fills up. + */ + pci_read_config_byte(pdev, APB_SECONDARY_CONTROL, &btmp); + btmp |= APB_SECONDARY_CTL_DISCON_FULL; + pci_write_config_byte(pdev, APB_SECONDARY_CONTROL, btmp); } } } diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.2.10/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue May 11 08:24:32 1999 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.58.2.1 1999/06/28 11:27:57 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -206,6 +206,7 @@ /* Kernel thread creation. */ EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(init_mm); /* prom symbols */ EXPORT_SYMBOL(idprom); diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.2.10/linux/arch/sparc64/kernel/sys_sunos32.c Wed Jun 2 09:55:38 1999 +++ linux/arch/sparc64/kernel/sys_sunos32.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.22.2.1 1999/05/24 19:42:36 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22.2.2 1999/08/07 10:43:02 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S --- v2.2.10/linux/arch/sparc64/kernel/trampoline.S Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/kernel/trampoline.S Mon Aug 9 12:05:45 1999 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.8 1998/12/09 21:01:15 davem Exp $ +/* $Id: trampoline.S,v 1.8.2.1 1999/08/09 13:00:27 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -23,6 +23,15 @@ .globl sparc64_cpu_startup, sparc64_cpu_startup_end sparc64_cpu_startup: flushw +#if 1 + /* XXX Disable reception of correctable memory errors until + * XXX we code up the proper handler... -DaveM + */ + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g1 + andn %g1, 0x1, %g1 + stxa %g1, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync +#endif mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1 stxa %g1, [%g0] ASI_LSU_CONTROL membar #Sync diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/fdtoi.c linux/arch/sparc64/math-emu/fdtoi.c --- v2.2.10/linux/arch/sparc64/math-emu/fdtoi.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/math-emu/fdtoi.c Mon Aug 9 12:04:57 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 32, 1); *rd = r; - return 0; + return _FTOI_RESULT; } diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/fdtox.c linux/arch/sparc64/math-emu/fdtox.c --- v2.2.10/linux/arch/sparc64/math-emu/fdtox.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/math-emu/fdtox.c Mon Aug 9 12:04:57 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 64, 1); *rd = r; - return 0; + return _FTOI_RESULT; } diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/fstoi.c linux/arch/sparc64/math-emu/fstoi.c --- v2.2.10/linux/arch/sparc64/math-emu/fstoi.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/math-emu/fstoi.c Mon Aug 9 12:04:57 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 32, 1); *rd = r; - return 0; + return _FTOI_RESULT; } diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/fstox.c linux/arch/sparc64/math-emu/fstox.c --- v2.2.10/linux/arch/sparc64/math-emu/fstox.c Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/math-emu/fstox.c Mon Aug 9 12:04:57 1999 @@ -9,5 +9,5 @@ __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 64, 1); *rd = r; - return 0; + return _FTOI_RESULT; } diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/op-common.h linux/arch/sparc64/math-emu/op-common.h --- v2.2.10/linux/arch/sparc64/math-emu/op-common.h Wed Mar 10 16:53:37 1999 +++ linux/arch/sparc64/math-emu/op-common.h Mon Aug 9 12:05:09 1999 @@ -1,6 +1,5 @@ - #define _FP_DECL(wc, X) \ - _FP_I_TYPE X##_c, X##_s, X##_e; \ + _FP_I_TYPE X##_c, X##_s, X##_e, X##_r=0; \ _FP_FRAC_DECL_##wc(X) /* @@ -8,6 +7,7 @@ * of fp value and normalizing both the exponent and the fraction. */ +#ifndef _FP_UNPACK_CANONICAL #define _FP_UNPACK_CANONICAL(fs, wc, X) \ do { \ switch (X##_e) \ @@ -23,15 +23,8 @@ if (_FP_FRAC_ZEROP_##wc(X)) \ X##_c = FP_CLS_ZERO; \ else \ - { \ - /* a denormalized number */ \ - _FP_I_TYPE _shift; \ - _FP_FRAC_CLZ_##wc(_shift, X); \ - _shift -= _FP_FRACXBITS_##fs; \ - _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ - X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ - X##_c = FP_CLS_NORMAL; \ - } \ + /* a denormalized number */ \ + __FP_UNPACK_DENORM(fs, wc, X) \ break; \ \ case _FP_EXPMAX_##fs: \ @@ -43,6 +36,7 @@ break; \ } \ } while (0) +#endif /* _FP_UNPACK_CANONICAL */ /* @@ -52,15 +46,16 @@ * extracted -- but that is ok, we can regenerate them now. */ +#ifndef _FP_PACK_CANONICAL #define _FP_PACK_CANONICAL(fs, wc, X) \ -({int __ret = 0; \ +({int __pk__ret = X##_r; \ switch (X##_c) \ { \ case FP_CLS_NORMAL: \ X##_e += _FP_EXPBIAS_##fs; \ if (X##_e > 0) \ { \ - __ret |= _FP_ROUND(wc, X); \ + __pk__ret |= _FP_ROUND(wc, X); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ @@ -73,7 +68,7 @@ /* overflow to infinity */ \ X##_e = _FP_EXPMAX_##fs; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - __ret |= EFLAG_OVERFLOW; \ + __pk__ret |= EFLAG_OVERFLOW; \ } \ } \ else \ @@ -83,7 +78,7 @@ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - __ret |= _FP_ROUND(wc, X); \ + __pk__ret |= _FP_ROUND(wc, X); \ _FP_FRAC_SLL_##wc(X, 1); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ @@ -94,7 +89,7 @@ { \ X##_e = 0; \ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ - __ret |= EFLAG_UNDERFLOW; \ + __pk__ret |= EFLAG_UNDERFLOW; \ } \ } \ else \ @@ -102,7 +97,7 @@ /* underflow to zero */ \ X##_e = 0; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - __ret |= EFLAG_UNDERFLOW; \ + __pk__ret |= EFLAG_UNDERFLOW; \ } \ } \ break; \ @@ -128,16 +123,18 @@ _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ break; \ } \ - __ret; \ + __pk__ret; \ }) - +#endif /* _FP_PACK_CANONICAL */ /* * Main addition routine. The input values should be cooked. */ - +#ifndef _FP_ADD #define _FP_ADD(fs, wc, R, X, Y) \ do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ { \ case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ @@ -150,8 +147,10 @@ diff = -diff; \ if (diff <= _FP_WFRACBITS_##fs) \ _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ - else if (!_FP_FRAC_ZEROP_##wc(X)) \ + else if (!_FP_FRAC_ZEROP_##wc(X)) { \ _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ + R_r |= EFLAG_INEXACT; \ + } \ else \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ R##_e = Y##_e; \ @@ -162,8 +161,10 @@ { \ if (diff <= _FP_WFRACBITS_##fs) \ _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ - else if (!_FP_FRAC_ZEROP_##wc(Y)) \ + else if (!_FP_FRAC_ZEROP_##wc(Y)) { \ _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ + R_r |= EFLAG_INEXACT; \ + } \ else \ _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \ } \ @@ -247,6 +248,7 @@ _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ R##_s = X##_s ^ Y##_s; \ R##_c = FP_CLS_NAN; \ + R##_r |= EFLAG_INVALID; \ break; \ } \ /* FALLTHRU */ \ @@ -276,28 +278,33 @@ abort(); \ } \ } while (0) +#endif /* _FP_ADD */ /* * Main negation routine. FIXME -- when we care about setting exception * bits reliably, this will not do. We should examine all of the fp classes. */ - +#ifndef _FP_NEG #define _FP_NEG(fs, wc, R, X) \ do { \ + R##_r |= X##_r; \ _FP_FRAC_COPY_##wc(R, X); \ R##_c = X##_c; \ R##_e = X##_e; \ R##_s = 1 ^ X##_s; \ } while (0) +#endif /* _FP_NEG */ /* * Main multiplication routine. The input values should be cooked. */ - +#ifndef _FP_MUL #define _FP_MUL(fs, wc, R, X, Y) \ do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ R##_s = X##_s ^ Y##_s; \ switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ { \ @@ -351,14 +358,17 @@ abort(); \ } \ } while (0) +#endif /* _FP_MUL */ /* * Main division routine. The input values should be cooked. */ - +#ifndef _FP_DIV #define _FP_DIV(fs, wc, R, X, Y) \ do { \ + /* Propagate any flags that may have been set during unpacking */ \ + R##_r |= (X##_r | Y##_r); \ R##_s = X##_s ^ Y##_s; \ switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ { \ @@ -411,13 +421,14 @@ abort(); \ } \ } while (0) +#endif _FP_DIV /* * Main differential comparison routine. The inputs should be raw not * cooked. The return is -1,0,1 for normal values, 2 otherwise. */ - +#ifndef _FP_CMP #define _FP_CMP(fs, wc, ret, X, Y, un) \ do { \ /* NANs are unordered */ \ @@ -426,6 +437,18 @@ { \ ret = un; \ } \ + /* Deal with infinities */ \ + else if (X##_c == FP_CLS_INF) { \ + if(Y##_c == FP_CLS_INF) { \ + ret = Y##_s - X##_s; \ + } \ + else { \ + ret = X##_s ? -1 : 1; \ + } \ + } \ + else if(Y##_c == FP_CLS_INF) { \ + ret = Y##_s ? 1 : -1; \ + } \ else \ { \ int __is_zero_x; \ @@ -454,10 +477,12 @@ ret = 0; \ } \ } while (0) +#endif /* _FP_CMP */ /* Simplification for strict equality. */ +#ifndef _FP_CMP_EQ #define _FP_CMP_EQ(fs, wc, ret, X, Y) \ do { \ /* NANs are unordered */ \ @@ -473,21 +498,21 @@ && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ } \ } while (0) +#endif /* _FP_CMP_EQ */ /* * Main square root routine. The input value should be cooked. */ - +#ifndef _FP_SQRT #define _FP_SQRT(fs, wc, R, X) \ do { \ _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ _FP_W_TYPE q; \ + R##_r |= X##_r; \ switch (X##_c) \ { \ case FP_CLS_NAN: \ - R##_s = 0; \ - R##_c = FP_CLS_NAN; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + _FP_CHOOSENAN_SQRT(fs, wc, R, X); \ break; \ case FP_CLS_INF: \ if (X##_s) \ @@ -524,6 +549,7 @@ _FP_FRAC_SRL_##wc(R, 1); \ } \ } while (0) +#endif /* FP_SQRT */ /* * Convert from FP to integer @@ -552,56 +578,60 @@ * in r be signed or unsigned?'. r is always(?) declared unsigned. * Comments below are mine, BTW -- PMM */ -#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ - do { \ - switch (X##_c) \ - { \ - case FP_CLS_NORMAL: \ - if (X##_e < 0) \ - { \ - /* case FP_CLS_NAN: see above! */ \ - case FP_CLS_ZERO: \ - r = 0; \ - } \ - else if (X##_e >= rsize - (rsigned != 0)) \ - { /* overflow */ \ - case FP_CLS_NAN: \ - case FP_CLS_INF: \ - if (rsigned) \ - { \ - r = 1; \ - r <<= rsize - 1; \ - r -= 1 - X##_s; \ - } \ - else \ - { \ - r = 0; \ - if (!X##_s) \ - r = ~r; \ - } \ - } \ - else \ - { \ - if (_FP_W_TYPE_SIZE*wc < rsize) \ - { \ - _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ - r <<= X##_e - _FP_WFRACBITS_##fs; \ - } \ - else \ - { \ - if (X##_e >= _FP_WFRACBITS_##fs) \ - _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ - else \ - _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ - _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ - } \ - if (rsigned && X##_s) \ - r = -r; \ - } \ - break; \ - } \ +#ifndef _FP_TO_INT +#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ + do { \ + switch (X##_c) \ + { \ + case FP_CLS_NORMAL: \ + if (X##_e < 0) \ + { \ + /* case FP_CLS_NAN: see above! */ \ + case FP_CLS_ZERO: \ + r = 0; \ + } \ + else if (X##_e >= rsize - (rsigned != 0)) \ + { /* overflow */ \ + case FP_CLS_NAN: \ + case FP_CLS_INF: \ + if (rsigned) \ + { \ + r = 1; \ + r <<= rsize - 1; \ + r -= 1 - X##_s; \ + } \ + else \ + { \ + r = 0; \ + if (!X##_s) \ + r = ~r; \ + } \ + } \ + else \ + { \ + if (_FP_W_TYPE_SIZE*wc < rsize) \ + { \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + r <<= X##_e - _FP_WFRACBITS_##fs; \ + } \ + else \ + { \ + if (X##_e >= _FP_WFRACBITS_##fs) \ + _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ + else \ + _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ + _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ + } \ + if (rsigned && X##_s) \ + r = -r; \ + } \ + break; \ + } \ } while (0) +#endif /* _FP_TO_INT */ + +#ifndef _FP_FROM_INT #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ do { \ if (r) \ @@ -633,15 +663,18 @@ X##_c = FP_CLS_ZERO, X##_s = 0; \ } \ } while (0) +#endif /* FP_FROM_INT */ - +#ifndef FP_CONV #define FP_CONV(dfs,sfs,dwc,swc,D,S) \ do { \ _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ D##_e = S##_e; \ D##_c = S##_c; \ D##_s = S##_s; \ + D##_r |= S##_r; \ } while (0) +#endif FP_CONV /* * Helper primitives. diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/math-emu/sfp-machine.h linux/arch/sparc64/math-emu/sfp-machine.h --- v2.2.10/linux/arch/sparc64/math-emu/sfp-machine.h Tue Mar 16 21:52:06 1999 +++ linux/arch/sparc64/math-emu/sfp-machine.h Mon Aug 9 12:04:57 1999 @@ -34,6 +34,11 @@ #define _FP_NANFRAC_D _FP_QNANBIT_D #define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0 +/* On some architectures float-to-int conversions return a result + * code. On others (e.g. Sparc) they return 0 + */ +#define _FTOI_RESULT 0 + #define _FP_KEEPNANFRACP 1 #define _FP_CHOOSENAN(fs, wc, R, X, Y) \ do { \ @@ -41,6 +46,25 @@ _FP_FRAC_COPY_##wc(R,Y); \ R##_c = FP_CLS_NAN; \ } while (0) + +#define _FP_CHOOSENAN_SQRT(fs, wc, R, X) \ + do { \ + R##_s = 0; \ + R##_c = FP_CLS_NAN; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } while (0) + + +#define __FP_UNPACK_DENORM(fs, wc, X) \ + { \ + _FP_I_TYPE _shift; \ + _FP_FRAC_CLZ_##wc(_shift, X); \ + _shift -= _FP_FRACXBITS_##fs; \ + _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ + X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ + X##_c = FP_CLS_NORMAL; \ + } + #define __FP_UNPACK_RAW_1(fs, X, val) \ do { \ diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c --- v2.2.10/linux/arch/sparc64/mm/generic.c Mon Mar 15 16:10:43 1999 +++ linux/arch/sparc64/mm/generic.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $ +/* $Id: generic.c,v 1.8.2.1 1999/07/23 22:31:03 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -95,7 +95,8 @@ space); curend = address + 0x10000; offset += 0x10000; - } + } else + offset += PAGE_SIZE; } else offset += PAGE_SIZE; diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.2.10/linux/arch/sparc64/mm/init.c Tue May 11 08:24:32 1999 +++ linux/arch/sparc64/mm/init.c Mon Aug 9 12:04:38 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $ +/* $Id: init.c,v 1.127.2.1 1999/06/25 10:42:10 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -418,10 +418,12 @@ } if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); iommu->flushflag = 0; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } sregs->sbuf_fsync = __pa(&(iommu->flushflag)); @@ -446,6 +448,8 @@ start &= PAGE_MASK; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); /* 1) Clear the flush flag word */ @@ -455,7 +459,7 @@ * we want flushed. */ while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } @@ -483,6 +487,8 @@ volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); iommu->flushflag = 0; @@ -499,7 +505,7 @@ sg[sz--].dvma_addr = sbus_dvma_addr(start); start &= PAGE_MASK; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } } @@ -534,6 +540,8 @@ unsigned long flags, tmp; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); /* 1) Clear the flush flag word */ @@ -548,7 +556,7 @@ start &= PAGE_MASK; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } sz--; diff -u --recursive --new-file v2.2.10/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.2.10/linux/arch/sparc64/solaris/socksys.c Sun Oct 4 10:22:43 1998 +++ linux/arch/sparc64/solaris/socksys.c Mon Aug 9 12:05:09 1999 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $ +/* $Id: socksys.c,v 1.8.2.1 1999/08/07 10:43:11 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.2.10/linux/drivers/Makefile linux/drivers/Makefile --- v2.2.10/linux/drivers/Makefile Mon May 10 10:18:34 1999 +++ linux/drivers/Makefile Mon Aug 9 12:04:38 1999 @@ -9,8 +9,8 @@ SUB_DIRS := block char net misc sound MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \ - macintosh video dio zorro fc4 usb +ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp \ + macintosh video dio zorro fc4 usb ifdef CONFIG_DIO SUB_DIRS += dio @@ -34,6 +34,10 @@ SUB_DIRS += nubus endif +ifdef CONFIG_TC +SUB_DIRS += tc +endif + ifdef CONFIG_VT SUB_DIRS += video MOD_SUB_DIRS += video @@ -52,6 +56,11 @@ MOD_SUB_DIRS += usb endif endif + +ifdef CONFIG_SGI +SUB_DIRS += sgi +MOD_SUB_DIRS += sgi +endif # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel, # but some of the low-level things may also be modules. diff -u --recursive --new-file v2.2.10/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c --- v2.2.10/linux/drivers/ap1000/bif.c Fri May 8 00:47:24 1998 +++ linux/drivers/ap1000/bif.c Mon Aug 9 12:04:38 1999 @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.2.10/linux/drivers/block/Config.in Thu Apr 29 12:53:48 1999 +++ linux/drivers/block/Config.in Mon Aug 9 12:04:38 1999 @@ -114,6 +114,9 @@ bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD fi tristate 'XT hard disk support' CONFIG_BLK_DEV_XD +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 +fi # PARIDE doesn't need PARPORT, but if PARPORT is configured as a module, # PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option @@ -128,6 +131,7 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then source drivers/block/paride/Config.in fi +tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then define_bool CONFIG_BLK_DEV_HD y diff -u --recursive --new-file v2.2.10/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.2.10/linux/drivers/block/DAC960.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/DAC960.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,3320 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + 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 complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +#define DAC960_DriverVersion "2.2.2" +#define DAC960_DriverDate "3 July 1999" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DAC960.h" + + +/* + DAC960_ControllerCount is the number of DAC960 Controllers detected. +*/ + +static int + DAC960_ControllerCount = 0; + + +/* + DAC960_ActiveControllerCount is the number of Active DAC960 Controllers + detected. +*/ + +static int + DAC960_ActiveControllerCount = 0; + + +/* + DAC960_Controllers is an array of pointers to the DAC960 Controller + structures. +*/ + +static DAC960_Controller_T + *DAC960_Controllers[DAC960_MaxControllers] = { NULL }; + + +/* + DAC960_FileOperations is the File Operations structure for DAC960 Logical + Disk Devices. +*/ + +static FileOperations_T + DAC960_FileOperations = + { llseek: NULL, + read: block_read, + write: block_write, + readdir: NULL, + poll: NULL, + ioctl: DAC960_IOCTL, + mmap: NULL, + open: DAC960_Open, + release: DAC960_Release, + fsync: block_fsync, + fasync: NULL, + check_media_change: NULL, + revalidate: NULL }; + + +/* + DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry. +*/ + +static PROC_DirectoryEntry_T + DAC960_ProcDirectoryEntry; + + +/* + DAC960_NotifierBlock is the Notifier Block structure for DAC960 Driver. +*/ + +static NotifierBlock_T + DAC960_NotifierBlock = { DAC960_Finalize, NULL, 0 }; + + +/* + DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name, + Copyright Notice, and Electronic Mail Address. +*/ + +static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller) +{ + DAC960_Announce("***** DAC960 RAID Driver Version " + DAC960_DriverVersion " of " + DAC960_DriverDate " *****\n", Controller); + DAC960_Announce("Copyright 1998-1999 by Leonard N. Zubkoff " + "\n", Controller); +} + + +/* + DAC960_Failure prints a standardized error message, and then returns false. +*/ + +static boolean DAC960_Failure(DAC960_Controller_T *Controller, + char *ErrorMessage) +{ + DAC960_Error("While configuring DAC960 PCI RAID Controller at\n", + Controller); + if (Controller->IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Controller->Bus, Controller->Device, + Controller->Function, Controller->IO_Address, + Controller->PCI_Address); + DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage); + return false; +} + + +/* + DAC960_ClearCommand clears critical fields of Command. +*/ + +static inline void DAC960_ClearCommand(DAC960_Command_T *Command) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Words[0] = 0; + CommandMailbox->Words[1] = 0; + CommandMailbox->Words[2] = 0; + CommandMailbox->Words[3] = 0; + Command->CommandStatus = 0; +} + + +/* + DAC960_AllocateCommand allocates a Command structure from Controller's + free list. +*/ + +static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T + *Controller) +{ + DAC960_Command_T *Command = Controller->FreeCommands; + if (Command == NULL) return NULL; + Controller->FreeCommands = Command->Next; + Command->Next = NULL; + return Command; +} + + +/* + DAC960_DeallocateCommand deallocates Command, returning it to Controller's + free list. +*/ + +static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Command->Next = Controller->FreeCommands; + Controller->FreeCommands = Command; +} + + +/* + DAC960_QueueCommand queues Command. +*/ + +static void DAC960_QueueCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands; + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V4_Controller: + NextCommandMailbox = Controller->NextCommandMailbox; + DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox); + if (Controller->PreviousCommandMailbox1->Words[0] == 0 || + Controller->PreviousCommandMailbox2->Words[0] == 0) + { + if (Controller->DualModeMemoryMailboxInterface) + DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress); + else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + } + Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1; + Controller->PreviousCommandMailbox1 = NextCommandMailbox; + if (++NextCommandMailbox > Controller->LastCommandMailbox) + NextCommandMailbox = Controller->FirstCommandMailbox; + Controller->NextCommandMailbox = NextCommandMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_MailboxFullP(ControllerBaseAddress)) + udelay(1); + DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox); + DAC960_V3_NewCommand(ControllerBaseAddress); + break; + } +} + + +/* + DAC960_ExecuteCommand executes Command and waits for completion. It + returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + Semaphore_T Semaphore = MUTEX_LOCKED; + unsigned long ProcessorFlags; + Command->Semaphore = &Semaphore; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (!in_interrupt()) + down(&Semaphore); + return Command->CommandStatus == DAC960_NormalCompletion; +} + + +/* + DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3.CommandOpcode = CommandOpcode; + CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for + completion. It returns true on success and false on failure. +*/ + +static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller, + DAC960_CommandOpcode_T CommandOpcode, + unsigned char Channel, + unsigned char TargetID, + void *DataPointer) +{ + DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + boolean Result; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox->Type3D.CommandOpcode = CommandOpcode; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer); + Result = DAC960_ExecuteCommand(Command); + DAC960_DeallocateCommand(Command); + return Result; +} + + +/* + DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface. +*/ + +static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T + *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_CommandMailbox_T *CommandMailboxesMemory; + DAC960_StatusMailbox_T *StatusMailboxesMemory; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + void *SavedMemoryMailboxesAddress = NULL; + short NextCommandMailboxIndex = 0; + short NextStatusMailboxIndex = 0; + int TimeoutCounter = 1000000, i; + if (Controller->ControllerType == DAC960_V5_Controller) + DAC960_V5_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + else DAC960_V4_RestoreMemoryMailboxInfo(Controller, + &SavedMemoryMailboxesAddress, + &NextCommandMailboxIndex, + &NextStatusMailboxIndex); + if (SavedMemoryMailboxesAddress == NULL) + CommandMailboxesMemory = + (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1); + else CommandMailboxesMemory = SavedMemoryMailboxesAddress; + memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1); + Controller->FirstCommandMailbox = CommandMailboxesMemory; + CommandMailboxesMemory += DAC960_CommandMailboxCount - 1; + Controller->LastCommandMailbox = CommandMailboxesMemory; + Controller->NextCommandMailbox = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox1 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + if (--NextCommandMailboxIndex < 0) + NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1; + Controller->PreviousCommandMailbox2 = + &Controller->FirstCommandMailbox[NextCommandMailboxIndex]; + StatusMailboxesMemory = + (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1); + Controller->FirstStatusMailbox = StatusMailboxesMemory; + StatusMailboxesMemory += DAC960_StatusMailboxCount - 1; + Controller->LastStatusMailbox = StatusMailboxesMemory; + Controller->NextStatusMailbox = + &Controller->FirstStatusMailbox[NextStatusMailboxIndex]; + if (SavedMemoryMailboxesAddress != NULL) return true; + /* Enable the Memory Mailbox Interface. */ + Controller->DualModeMemoryMailboxInterface = true; + CommandMailbox.TypeX.CommandOpcode = 0x2B; + CommandMailbox.TypeX.CommandIdentifier = 0; + CommandMailbox.TypeX.CommandOpcode2 = 0x14; + CommandMailbox.TypeX.CommandMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstCommandMailbox); + CommandMailbox.TypeX.StatusMailboxesBusAddress = + Virtual_to_Bus(Controller->FirstStatusMailbox); + for (i = 0; i < 2; i++) + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxEmptyP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V5_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + case DAC960_V4_Controller: + while (--TimeoutCounter >= 0) + { + if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress); + while (--TimeoutCounter >= 0) + { + if (DAC960_V4_HardwareMailboxStatusAvailableP( + ControllerBaseAddress)) + break; + udelay(10); + } + if (TimeoutCounter < 0) return false; + CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress); + DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); + if (CommandStatus == DAC960_NormalCompletion) return true; + Controller->DualModeMemoryMailboxInterface = false; + CommandMailbox.TypeX.CommandOpcode2 = 0x10; + break; + default: + break; + } + return false; +} + + +/* + DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating + the PCI Configuration Space for Controller Type. +*/ + +static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType) +{ + unsigned short VendorID = 0, DeviceID = 0; + unsigned int MemoryWindowSize = 0; + PCI_Device_T *PCI_Device = NULL; + switch (ControllerType) + { + case DAC960_V5_Controller: + VendorID = PCI_VENDOR_ID_DEC; + DeviceID = PCI_DEVICE_ID_DEC_21285; + MemoryWindowSize = DAC960_V5_RegisterWindowSize; + break; + case DAC960_V4_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4; + MemoryWindowSize = DAC960_V4_RegisterWindowSize; + break; + case DAC960_V3_Controller: + VendorID = PCI_VENDOR_ID_MYLEX; + DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3; + MemoryWindowSize = DAC960_V3_RegisterWindowSize; + break; + } + while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL) + { + DAC960_Controller_T *Controller = (DAC960_Controller_T *) + kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); + DAC960_IO_Address_T IO_Address = 0; + DAC960_PCI_Address_T PCI_Address = 0; + unsigned char Bus = PCI_Device->bus->number; + unsigned char DeviceFunction = PCI_Device->devfn; + unsigned char Device = DeviceFunction >> 3; + unsigned char Function = DeviceFunction & 0x7; + unsigned int IRQ_Channel = PCI_Device->irq; + unsigned long BaseAddress0 = PCI_Device->base_address[0]; + unsigned long BaseAddress1 = PCI_Device->base_address[1]; + unsigned short SubsystemVendorID, SubsystemDeviceID; + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID, + &SubsystemVendorID); + pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID, + &SubsystemDeviceID); + switch (ControllerType) + { + case DAC960_V5_Controller: + if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX && + SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5)) + goto Ignore; + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V4_Controller: + PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK; + break; + case DAC960_V3_Controller: + IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK; + PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK; + break; + } + if (DAC960_ControllerCount == DAC960_MaxControllers) + { + DAC960_Error("More than %d DAC960 Controllers detected - " + "ignoring from Controller at\n", + NULL, DAC960_MaxControllers); + goto Ignore; + } + if (Controller == NULL) + { + DAC960_Error("Unable to allocate Controller structure for " + "Controller at\n", NULL); + goto Ignore; + } + memset(Controller, 0, sizeof(DAC960_Controller_T)); + Controller->ControllerNumber = DAC960_ControllerCount; + DAC960_Controllers[DAC960_ControllerCount++] = Controller; + DAC960_AnnounceDriver(Controller); + Controller->ControllerType = ControllerType; + Controller->IO_Address = IO_Address; + Controller->PCI_Address = PCI_Address; + Controller->Bus = Bus; + Controller->Device = Device; + Controller->Function = Function; + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); + /* + Acquire shared access to the IRQ Channel. + */ + if (IRQ_Channel == 0) + { + DAC960_Error("IRQ Channel %d illegal for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + strcpy(Controller->FullModelName, "DAC960"); + if (request_irq(IRQ_Channel, DAC960_InterruptHandler, + SA_SHIRQ, Controller->FullModelName, Controller) < 0) + { + DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", + Controller, IRQ_Channel); + goto Failure; + } + Controller->IRQ_Channel = IRQ_Channel; + /* + Map the Controller Register Window. + */ + if (MemoryWindowSize < PAGE_SIZE) + MemoryWindowSize = PAGE_SIZE; + Controller->MemoryMappedAddress = + ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize); + Controller->BaseAddress = + Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK); + if (Controller->MemoryMappedAddress == NULL) + { + DAC960_Error("Unable to map Controller Register Window for " + "Controller at\n", Controller); + goto Failure; + } + switch (ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V5_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V4_Controller: + DAC960_V4_DisableInterrupts(Controller->BaseAddress); + if (!DAC960_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to Enable Memory Mailbox Interface " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_V4_EnableInterrupts(Controller->BaseAddress); + break; + case DAC960_V3_Controller: + request_region(Controller->IO_Address, 0x80, + Controller->FullModelName); + DAC960_V3_EnableInterrupts(Controller->BaseAddress); + break; + } + DAC960_ActiveControllerCount++; + Controller->Commands[0].Controller = Controller; + Controller->Commands[0].Next = NULL; + Controller->FreeCommands = &Controller->Commands[0]; + continue; + Failure: + if (IO_Address == 0) + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " + "PCI Address 0x%X\n", Controller, + Bus, Device, Function, PCI_Address); + else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + "0x%X PCI Address 0x%X\n", Controller, + Bus, Device, Function, IO_Address, PCI_Address); + if (Controller == NULL) break; + if (Controller->IRQ_Channel > 0) + free_irq(IRQ_Channel, Controller); + if (Controller->MemoryMappedAddress != NULL) + iounmap(Controller->MemoryMappedAddress); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + Ignore: + kfree(Controller); + } +} + + +/* + DAC960_ReadControllerConfiguration reads the Configuration Information + from Controller and initializes the Controller structure. +*/ + +static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T + *Controller) +{ + DAC960_Enquiry2_T Enquiry2; + DAC960_Config2_T Config2; + int LogicalDriveNumber, Channel, TargetID; + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry, + &Controller->Enquiry[0])) + return DAC960_Failure(Controller, "ENQUIRY"); + if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2)) + return DAC960_Failure(Controller, "ENQUIRY2"); + if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2)) + return DAC960_Failure(Controller, "READ CONFIG2"); + if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation, + &Controller->LogicalDriveInformation[0])) + return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); + for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState, + Channel, TargetID, + &Controller->DeviceState[0][Channel][TargetID])) + return DAC960_Failure(Controller, "GET DEVICE STATE"); + /* + Initialize the Controller Model Name and Full Model Name fields. + */ + switch (Enquiry2.HardwareID.SubModel) + { + case DAC960_P_PD_PU: + if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra) + strcpy(Controller->ModelName, "DAC960PU"); + else strcpy(Controller->ModelName, "DAC960PD"); + break; + case DAC960_PL: + strcpy(Controller->ModelName, "DAC960PL"); + break; + case DAC960_PG: + strcpy(Controller->ModelName, "DAC960PG"); + break; + case DAC960_PJ: + strcpy(Controller->ModelName, "DAC960PJ"); + break; + case DAC960_PR: + strcpy(Controller->ModelName, "DAC960PR"); + break; + case DAC960_PT: + strcpy(Controller->ModelName, "DAC960PT"); + break; + case DAC960_PTL0: + strcpy(Controller->ModelName, "DAC960PTL0"); + break; + case DAC960_PRL: + strcpy(Controller->ModelName, "DAC960PRL"); + break; + case DAC960_PTL1: + strcpy(Controller->ModelName, "DAC960PTL1"); + break; + case DAC1164_P: + strcpy(Controller->ModelName, "DAC1164P"); + break; + default: + return DAC960_Failure(Controller, "MODEL VERIFICATION"); + } + strcpy(Controller->FullModelName, "Mylex "); + strcat(Controller->FullModelName, Controller->ModelName); + /* + Initialize the Controller Firmware Version field and verify that it + is a supported firmware version. The supported firmware versions are: + + DAC1164P 5.06 and above + DAC960PTL/PRL/PJ/PG 4.06 and above + DAC960PU/PD/PL 3.51 and above + */ + sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d", + Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion, + Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID); + if (!((Controller->FirmwareVersion[0] == '5' && + strcmp(Controller->FirmwareVersion, "5.06") >= 0) || + (Controller->FirmwareVersion[0] == '4' && + strcmp(Controller->FirmwareVersion, "4.06") >= 0) || + (Controller->FirmwareVersion[0] == '3' && + strcmp(Controller->FirmwareVersion, "3.51") >= 0))) + { + DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); + DAC960_Error("Firmware Version = '%s'\n", Controller, + Controller->FirmwareVersion); + return false; + } + /* + Initialize the Controller Channels, Memory Size, and SAF-TE Enclosure + Management Enabled fields. + */ + Controller->Channels = Enquiry2.ActualChannels; + Controller->MemorySize = Enquiry2.MemorySize >> 20; + Controller->SAFTE_EnclosureManagementEnabled = + Enquiry2.FaultManagementType == DAC960_SAFTE; + /* + Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive + Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments. + The Driver Queue Depth must be at most one less than the Controller Queue + Depth to allow for an automatic drive rebuild operation. + */ + Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands; + Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1; + Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives; + Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand; + Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries; + /* + Initialize the Stripe Size, Segment Size, and Geometry Translation. + */ + Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor + >> (10 - DAC960_BlockSizeBits); + switch (Config2.DriveGeometry) + { + case DAC960_Geometry_128_32: + Controller->GeometryTranslationHeads = 128; + Controller->GeometryTranslationSectors = 32; + break; + case DAC960_Geometry_255_63: + Controller->GeometryTranslationHeads = 255; + Controller->GeometryTranslationSectors = 63; + break; + default: + return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); + } + /* + Initialize the Logical Drive Initial State. + */ + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + Controller->LogicalDriveInformation[0] + [LogicalDriveNumber].LogicalDriveState; + Controller->LastRebuildStatus = DAC960_NoRebuildOrCheckInProgress; + return true; +} + + +/* + DAC960_ReportControllerConfiguration reports the configuration of + Controller. +*/ + +static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T + *Controller) +{ + int LogicalDriveNumber, Channel, TargetID; + DAC960_Info("Configuring Mylex %s PCI RAID Controller\n", + Controller, Controller->ModelName); + DAC960_Info(" Firmware Version: %s, Channels: %d, Memory Size: %dMB\n", + Controller, Controller->FirmwareVersion, + Controller->Channels, Controller->MemorySize); + DAC960_Info(" PCI Bus: %d, Device: %d, Function: %d, I/O Address: ", + Controller, Controller->Bus, + Controller->Device, Controller->Function); + if (Controller->IO_Address == 0) + DAC960_Info("Unassigned\n", Controller); + else DAC960_Info("0x%X\n", Controller, Controller->IO_Address); + DAC960_Info(" PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n", + Controller, Controller->PCI_Address, + (unsigned long) Controller->BaseAddress, + Controller->IRQ_Channel); + DAC960_Info(" Controller Queue Depth: %d, " + "Maximum Blocks per Command: %d\n", + Controller, Controller->ControllerQueueDepth, + Controller->MaxBlocksPerCommand); + DAC960_Info(" Driver Queue Depth: %d, " + "Maximum Scatter/Gather Segments: %d\n", + Controller, Controller->DriverQueueDepth, + Controller->MaxScatterGatherSegments); + DAC960_Info(" Stripe Size: %dKB, Segment Size: %dKB, " + "BIOS Geometry: %d/%d\n", Controller, + Controller->StripeSize, + Controller->SegmentSize, + Controller->GeometryTranslationHeads, + Controller->GeometryTranslationSectors); + if (Controller->SAFTE_EnclosureManagementEnabled) + DAC960_Info(" SAF-TE Enclosure Management Enabled\n", Controller); + DAC960_Info(" Physical Devices:\n", Controller); + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (!DeviceState->Present) continue; + switch (DeviceState->DeviceType) + { + case DAC960_OtherType: + DAC960_Info(" %d:%d - Other\n", Controller, Channel, TargetID); + break; + case DAC960_DiskType: + DAC960_Info(" %d:%d - Disk: %s, %d blocks\n", Controller, + Channel, TargetID, + (DeviceState->DeviceState == DAC960_Device_Dead + ? "Dead" + : DeviceState->DeviceState == DAC960_Device_WriteOnly + ? "Write-Only" + : DeviceState->DeviceState == DAC960_Device_Online + ? "Online" : "Standby"), + DeviceState->DiskSize); + break; + case DAC960_SequentialType: + DAC960_Info(" %d:%d - Sequential\n", Controller, + Channel, TargetID); + break; + case DAC960_CDROM_or_WORM_Type: + DAC960_Info(" %d:%d - CD-ROM or WORM\n", Controller, + Channel, TargetID); + break; + } + + } + DAC960_Info(" Logical Drives:\n", Controller); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex][LogicalDriveNumber]; + DAC960_Info(" /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n", + Controller, Controller->ControllerNumber, LogicalDriveNumber, + LogicalDriveInformation->RAIDLevel, + (LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Online + ? "Online" + : LogicalDriveInformation->LogicalDriveState == + DAC960_LogicalDrive_Critical + ? "Critical" : "Offline"), + LogicalDriveInformation->LogicalDriveSize, + (LogicalDriveInformation->WriteBack + ? "Write Back" : "Write Thru")); + } + return true; +} + + +/* + DAC960_RegisterBlockDevice registers the Block Device structures + associated with Controller. +*/ + +static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) +{ + static void (*RequestFunctions[DAC960_MaxControllers])(void) = + { DAC960_RequestFunction0, DAC960_RequestFunction1, + DAC960_RequestFunction2, DAC960_RequestFunction3, + DAC960_RequestFunction4, DAC960_RequestFunction5, + DAC960_RequestFunction6, DAC960_RequestFunction7 }; + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + GenericDiskInfo_T *GenericDiskInfo; + int MinorNumber; + /* + Register the Block Device Major Number for this DAC960 Controller. + */ + if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0) + { + DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n", + Controller, MajorNumber); + return false; + } + /* + Initialize the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = + RequestFunctions[Controller->ControllerNumber]; + /* + Initialize the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++) + { + Controller->BlockSizes[MinorNumber] = BLOCK_SIZE; + Controller->MaxSectorsPerRequest[MinorNumber] = + Controller->MaxBlocksPerCommand; + Controller->MaxSegmentsPerRequest[MinorNumber] = + Controller->MaxScatterGatherSegments; + } + Controller->GenericDiskInfo.part = Controller->DiskPartitions; + Controller->GenericDiskInfo.sizes = Controller->PartitionSizes; + blksize_size[MajorNumber] = Controller->BlockSizes; + max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest; + max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest; + /* + Initialize Read Ahead to 128 sectors. + */ + read_ahead[MajorNumber] = 128; + /* + Complete initialization of the Generic Disk Information structure. + */ + Controller->GenericDiskInfo.major = MajorNumber; + Controller->GenericDiskInfo.major_name = "rd"; + Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits; + Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions; + Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives; + Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo; + Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount; + Controller->GenericDiskInfo.real_devices = Controller; + Controller->GenericDiskInfo.next = NULL; + /* + Install the Generic Disk Information structure at the end of the list. + */ + if ((GenericDiskInfo = gendisk_head) != NULL) + { + while (GenericDiskInfo->next != NULL) + GenericDiskInfo = GenericDiskInfo->next; + GenericDiskInfo->next = &Controller->GenericDiskInfo; + } + else gendisk_head = &Controller->GenericDiskInfo; + /* + Indicate the Block Device Registration completed successfully, + */ + return true; +} + + +/* + DAC960_UnregisterBlockDevice unregisters the Block Device structures + associated with Controller. +*/ + +static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller) +{ + int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; + /* + Unregister the Block Device Major Number for this DAC960 Controller. + */ + unregister_blkdev(MajorNumber, "rd"); + /* + Remove the I/O Request Function. + */ + blk_dev[MajorNumber].request_fn = NULL; + /* + Remove the Disk Partitions array, Partition Sizes array, Block Sizes + array, Max Sectors per Request array, and Max Segments per Request array. + */ + Controller->GenericDiskInfo.part = NULL; + Controller->GenericDiskInfo.sizes = NULL; + blk_size[MajorNumber] = NULL; + blksize_size[MajorNumber] = NULL; + max_sectors[MajorNumber] = NULL; + max_segments[MajorNumber] = NULL; + /* + Remove the Generic Disk Information structure from the list. + */ + if (gendisk_head != &Controller->GenericDiskInfo) + { + GenericDiskInfo_T *GenericDiskInfo = gendisk_head; + while (GenericDiskInfo != NULL && + GenericDiskInfo->next != &Controller->GenericDiskInfo) + GenericDiskInfo = GenericDiskInfo->next; + if (GenericDiskInfo != NULL) + GenericDiskInfo->next = GenericDiskInfo->next->next; + } + else gendisk_head = Controller->GenericDiskInfo.next; +} + + +/* + DAC960_InitializeController initializes Controller. +*/ + +static void DAC960_InitializeController(DAC960_Controller_T *Controller) +{ + if (DAC960_ReadControllerConfiguration(Controller) && + DAC960_ReportControllerConfiguration(Controller) && + DAC960_RegisterBlockDevice(Controller)) + { + /* + Initialize the Command structures. + */ + DAC960_Command_T *Commands = Controller->Commands; + int CommandIdentifier; + Controller->FreeCommands = NULL; + for (CommandIdentifier = 0; + CommandIdentifier < Controller->DriverQueueDepth; + CommandIdentifier++) + { + Commands[CommandIdentifier].Controller = Controller; + Commands[CommandIdentifier].Next = Controller->FreeCommands; + Controller->FreeCommands = &Commands[CommandIdentifier]; + } + /* + Initialize the Monitoring Timer. + */ + init_timer(&Controller->MonitoringTimer); + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + Controller->MonitoringTimer.data = (unsigned long) Controller; + Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction; + add_timer(&Controller->MonitoringTimer); + Controller->ControllerInitialized = true; + } + else DAC960_FinalizeController(Controller); +} + + +/* + DAC960_FinalizeController finalizes Controller. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *Controller) +{ + if (Controller->ControllerInitialized) + { + del_timer(&Controller->MonitoringTimer); + DAC960_Notice("Flushing Cache...", Controller); + DAC960_ExecuteType3(Controller, DAC960_Flush, NULL); + DAC960_Notice("done\n", Controller); + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V5_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V4_Controller: + if (!Controller->DualModeMemoryMailboxInterface) + DAC960_V4_SaveMemoryMailboxInfo(Controller); + break; + case DAC960_V3_Controller: + break; + } + } + free_irq(Controller->IRQ_Channel, Controller); + iounmap(Controller->MemoryMappedAddress); + if (Controller->IO_Address > 0) + release_region(Controller->IO_Address, 0x80); + DAC960_UnregisterBlockDevice(Controller); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + kfree(Controller); +} + + +/* + DAC960_Initialize initializes the DAC960 Driver. +*/ + +void DAC960_Initialize(void) +{ + int ControllerNumber; + DAC960_DetectControllers(DAC960_V5_Controller); + DAC960_DetectControllers(DAC960_V4_Controller); + DAC960_DetectControllers(DAC960_V3_Controller); + if (DAC960_ActiveControllerCount == 0) return; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_InitializeController(DAC960_Controllers[ControllerNumber]); + DAC960_CreateProcEntries(); + register_reboot_notifier(&DAC960_NotifierBlock); +} + + +/* + DAC960_Finalize finalizes the DAC960 Driver. +*/ + +static int DAC960_Finalize(NotifierBlock_T *NotifierBlock, + unsigned long Event, + void *Buffer) +{ + int ControllerNumber; + if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF)) + return NOTIFY_DONE; + if (DAC960_ActiveControllerCount == 0) return NOTIFY_OK; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + if (DAC960_Controllers[ControllerNumber] != NULL) + DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]); + DAC960_DestroyProcEntries(); + unregister_reboot_notifier(&DAC960_NotifierBlock); + return NOTIFY_OK; +} + + +/* + DAC960_ProcessRequest attempts to remove one I/O Request from Controller's + I/O Request Queue and queues it to the Controller. WaitForCommand is true if + this function should wait for a Command to become available if necessary. + This function returns true if an I/O Request was queued and false otherwise. +*/ + +static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller, + boolean WaitForCommand) +{ + IO_Request_T **RequestQueuePointer = + &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request; + IO_Request_T *Request; + DAC960_Command_T *Command; + char *RequestBuffer; + while (true) + { + Request = *RequestQueuePointer; + if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false; + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) break; + if (!WaitForCommand) return false; + spin_unlock(&io_request_lock); + sleep_on(&Controller->CommandWaitQueue); + spin_lock_irq(&io_request_lock); + } + DAC960_ClearCommand(Command); + if (Request->cmd == READ) + Command->CommandType = DAC960_ReadCommand; + else Command->CommandType = DAC960_WriteCommand; + Command->Semaphore = Request->sem; + Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev); + Command->BlockNumber = + Request->sector + + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect; + Command->BlockCount = Request->nr_sectors; + Command->SegmentCount = Request->nr_segments; + Command->BufferHeader = Request->bh; + RequestBuffer = Request->buffer; + Request->rq_status = RQ_INACTIVE; + *RequestQueuePointer = Request->next; + wake_up(&wait_for_request); + if (Command->SegmentCount == 1) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + else CommandMailbox->Type5.CommandOpcode = DAC960_Write; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer); + } + else + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ScatterGatherSegment_T + *ScatterGatherList = Command->ScatterGatherList; + BufferHeader_T *BufferHeader = Command->BufferHeader; + char *LastDataEndPointer = NULL; + int SegmentNumber = 0; + if (Command->CommandType == DAC960_ReadCommand) + CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather; + else + CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList); + CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; + while (BufferHeader != NULL) + { + if (BufferHeader->b_data == LastDataEndPointer) + { + ScatterGatherList[SegmentNumber-1].SegmentByteCount += + BufferHeader->b_size; + LastDataEndPointer += BufferHeader->b_size; + } + else + { + ScatterGatherList[SegmentNumber].SegmentDataPointer = + Virtual_to_Bus(BufferHeader->b_data); + ScatterGatherList[SegmentNumber].SegmentByteCount = + BufferHeader->b_size; + LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size; + if (SegmentNumber++ > Controller->MaxScatterGatherSegments) + panic("DAC960: Scatter/Gather Segment Overflow\n"); + } + BufferHeader = BufferHeader->b_reqnext; + } + if (SegmentNumber != Command->SegmentCount) + panic("DAC960: SegmentNumber != SegmentCount\n"); + } + DAC960_QueueCommand(Command); + return true; +} + + +/* + DAC960_ProcessRequests attempts to remove as many I/O Requests as possible + from Controller's I/O Request Queue and queue them to the Controller. +*/ + +static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller) +{ + int Counter = 0; + while (DAC960_ProcessRequest(Controller, Counter++ == 0)) ; +} + + +/* + DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0. +*/ + +static void DAC960_RequestFunction0(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[0]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1. +*/ + +static void DAC960_RequestFunction1(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[1]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2. +*/ + +static void DAC960_RequestFunction2(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[2]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3. +*/ + +static void DAC960_RequestFunction3(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[3]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4. +*/ + +static void DAC960_RequestFunction4(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[4]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5. +*/ + +static void DAC960_RequestFunction5(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[5]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6. +*/ + +static void DAC960_RequestFunction6(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[6]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7. +*/ + +static void DAC960_RequestFunction7(void) +{ + DAC960_Controller_T *Controller = DAC960_Controllers[7]; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags); + /* + Process I/O Requests for Controller. + */ + DAC960_ProcessRequests(Controller); + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags); +} + + +/* + DAC960_ReadWriteError prints an appropriate error message for Command when + an error occurs on a Read or Write operation. +*/ + +static void DAC960_ReadWriteError(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + char *CommandName = "UNKNOWN"; + switch (Command->CommandType) + { + case DAC960_ReadCommand: + case DAC960_ReadRetryCommand: + CommandName = "READ"; + break; + case DAC960_WriteCommand: + case DAC960_WriteRetryCommand: + CommandName = "WRITE"; + break; + case DAC960_MonitoringCommand: + case DAC960_ImmediateCommand: + case DAC960_QueuedCommand: + break; + } + switch (Command->CommandStatus) + { + case DAC960_IrrecoverableDataError: + DAC960_Error("Irrecoverable Data Error on %s:\n", + Controller, CommandName); + break; + case DAC960_LogicalDriveNonexistentOrOffline: + DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n", + Controller, CommandName); + break; + case DAC960_AccessBeyondEndOfLogicalDrive: + DAC960_Error("Attempt to Access Beyond End of Logical Drive " + "on %s:\n", Controller, CommandName); + break; + case DAC960_BadDataEncountered: + DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName); + break; + default: + DAC960_Error("Unexpected Error Status %04X on %s:\n", + Controller, Command->CommandStatus, CommandName); + break; + } + DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, Command->BlockNumber, + Command->BlockNumber + Command->BlockCount - 1); + if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0) + DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %d..%d\n", + Controller, Controller->ControllerNumber, + Command->LogicalDriveNumber, + DAC960_PartitionNumber(Command->BufferHeader->b_rdev), + Command->BufferHeader->b_rsector, + Command->BufferHeader->b_rsector + Command->BlockCount - 1); +} + + +/* + DAC960_ProcessCompletedBuffer performs completion processing for an + individual Buffer. +*/ + +static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, + boolean SuccessfulIO) +{ + BufferHeader->b_end_io(BufferHeader, SuccessfulIO); +} + + +/* + DAC960_ProcessCompletedCommand performs completion processing for Command. +*/ + +static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandType_T CommandType = Command->CommandType; + DAC960_CommandOpcode_T CommandOpcode = + Command->CommandMailbox.Common.CommandOpcode; + DAC960_CommandStatus_T CommandStatus = Command->CommandStatus; + BufferHeader_T *BufferHeader = Command->BufferHeader; + if (CommandType == DAC960_ReadCommand || + CommandType == DAC960_WriteCommand) + { + if (CommandStatus == DAC960_NormalCompletion) + { + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, true); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber); + } + else if ((CommandStatus == DAC960_IrrecoverableDataError || + CommandStatus == DAC960_BadDataEncountered) && + BufferHeader != NULL && + BufferHeader->b_reqnext != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + if (CommandType == DAC960_ReadCommand) + { + Command->CommandType = DAC960_ReadRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Read; + } + else + { + Command->CommandType = DAC960_WriteRetryCommand; + CommandMailbox->Type5.CommandOpcode = DAC960_Write; + } + Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(BufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + /* + Perform completion processing for all buffers in this I/O Request. + */ + while (BufferHeader != NULL) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + DAC960_ProcessCompletedBuffer(BufferHeader, false); + BufferHeader = NextBufferHeader; + } + /* + Wake up requestor for swap file paging requests. + */ + if (Command->Semaphore != NULL) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + } + } + } + else if (CommandType == DAC960_ReadRetryCommand || + CommandType == DAC960_WriteRetryCommand) + { + BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext; + BufferHeader->b_reqnext = NULL; + /* + Perform completion processing for this single buffer. + */ + if (CommandStatus == DAC960_NormalCompletion) + DAC960_ProcessCompletedBuffer(BufferHeader, true); + else + { + if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline) + DAC960_ReadWriteError(Command); + DAC960_ProcessCompletedBuffer(BufferHeader, false); + } + if (NextBufferHeader != NULL) + { + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + Command->BlockNumber += + BufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BlockCount = + NextBufferHeader->b_size >> DAC960_BlockSizeBits; + Command->BufferHeader = NextBufferHeader; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; + CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; + CommandMailbox->Type5.BusAddress = + Virtual_to_Bus(NextBufferHeader->b_data); + DAC960_QueueCommand(Command); + return; + } + } + else if (CommandType == DAC960_MonitoringCommand || + CommandOpcode == DAC960_Enquiry || + CommandOpcode == DAC960_GetRebuildProgress) + { + if (CommandType != DAC960_MonitoringCommand) + { + if (CommandOpcode == DAC960_Enquiry) + memcpy(&Controller->Enquiry[Controller->EnquiryIndex ^ 1], + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_Enquiry_T)); + else if (CommandOpcode == DAC960_GetRebuildProgress) + memcpy(&Controller->RebuildProgress, + Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress), + sizeof(DAC960_RebuildProgress_T)); + } + if (CommandOpcode == DAC960_Enquiry) + { + DAC960_Enquiry_T *OldEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex]; + DAC960_Enquiry_T *NewEnquiry = + &Controller->Enquiry[Controller->EnquiryIndex ^= 1]; + unsigned int OldCriticalLogicalDriveCount = + OldEnquiry->CriticalLogicalDriveCount; + unsigned int NewCriticalLogicalDriveCount = + NewEnquiry->CriticalLogicalDriveCount; + if (NewEnquiry->StatusFlags.DeferredWriteError != + OldEnquiry->StatusFlags.DeferredWriteError) + DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller, + (NewEnquiry->StatusFlags.DeferredWriteError + ? "TRUE" : "FALSE")); + if ((NewCriticalLogicalDriveCount > 0 || + NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) || + (NewEnquiry->OfflineLogicalDriveCount > 0 || + NewEnquiry->OfflineLogicalDriveCount != + OldEnquiry->OfflineLogicalDriveCount) || + (NewEnquiry->DeadDriveCount > 0 || + NewEnquiry->DeadDriveCount != + OldEnquiry->DeadDriveCount) || + (NewEnquiry->EventLogSequenceNumber != + OldEnquiry->EventLogSequenceNumber) || + Controller->MonitoringTimerCount == 0 || + (jiffies - Controller->SecondaryMonitoringTime + >= DAC960_SecondaryMonitoringInterval)) + { + Controller->NeedLogicalDriveInformation = true; + Controller->NewEventLogSequenceNumber = + NewEnquiry->EventLogSequenceNumber; + Controller->NeedErrorTableInformation = true; + Controller->NeedDeviceStateInformation = true; + Controller->DeviceStateChannel = 0; + Controller->DeviceStateTargetID = 0; + Controller->SecondaryMonitoringTime = jiffies; + } + if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress || + OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress) + Controller->NeedRebuildProgress = true; + if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + switch (NewEnquiry->RebuildFlag) + { + case DAC960_NoStandbyRebuildOrCheckInProgress: + DAC960_Progress("Consistency Check Completed Successfully\n", + Controller); + break; + case DAC960_StandbyRebuildInProgress: + case DAC960_BackgroundRebuildInProgress: + break; + case DAC960_BackgroundCheckInProgress: + Controller->NeedConsistencyCheckProgress = true; + break; + case DAC960_StandbyRebuildCompletedWithError: + DAC960_Progress("Consistency Check Completed with Error\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Physical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed: + DAC960_Progress("Consistency Check Failed - " + "Logical Drive Failed\n", Controller); + break; + case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses: + DAC960_Progress("Consistency Check Failed - Other Causes\n", + Controller); + break; + case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated: + DAC960_Progress("Consistency Check Successfully Terminated\n", + Controller); + break; + } + else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress) + Controller->NeedConsistencyCheckProgress = true; + } + else if (CommandOpcode == DAC960_PerformEventLogOperation) + { + static char + *DAC960_EventMessages[] = + { "killed because write recovery failed", + "killed because of SCSI bus reset failure", + "killed because of double check condition", + "killed because it was removed", + "killed because of gross error on SCSI chip", + "killed because of bad tag returned from drive", + "killed because of timeout on SCSI command", + "killed because of reset SCSI command issued from system", + "killed because busy or parity error count exceeded limit", + "killed because of 'kill drive' command from system", + "killed because of selection timeout", + "killed due to SCSI phase sequence error", + "killed due to unknown status" }; + DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry; + if (EventLogEntry->SequenceNumber == + Controller->OldEventLogSequenceNumber) + { + unsigned char SenseKey = EventLogEntry->SenseKey; + unsigned char AdditionalSenseCode = + EventLogEntry->AdditionalSenseCode; + unsigned char AdditionalSenseCodeQualifier = + EventLogEntry->AdditionalSenseCodeQualifier; + if (SenseKey == 9 && + AdditionalSenseCode == 0x80 && + AdditionalSenseCodeQualifier < + sizeof(DAC960_EventMessages) / sizeof(char *)) + DAC960_Critical("Physical Drive %d:%d %s\n", Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + DAC960_EventMessages[ + AdditionalSenseCodeQualifier]); + else if (!(SenseKey == 0 || + (SenseKey == 2 && + AdditionalSenseCode == 0x04 && + (AdditionalSenseCodeQualifier == 0x01 || + AdditionalSenseCodeQualifier == 0x02)) || + (SenseKey == 6 && AdditionalSenseCode == 0x29 && + Controller->MonitoringTimerCount == 0))) + { + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Sense Key = %d, ASC = %02X, ASCQ = %02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + SenseKey, + AdditionalSenseCode, + AdditionalSenseCodeQualifier); + DAC960_Critical("Physical Drive %d:%d Error Log: " + "Information = %02X%02X%02X%02X " + "%02X%02X%02X%02X\n", + Controller, + EventLogEntry->Channel, + EventLogEntry->TargetID, + EventLogEntry->Information[0], + EventLogEntry->Information[1], + EventLogEntry->Information[2], + EventLogEntry->Information[3], + EventLogEntry->CommandSpecificInformation[0], + EventLogEntry->CommandSpecificInformation[1], + EventLogEntry->CommandSpecificInformation[2], + EventLogEntry->CommandSpecificInformation[3]); + } + } + Controller->OldEventLogSequenceNumber++; + } + else if (CommandOpcode == DAC960_GetErrorTable) + { + DAC960_ErrorTable_T *OldErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex]; + DAC960_ErrorTable_T *NewErrorTable = + &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1]; + int Channel, TargetID; + for (Channel = 0; Channel < Controller->Channels; Channel++) + for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++) + { + DAC960_ErrorTableEntry_T *NewErrorEntry = + &NewErrorTable->ErrorTableEntries[Channel][TargetID]; + DAC960_ErrorTableEntry_T *OldErrorEntry = + &OldErrorTable->ErrorTableEntries[Channel][TargetID]; + if ((NewErrorEntry->ParityErrorCount != + OldErrorEntry->ParityErrorCount) || + (NewErrorEntry->SoftErrorCount != + OldErrorEntry->SoftErrorCount) || + (NewErrorEntry->HardErrorCount != + OldErrorEntry->HardErrorCount) || + (NewErrorEntry->MiscErrorCount != + OldErrorEntry->MiscErrorCount)) + DAC960_Critical("Physical Drive %d:%d Errors: " + "Parity = %d, Soft = %d, " + "Hard = %d, Misc = %d\n", + Controller, Channel, TargetID, + NewErrorEntry->ParityErrorCount, + NewErrorEntry->SoftErrorCount, + NewErrorEntry->HardErrorCount, + NewErrorEntry->MiscErrorCount); + } + } + else if (CommandOpcode == DAC960_GetDeviceState) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + DAC960_DeviceState_T *NewDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (NewDeviceState->DeviceState != OldDeviceState->DeviceState) + DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller, + Controller->DeviceStateChannel, + Controller->DeviceStateTargetID, + (NewDeviceState->DeviceState == DAC960_Device_Dead + ? "DEAD" + : NewDeviceState->DeviceState + == DAC960_Device_WriteOnly + ? "WRITE-ONLY" + : NewDeviceState->DeviceState + == DAC960_Device_Online + ? "ONLINE" : "STANDBY")); + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + } + else if (CommandOpcode == DAC960_GetLogicalDriveInformation) + { + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + { + DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber]; + DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation = + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1] + [LogicalDriveNumber]; + if (NewLogicalDriveInformation->LogicalDriveState != + OldLogicalDriveInformation->LogicalDriveState) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Online + ? "ONLINE" + : NewLogicalDriveInformation->LogicalDriveState + == DAC960_LogicalDrive_Critical + ? "CRITICAL" : "OFFLINE")); + if (NewLogicalDriveInformation->WriteBack != + OldLogicalDriveInformation->WriteBack) + DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " + "is now %s\n", Controller, + LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (NewLogicalDriveInformation->WriteBack + ? "WRITE BACK" : "WRITE THRU")); + } + Controller->LogicalDriveInformationIndex ^= 1; + } + else if (CommandOpcode == DAC960_GetRebuildProgress) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + switch (CommandStatus) + { + case DAC960_NormalCompletion: + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Rebuild in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + break; + case DAC960_RebuildFailed_LogicalDriveFailure: + DAC960_Progress("Rebuild Failed due to " + "Logical Drive Failure\n", Controller); + break; + case DAC960_RebuildFailed_BadBlocksOnOther: + DAC960_Progress("Rebuild Failed due to " + "Bad Blocks on Other Drives\n", Controller); + break; + case DAC960_RebuildFailed_NewDriveFailed: + DAC960_Progress("Rebuild Failed due to " + "Failure of Drive Being Rebuilt\n", Controller); + break; + case DAC960_NoRebuildOrCheckInProgress: + if (Controller->LastRebuildStatus != DAC960_NormalCompletion) + break; + case DAC960_RebuildSuccessful: + DAC960_Progress("Rebuild Completed Successfully\n", Controller); + break; + } + Controller->LastRebuildStatus = CommandStatus; + } + else if (CommandOpcode == DAC960_RebuildStat) + { + unsigned int LogicalDriveNumber = + Controller->RebuildProgress.LogicalDriveNumber; + unsigned int LogicalDriveSize = + Controller->RebuildProgress.LogicalDriveSize; + unsigned int BlocksCompleted = + LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks; + if (CommandStatus == DAC960_NormalCompletion) + { + Controller->EphemeralProgressMessage = true; + DAC960_Progress("Consistency Check in Progress: " + "Logical Drive %d (/dev/rd/c%dd%d) " + "%d%% completed\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, + (100 * (BlocksCompleted >> 7)) + / (LogicalDriveSize >> 7)); + Controller->EphemeralProgressMessage = false; + } + } + } + if (CommandType == DAC960_MonitoringCommand) + { + if (Controller->NewEventLogSequenceNumber + - Controller->OldEventLogSequenceNumber > 0) + { + Command->CommandMailbox.Type3E.CommandOpcode = + DAC960_PerformEventLogOperation; + Command->CommandMailbox.Type3E.OperationType = + DAC960_GetEventLogEntry; + Command->CommandMailbox.Type3E.OperationQualifier = 1; + Command->CommandMailbox.Type3E.SequenceNumber = + Controller->OldEventLogSequenceNumber; + Command->CommandMailbox.Type3E.BusAddress = + Virtual_to_Bus(&Controller->EventLogEntry); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedErrorTableInformation) + { + Controller->NeedErrorTableInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress && + Controller->Enquiry[Controller->EnquiryIndex] + .CriticalLogicalDriveCount < + Controller->Enquiry[Controller->EnquiryIndex ^ 1] + .CriticalLogicalDriveCount) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedDeviceStateInformation) + { + while (Controller->DeviceStateChannel < Controller->Channels) + { + DAC960_DeviceState_T *OldDeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]; + if (OldDeviceState->Present && + OldDeviceState->DeviceType == DAC960_DiskType) + { + Command->CommandMailbox.Type3D.CommandOpcode = + DAC960_GetDeviceState; + Command->CommandMailbox.Type3D.Channel = + Controller->DeviceStateChannel; + Command->CommandMailbox.Type3D.TargetID = + Controller->DeviceStateTargetID; + Command->CommandMailbox.Type3D.BusAddress = + Virtual_to_Bus(&Controller->DeviceState + [Controller->DeviceStateIndex ^ 1] + [Controller->DeviceStateChannel] + [Controller->DeviceStateTargetID]); + DAC960_QueueCommand(Command); + return; + } + if (++Controller->DeviceStateTargetID == DAC960_MaxTargets) + { + Controller->DeviceStateChannel++; + Controller->DeviceStateTargetID = 0; + } + } + Controller->NeedDeviceStateInformation = false; + Controller->DeviceStateIndex ^= 1; + } + if (Controller->NeedLogicalDriveInformation) + { + Controller->NeedLogicalDriveInformation = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetLogicalDriveInformation; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus( + &Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex ^ 1]); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedRebuildProgress) + { + Controller->NeedRebuildProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = + DAC960_GetRebuildProgress; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + if (Controller->NeedConsistencyCheckProgress) + { + Controller->NeedConsistencyCheckProgress = false; + Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat; + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(&Controller->RebuildProgress); + DAC960_QueueCommand(Command); + return; + } + Controller->MonitoringTimerCount++; + Controller->MonitoringTimer.expires = + jiffies + DAC960_MonitoringTimerInterval; + add_timer(&Controller->MonitoringTimer); + } + if (CommandType == DAC960_ImmediateCommand) + { + up(Command->Semaphore); + Command->Semaphore = NULL; + return; + } + if (CommandType == DAC960_QueuedCommand) + { + DAC960_KernelCommand_T *KernelCommand = Command->KernelCommand; + KernelCommand->CommandStatus = CommandStatus; + Command->KernelCommand = NULL; + if (CommandOpcode == DAC960_DCDB) + Controller->DirectCommandActive[KernelCommand->DCDB->Channel] + [KernelCommand->DCDB->TargetID] = false; + DAC960_DeallocateCommand(Command); + KernelCommand->CompletionFunction(KernelCommand); + return; + } + /* + Queue a Status Monitoring Command to the Controller using the just + completed Command if one was deferred previously due to lack of a + free Command when the Monitoring Timer Function was called. + */ + if (Controller->MonitoringCommandDeferred) + { + Controller->MonitoringCommandDeferred = false; + DAC960_QueueMonitoringCommand(Command); + return; + } + /* + Deallocate the Command, and wake up any processes waiting on a free Command. + */ + DAC960_DeallocateCommand(Command); + wake_up(&Controller->CommandWaitQueue); +} + + +/* + DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers. +*/ + +static void DAC960_InterruptHandler(int IRQ_Channel, + void *DeviceIdentifier, + Registers_T *InterruptRegisters) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier; + void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_StatusMailbox_T *NextStatusMailbox; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags); + /* + Process Hardware Interrupts for Controller. + */ + switch (Controller->ControllerType) + { + case DAC960_V5_Controller: + DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V4_Controller: + DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress); + NextStatusMailbox = Controller->NextStatusMailbox; + while (NextStatusMailbox->Fields.Valid) + { + DAC960_CommandIdentifier_T CommandIdentifier = + NextStatusMailbox->Fields.CommandIdentifier; + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus; + NextStatusMailbox->Word = 0; + if (++NextStatusMailbox > Controller->LastStatusMailbox) + NextStatusMailbox = Controller->FirstStatusMailbox; + DAC960_ProcessCompletedCommand(Command); + } + Controller->NextStatusMailbox = NextStatusMailbox; + break; + case DAC960_V3_Controller: + while (DAC960_V3_StatusAvailableP(ControllerBaseAddress)) + { + DAC960_CommandIdentifier_T CommandIdentifier = + DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress); + DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier]; + Command->CommandStatus = + DAC960_V3_ReadStatusRegister(ControllerBaseAddress); + DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress); + DAC960_V3_AcknowledgeStatus(ControllerBaseAddress); + DAC960_ProcessCompletedCommand(Command); + } + break; + } + /* + Attempt to remove additional I/O Requests from the Controller's + I/O Request Queue and queue them to the Controller. + */ + while (DAC960_ProcessRequest(Controller, false)) ; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags); +} + + +/* + DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller. +*/ + +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command) +{ + DAC960_Controller_T *Controller = Command->Controller; + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_MonitoringCommand; + CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry; + CommandMailbox->Type3.BusAddress = + Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]); + DAC960_QueueCommand(Command); +} + + +/* + DAC960_MonitoringTimerFunction is the timer function for monitoring + the status of DAC960 Controllers. +*/ + +static void DAC960_MonitoringTimerFunction(unsigned long TimerData) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData; + DAC960_Command_T *Command; + ProcessorFlags_T ProcessorFlags; + /* + Acquire exclusive access to Controller. + */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + /* + Queue a Status Monitoring Command to Controller. + */ + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + DAC960_QueueMonitoringCommand(Command); + else Controller->MonitoringCommandDeferred = true; + /* + Release exclusive access to Controller. + */ + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); +} + + +/* + DAC960_Open is the Device Open Function for the DAC960 Driver. +*/ + +static int DAC960_Open(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + if (Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveState + == DAC960_LogicalDrive_Offline) + return -ENXIO; + if (Controller->LogicalDriveInitialState[LogicalDriveNumber] + == DAC960_LogicalDrive_Offline) + { + Controller->LogicalDriveInitialState[LogicalDriveNumber] = + DAC960_LogicalDrive_Online; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0) + return -ENXIO; + /* + Increment Controller and Logical Drive Usage Counts. + */ + Controller->ControllerUsageCount++; + Controller->LogicalDriveUsageCount[LogicalDriveNumber]++; + ModuleOnly: + MOD_INC_USE_COUNT; + return 0; +} + + +/* + DAC960_Release is the Device Release Function for the DAC960 Driver. +*/ + +static int DAC960_Release(Inode_T *Inode, File_T *File) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (ControllerNumber == 0 && LogicalDriveNumber == 0 && + File != NULL && (File->f_flags & O_NONBLOCK)) + goto ModuleOnly; + /* + Force any buffered data to be written. + */ + fsync_dev(Inode->i_rdev); + /* + Decrement the Logical Drive and Controller Usage Counts. + */ + Controller->LogicalDriveUsageCount[LogicalDriveNumber]--; + Controller->ControllerUsageCount--; + ModuleOnly: + MOD_DEC_USE_COUNT; + return 0; +} + + +/* + DAC960_IOCTL is the Device IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_IOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev); + int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev); + DiskGeometry_T Geometry, *UserGeometry; + DAC960_Controller_T *Controller; + int PartitionNumber; + if (File->f_flags & O_NONBLOCK) + return DAC960_UserIOCTL(Inode, File, Request, Argument); + if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL || + LogicalDriveNumber > Controller->LogicalDriveCount - 1) + return -ENXIO; + switch (Request) + { + case HDIO_GETGEO: + /* Get BIOS Disk Geometry. */ + UserGeometry = (DiskGeometry_T *) Argument; + if (UserGeometry == NULL) return -EINVAL; + Geometry.heads = Controller->GeometryTranslationHeads; + Geometry.sectors = Controller->GeometryTranslationSectors; + Geometry.cylinders = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex] + [LogicalDriveNumber].LogicalDriveSize + / (Controller->GeometryTranslationHeads * + Controller->GeometryTranslationSectors); + Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .start_sect; + return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T)); + case BLKGETSIZE: + /* Get Device Size. */ + if ((long *) Argument == NULL) return -EINVAL; + return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] + .nr_sects, + (long *) Argument); + case BLKRAGET: + /* Get Read-Ahead. */ + if ((int *) Argument == NULL) return -EINVAL; + return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument); + case BLKRASET: + /* Set Read-Ahead. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Argument > 256) return -EINVAL; + read_ahead[MAJOR(Inode->i_rdev)] = Argument; + return 0; + case BLKFLSBUF: + /* Flush Buffers. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + fsync_dev(Inode->i_rdev); + invalidate_buffers(Inode->i_rdev); + return 0; + case BLKRRPART: + /* Re-Read Partition Table. */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1) + return -EBUSY; + for (PartitionNumber = 0; + PartitionNumber < DAC960_MaxPartitions; + PartitionNumber++) + { + KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber, + LogicalDriveNumber, + PartitionNumber); + int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber, + PartitionNumber); + SuperBlock_T *SuperBlock = get_super(Device); + if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0) + continue; + /* + Flush all changes and invalidate buffered state. + */ + sync_dev(Device); + if (SuperBlock != NULL) + invalidate_inodes(SuperBlock); + invalidate_buffers(Device); + /* + Clear existing partition sizes. + */ + if (PartitionNumber > 0) + { + Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0; + Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0; + } + /* + Reset the Block Size so that the partition table can be read. + */ + set_blocksize(Device, BLOCK_SIZE); + } + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + return 0; + } + return -EINVAL; +} + + +/* + DAC960_UserIOCTL is the User IOCTL Function for the DAC960 Driver. +*/ + +static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, + unsigned int Request, unsigned long Argument) +{ + int ErrorCode; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *UserSpaceControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_ControllerInfo_T ControllerInfo; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (UserSpaceControllerInfo == NULL) return -EINVAL; + ErrorCode = get_user(ControllerNumber, + &UserSpaceControllerInfo->ControllerNumber); + if (ErrorCode != 0) return ErrorCode; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo.ControllerNumber = ControllerNumber; + ControllerInfo.PCI_Bus = Controller->Bus; + ControllerInfo.PCI_Device = Controller->Device; + ControllerInfo.PCI_Function = Controller->Function; + ControllerInfo.IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo.Channels = Controller->Channels; + ControllerInfo.PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo.ModelName, Controller->ModelName); + strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); + return copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + sizeof(DAC960_ControllerInfo_T)); + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_UserCommand_T *UserSpaceUserCommand = + (DAC960_UserCommand_T *) Argument; + DAC960_UserCommand_T UserCommand; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_CommandStatus_T CommandStatus; + DAC960_DCDB_T DCDB; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (UserSpaceUserCommand == NULL) return -EINVAL; + ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand, + sizeof(DAC960_UserCommand_T)); + if (ErrorCode != 0) goto Failure; + ControllerNumber = UserCommand.ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; + DataTransferLength = UserCommand.DataTransferLength; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + ErrorCode = + copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + if (!((DataTransferLength == 0 && + DCDB.Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB.Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB.Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength > 0) + { + DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + memset(DataTransferBuffer, 0, DataTransferLength); + } + else if (DataTransferLength < 0) + { + DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); + if (DataTransferBuffer == NULL) return -ENOMEM; + ErrorCode = copy_from_user(DataTransferBuffer, + UserCommand.DataTransferBuffer, + -DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command != NULL) + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = true; + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(&DCDB); + DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer); + } + else + { + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + } + DAC960_ExecuteCommand(Command); + CommandStatus = Command->CommandStatus; + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (CommandStatus == DAC960_NormalCompletion && + DataTransferLength > 0) + { + ErrorCode = copy_to_user(UserCommand.DataTransferBuffer, + DataTransferBuffer, DataTransferLength); + if (ErrorCode != 0) goto Failure; + } + if (CommandOpcode == DAC960_DCDB) + { + Controller->DirectCommandActive[DCDB.Channel] + [DCDB.TargetID] = false; + ErrorCode = + copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_DCDB_T)); + if (ErrorCode != 0) goto Failure; + } + ErrorCode = CommandStatus; + Failure: + if (DataTransferBuffer != NULL) + kfree(DataTransferBuffer); + return ErrorCode; + } + } + return -EINVAL; +} + + +/* + DAC960_KernelIOCTL is the Kernel IOCTL Function for the DAC960 Driver. +*/ + +int DAC960_KernelIOCTL(unsigned int Request, void *Argument) +{ + switch (Request) + { + case DAC960_IOCTL_GET_CONTROLLER_COUNT: + return DAC960_ControllerCount; + case DAC960_IOCTL_GET_CONTROLLER_INFO: + { + DAC960_ControllerInfo_T *ControllerInfo = + (DAC960_ControllerInfo_T *) Argument; + DAC960_Controller_T *Controller; + int ControllerNumber; + if (ControllerInfo == NULL) return -EINVAL; + ControllerNumber = ControllerInfo->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); + ControllerInfo->ControllerNumber = ControllerNumber; + ControllerInfo->PCI_Bus = Controller->Bus; + ControllerInfo->PCI_Device = Controller->Device; + ControllerInfo->PCI_Function = Controller->Function; + ControllerInfo->IRQ_Channel = Controller->IRQ_Channel; + ControllerInfo->Channels = Controller->Channels; + ControllerInfo->PCI_Address = Controller->PCI_Address; + strcpy(ControllerInfo->ModelName, Controller->ModelName); + strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion); + return 0; + } + case DAC960_IOCTL_EXECUTE_COMMAND: + { + DAC960_KernelCommand_T *KernelCommand = + (DAC960_KernelCommand_T *) Argument; + DAC960_Controller_T *Controller; + DAC960_Command_T *Command = NULL; + DAC960_CommandOpcode_T CommandOpcode; + DAC960_DCDB_T *DCDB = NULL; + ProcessorFlags_T ProcessorFlags; + int ControllerNumber, DataTransferLength; + unsigned char *DataTransferBuffer = NULL; + if (KernelCommand == NULL) return -EINVAL; + ControllerNumber = KernelCommand->ControllerNumber; + if (ControllerNumber < 0 || + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; + Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) + return -ENXIO; + CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode; + DataTransferLength = KernelCommand->DataTransferLength; + DataTransferBuffer = KernelCommand->DataTransferBuffer; + if (CommandOpcode & 0x80) return -EINVAL; + if (CommandOpcode == DAC960_DCDB) + { + DCDB = KernelCommand->DCDB; + if (!((DataTransferLength == 0 && + DCDB->Direction == DAC960_DCDB_NoDataTransfer) || + (DataTransferLength > 0 && + DCDB->Direction == DAC960_DCDB_DataTransferDeviceToSystem) || + (DataTransferLength < 0 && + DCDB->Direction == DAC960_DCDB_DataTransferSystemToDevice))) + return -EINVAL; + if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength) + != abs(DataTransferLength)) + return -EINVAL; + } + if (DataTransferLength != 0 && DataTransferBuffer == NULL) + return -EINVAL; + if (DataTransferLength > 0) + memset(DataTransferBuffer, 0, DataTransferLength); + if (CommandOpcode == DAC960_DCDB) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + if (!Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID]) + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + else Controller->DirectCommandActive[DCDB->Channel] + [DCDB->TargetID] = true; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB); + Command->KernelCommand = KernelCommand; + DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer); + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + else + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + if (Command == NULL) + { + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return -EBUSY; + } + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_QueuedCommand; + memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox, + sizeof(DAC960_CommandMailbox_T)); + if (DataTransferBuffer != NULL) + Command->CommandMailbox.Type3.BusAddress = + Virtual_to_Bus(DataTransferBuffer); + Command->KernelCommand = KernelCommand; + DAC960_QueueCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + } + return 0; + } + } + return -EINVAL; +} + + +/* + DAC960_GenericDiskInit is the Generic Disk Information Initialization + Function for the DAC960 Driver. +*/ + +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo) +{ + DAC960_Controller_T *Controller = + (DAC960_Controller_T *) GenericDiskInfo->real_devices; + DAC960_LogicalDriveInformation_T *LogicalDriveInformation = + Controller->LogicalDriveInformation + [Controller->LogicalDriveInformationIndex]; + int LogicalDriveNumber; + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects = + LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize; +} + + +/* + DAC960_Message prints Driver Messages. +*/ + +static void DAC960_Message(DAC960_MessageLevel_T MessageLevel, + char *Format, + DAC960_Controller_T *Controller, + ...) +{ + static char Buffer[DAC960_LineBufferSize]; + static boolean BeginningOfLine = true; + va_list Arguments; + int Length = 0; + va_start(Arguments, Controller); + Length = vsprintf(Buffer, Format, Arguments); + va_end(Arguments); + if (Controller == NULL) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + DAC960_ControllerCount, Buffer); + else if (MessageLevel == DAC960_AnnounceLevel || + MessageLevel == DAC960_InfoLevel) + { + if (!Controller->ControllerInitialized) + { + strcpy(&Controller->InitialStatusBuffer[ + Controller->InitialStatusLength], Buffer); + Controller->InitialStatusLength += Length; + if (MessageLevel == DAC960_AnnounceLevel) + { + static int AnnouncementLines = 0; + if (++AnnouncementLines <= 2) + printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], + Buffer); + } + else + { + if (BeginningOfLine) + { + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", + DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else printk("%s", Buffer); + } + } + else + { + strcpy(&Controller->CurrentStatusBuffer[ + Controller->CurrentStatusLength], Buffer); + Controller->CurrentStatusLength += Length; + } + } + else if (MessageLevel == DAC960_ProgressLevel) + { + strcpy(Controller->RebuildProgressBuffer, Buffer); + Controller->RebuildProgressLength = Length; + if (Controller->EphemeralProgressMessage) + { + if (jiffies - Controller->LastProgressReportTime + >= DAC960_ProgressReportingInterval) + { + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + Controller->LastProgressReportTime = jiffies; + } + } + else printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else if (MessageLevel == DAC960_UserCriticalLevel) + { + strcpy(&Controller->UserStatusBuffer[Controller->UserStatusLength], + Buffer); + Controller->UserStatusLength += Length; + if (Buffer[0] != '\n' || Length > 1) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + } + else + { + if (BeginningOfLine) + printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel], + Controller->ControllerNumber, Buffer); + else printk("%s", Buffer); + } + BeginningOfLine = (Buffer[Length-1] == '\n'); +} + + +/* + DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive + Channel:TargetID specification from a User Command string. It updates + Channel and TargetID and returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *Channel, + unsigned char *TargetID) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XChannel, XTargetID; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XChannel = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != ':' || + XChannel >= Controller->Channels) + return false; + UserCommandString = ++NewUserCommandString; + XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XTargetID >= DAC960_MaxTargets) + return false; + *Channel = XChannel; + *TargetID = XTargetID; + return true; +} + + +/* + DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number + specification from a User Command string. It updates LogicalDriveNumber and + returns true on success and returns false otherwise. +*/ + +static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller, + char *UserCommandString, + unsigned char *LogicalDriveNumber) +{ + char *NewUserCommandString = UserCommandString; + unsigned long XLogicalDriveNumber; + while (*UserCommandString == ' ') UserCommandString++; + if (UserCommandString == NewUserCommandString) + return false; + XLogicalDriveNumber = + simple_strtoul(UserCommandString, &NewUserCommandString, 10); + if (NewUserCommandString == UserCommandString || + *NewUserCommandString != '\0' || + XLogicalDriveNumber >= Controller->LogicalDriveCount) + return false; + *LogicalDriveNumber = XLogicalDriveNumber; + return true; +} + + +/* + DAC960_SetDeviceState sets the Device State for a Physical Drive. +*/ + +static void DAC960_SetDeviceState(DAC960_Controller_T *Controller, + DAC960_Command_T *Command, + unsigned char Channel, + unsigned char TargetID, + DAC960_PhysicalDeviceState_T DeviceState, + const char *DeviceStateString) +{ + DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox; + CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + CommandMailbox->Type3D.DeviceState = DeviceState; + CommandMailbox->Type3D.Modifier = 0; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_UnableToStartDevice: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unable to Start Device\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_NoDeviceAtAddress: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "No Device at Address\n", Controller, + DeviceStateString, Channel, TargetID); + break; + case DAC960_InvalidChannelOrTargetOrModifier: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Invalid Channel or Target or Modifier\n", + Controller, DeviceStateString, Channel, TargetID); + break; + case DAC960_ChannelBusy: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Channel Busy\n", Controller, + DeviceStateString, Channel, TargetID); + break; + default: + DAC960_UserCritical("%s of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + DeviceStateString, Channel, TargetID, + Command->CommandStatus); + break; + } +} + + +/* + DAC960_ExecuteUserCommand executes a User Command. +*/ + +static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller, + char *UserCommand) +{ + DAC960_Command_T *Command; + DAC960_CommandMailbox_T *CommandMailbox; + ProcessorFlags_T ProcessorFlags; + unsigned char Channel, TargetID, LogicalDriveNumber; + while (true) + { + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Command = DAC960_AllocateCommand(Controller); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + if (Command != NULL) break; + sleep_on(&Controller->CommandWaitQueue); + } + Controller->UserStatusLength = 0; + DAC960_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + CommandMailbox = &Command->CommandMailbox; + if (strcmp(UserCommand, "flush-cache") == 0) + { + CommandMailbox->Type3.CommandOpcode = DAC960_Flush; + DAC960_ExecuteCommand(Command); + DAC960_UserCritical("Cache Flush Completed\n", Controller); + } + else if (strncmp(UserCommand, "kill", 4) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[4], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState != DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Dead, "Kill"); + else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "make-online", 11) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[11], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Online, "Make Online"); + else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + + } + else if (strncmp(UserCommand, "make-standby", 12) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[12], + &Channel, &TargetID)) + { + DAC960_DeviceState_T *DeviceState = + &Controller->DeviceState[Controller->DeviceStateIndex] + [Channel][TargetID]; + if (DeviceState->Present && + DeviceState->DeviceType == DAC960_DiskType && + DeviceState->DeviceState == DAC960_Device_Dead) + DAC960_SetDeviceState(Controller, Command, Channel, TargetID, + DAC960_Device_Standby, "Make Standby"); + else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n", + Controller, Channel, TargetID); + } + else if (strncmp(UserCommand, "rebuild", 7) == 0 && + DAC960_ParsePhysicalDrive(Controller, &UserCommand[7], + &Channel, &TargetID)) + { + CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync; + CommandMailbox->Type3D.Channel = Channel; + CommandMailbox->Type3D.TargetID = TargetID; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n", + Controller, Channel, TargetID); + break; + case DAC960_AttemptToRebuildOnlineDrive: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Attempt to Rebuild Online or " + "Unresponsive Drive\n", + Controller, Channel, TargetID); + break; + case DAC960_NewDiskFailedDuringRebuild: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "New Disk Failed During Rebuild\n", + Controller, Channel, TargetID); + break; + case DAC960_InvalidDeviceAddress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Invalid Device Address\n", + Controller, Channel, TargetID); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Rebuild or Consistency Check Already " + "in Progress\n", Controller, Channel, TargetID); + break; + default: + DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - " + "Unexpected Status %04X\n", Controller, + Channel, TargetID, Command->CommandStatus); + break; + } + } + else if (strncmp(UserCommand, "check-consistency", 17) == 0 && + DAC960_ParseLogicalDrive(Controller, &UserCommand[17], + &LogicalDriveNumber)) + { + CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync; + CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber; + CommandMailbox->Type3C.AutoRestore = true; + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Initiated\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_DependentDiskIsDead: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Dependent Physical Drive is DEAD\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_InvalidOrNonredundantLogicalDrive: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Invalid or Nonredundant Logical Drive\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + case DAC960_RebuildOrCheckAlreadyInProgress: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - Rebuild or " + "Consistency Check Already in Progress\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber); + break; + default: + DAC960_UserCritical("Consistency Check of Logical Drive %d " + "(/dev/rd/c%dd%d) Failed - " + "Unexpected Status %04X\n", + Controller, LogicalDriveNumber, + Controller->ControllerNumber, + LogicalDriveNumber, Command->CommandStatus); + break; + } + } + else if (strcmp(UserCommand, "cancel-rebuild") == 0 || + strcmp(UserCommand, "cancel-consistency-check") == 0) + { + unsigned char OldRebuildRateConstant; + CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl; + CommandMailbox->Type3R.RebuildRateConstant = 0xFF; + CommandMailbox->Type3R.BusAddress = + Virtual_to_Bus(&OldRebuildRateConstant); + DAC960_ExecuteCommand(Command); + switch (Command->CommandStatus) + { + case DAC960_NormalCompletion: + DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n", + Controller); + break; + default: + DAC960_UserCritical("Cancellation of Rebuild or " + "Consistency Check Failed - " + "Unexpected Status %04X\n", + Controller, Command->CommandStatus); + break; + } + } + else DAC960_UserCritical("Illegal User Command: '%s'\n", + Controller, UserCommand); + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + DAC960_DeallocateCommand(Command); + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + return true; +} + + +/* + DAC960_ProcReadStatus implements reading /proc/rd/status. +*/ + +static ssize_t DAC960_ProcReadStatus(char *Page, char **Start, + off_t Offset, int Count, + int *EOF, void *Data) +{ + char *StatusMessage = "OK\n"; + int ControllerNumber, BytesAvailable; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + DAC960_Enquiry_T *Enquiry; + if (Controller == NULL) continue; + Enquiry = &Controller->Enquiry[Controller->EnquiryIndex]; + if (Enquiry->CriticalLogicalDriveCount > 0 || + Enquiry->OfflineLogicalDriveCount > 0 || + Enquiry->DeadDriveCount > 0) + { + StatusMessage = "ALERT\n"; + break; + } + } + BytesAvailable = strlen(StatusMessage) - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + memcpy(Page, &StatusMessage[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status. +*/ + +static ssize_t DAC960_ProcReadInitialStatus(char *Page, char **Start, + off_t Offset, int Count, + int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->InitialStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + memcpy(Page, &Controller->InitialStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status. +*/ + +static ssize_t DAC960_ProcReadCurrentStatus(char *Page, char **Start, + off_t Offset, int Count, + int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable; + Controller->CurrentStatusLength = 0; + DAC960_AnnounceDriver(Controller); + DAC960_ReportControllerConfiguration(Controller); + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' '; + if (Controller->RebuildProgressLength > 0) + { + strcpy(&Controller->CurrentStatusBuffer[Controller->CurrentStatusLength], + Controller->RebuildProgressBuffer); + Controller->CurrentStatusLength += Controller->RebuildProgressLength; + } + else + { + char *StatusMessage = "No Rebuild or Consistency Check in Progress\n"; + strcpy(&Controller->CurrentStatusBuffer[Controller->CurrentStatusLength], + StatusMessage); + Controller->CurrentStatusLength += strlen(StatusMessage); + } + BytesAvailable = Controller->CurrentStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command. +*/ + +static ssize_t DAC960_ProcReadUserCommand(char *Page, char **Start, + off_t Offset, int Count, + int *EOF, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + int BytesAvailable = Controller->UserStatusLength - Offset; + if (Count >= BytesAvailable) + { + Count = BytesAvailable; + *EOF = true; + } + if (Count <= 0) return 0; + memcpy(Page, &Controller->UserStatusBuffer[Offset], Count); + return Count; +} + + +/* + DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command. +*/ + +static ssize_t DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer, + unsigned long Count, void *Data) +{ + DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data; + char CommandBuffer[80]; + int Length; + if (Count > sizeof(CommandBuffer)-1) return -EINVAL; + copy_from_user(CommandBuffer, Buffer, Count); + CommandBuffer[Count] = '\0'; + Length = strlen(CommandBuffer); + if (CommandBuffer[Length-1] == '\n') + CommandBuffer[--Length] = '\0'; + return (DAC960_ExecuteUserCommand(Controller, CommandBuffer) + ? Count : -EBUSY); +} + + +/* + DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_CreateProcEntries(void) +{ + static PROC_DirectoryEntry_T StatusProcEntry; + int ControllerNumber; + DAC960_ProcDirectoryEntry.name = "rd"; + DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name); + DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&proc_root, &DAC960_ProcDirectoryEntry); + StatusProcEntry.name = "status"; + StatusProcEntry.namelen = strlen(StatusProcEntry.name); + StatusProcEntry.mode = S_IFREG | S_IRUGO; + StatusProcEntry.read_proc = DAC960_ProcReadStatus; + proc_register(&DAC960_ProcDirectoryEntry, &StatusProcEntry); + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + PROC_DirectoryEntry_T *ControllerProcEntry, *InitialStatusProcEntry; + PROC_DirectoryEntry_T *CurrentStatusProcEntry, *UserCommandProcEntry; + if (Controller == NULL) continue; + ControllerProcEntry = &Controller->ControllerProcEntry; + ControllerProcEntry->name = Controller->ControllerName; + ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); + ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + proc_register(&DAC960_ProcDirectoryEntry, ControllerProcEntry); + InitialStatusProcEntry = &Controller->InitialStatusProcEntry; + InitialStatusProcEntry->name = "initial_status"; + InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); + InitialStatusProcEntry->mode = S_IFREG | S_IRUGO; + InitialStatusProcEntry->data = Controller; + InitialStatusProcEntry->read_proc = DAC960_ProcReadInitialStatus; + proc_register(ControllerProcEntry, InitialStatusProcEntry); + CurrentStatusProcEntry = &Controller->CurrentStatusProcEntry; + CurrentStatusProcEntry->name = "current_status"; + CurrentStatusProcEntry->namelen = strlen(CurrentStatusProcEntry->name); + CurrentStatusProcEntry->mode = S_IFREG | S_IRUGO; + CurrentStatusProcEntry->data = Controller; + CurrentStatusProcEntry->read_proc = DAC960_ProcReadCurrentStatus; + proc_register(ControllerProcEntry, CurrentStatusProcEntry); + UserCommandProcEntry = &Controller->UserCommandProcEntry; + UserCommandProcEntry->name = "user_command"; + UserCommandProcEntry->namelen = strlen(UserCommandProcEntry->name); + UserCommandProcEntry->mode = S_IFREG | S_IWUSR | S_IRUSR; + UserCommandProcEntry->data = Controller; + UserCommandProcEntry->read_proc = DAC960_ProcReadUserCommand; + UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; + proc_register(ControllerProcEntry, UserCommandProcEntry); + } +} + + +/* + DAC960_DestroyProcEntries destroys the /proc/rd/... entries for the DAC960 + Driver. +*/ + +static void DAC960_DestroyProcEntries(void) +{ + proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino); +} + + +/* + Include Module support if requested. +*/ + +#ifdef MODULE + + +int init_module(void) +{ + int ControllerNumber, LogicalDriveNumber; + DAC960_Initialize(); + if (DAC960_ActiveControllerCount == 0) return -1; + for (ControllerNumber = 0; + ControllerNumber < DAC960_ControllerCount; + ControllerNumber++) + { + DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; + if (Controller == NULL) continue; + DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo); + for (LogicalDriveNumber = 0; + LogicalDriveNumber < Controller->LogicalDriveCount; + LogicalDriveNumber++) + resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber); + } + return 0; +} + + +void cleanup_module(void) +{ + DAC960_Finalize(&DAC960_NotifierBlock, SYS_RESTART, NULL); +} + + +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h --- v2.2.10/linux/drivers/block/DAC960.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/DAC960.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,2184 @@ +/* + + Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers + + Copyright 1998-1999 by Leonard N. Zubkoff + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + 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 complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + +*/ + + +/* + Define the maximum number of DAC960 Controllers supported by this driver. +*/ + +#define DAC960_MaxControllers 8 + + +/* + Define the maximum number of Controller Channels supported by this driver. +*/ + +#define DAC960_MaxChannels 3 + + +/* + Define the maximum number of Targets per Channel supported by this driver. +*/ + +#define DAC960_MaxTargets 16 + + +/* + Define the maximum number of Logical Drives supported by any DAC960 model. +*/ + +#define DAC960_MaxLogicalDrives 32 + + +/* + Define a Boolean data type. +*/ + +typedef enum { false, true } __attribute__ ((packed)) boolean; + + +/* + Define a 32 bit I/O Address data type. +*/ + +typedef unsigned int DAC960_IO_Address_T; + + +/* + Define a 32 bit PCI Bus Address data type. +*/ + +typedef unsigned int DAC960_PCI_Address_T; + + +/* + Define a 32 bit Bus Address data type. +*/ + +typedef unsigned int DAC960_BusAddress_T; + + +/* + Define a 32 bit Byte Count data type. +*/ + +typedef unsigned int DAC960_ByteCount_T; + + +/* + Define the DAC960 Command Opcodes. +*/ + +typedef enum +{ + /* I/O Commands */ + DAC960_ReadExtended = 0x33, + DAC960_WriteExtended = 0x34, + DAC960_ReadAheadExtended = 0x35, + DAC960_ReadExtendedWithScatterGather = 0xB3, + DAC960_WriteExtendedWithScatterGather = 0xB4, + DAC960_Read = 0x36, + DAC960_ReadWithOldScatterGather = 0xB6, + DAC960_Write = 0x37, + DAC960_WriteWithOldScatterGather = 0xB7, + DAC960_DCDB = 0x04, + DAC960_DCDBWithScatterGather = 0x84, + DAC960_Flush = 0x0A, + /* Controller Status Related Commands */ + DAC960_Enquiry = 0x53, + DAC960_Enquiry2 = 0x1C, + DAC960_GetLogicalDriveElement = 0x55, + DAC960_GetLogicalDriveInformation = 0x19, + DAC960_IOPortRead = 0x39, + DAC960_IOPortWrite = 0x3A, + DAC960_GetSDStats = 0x3E, + DAC960_GetPDStats = 0x3F, + DAC960_PerformEventLogOperation = 0x72, + /* Device Related Commands */ + DAC960_StartDevice = 0x10, + DAC960_GetDeviceState = 0x50, + DAC960_StopChannel = 0x13, + DAC960_StartChannel = 0x12, + DAC960_ResetChannel = 0x1A, + /* Commands Associated with Data Consistency and Errors */ + DAC960_Rebuild = 0x09, + DAC960_RebuildAsync = 0x16, + DAC960_CheckConsistency = 0x0F, + DAC960_CheckConsistencyAsync = 0x1E, + DAC960_RebuildStat = 0x0C, + DAC960_GetRebuildProgress = 0x27, + DAC960_RebuildControl = 0x1F, + DAC960_ReadBadBlockTable = 0x0B, + DAC960_ReadBadDataTable = 0x25, + DAC960_ClearBadDataTable = 0x26, + DAC960_GetErrorTable = 0x17, + DAC960_AddCapacityAsync = 0x2A, + /* Configuration Related Commands */ + DAC960_ReadConfig2 = 0x3D, + DAC960_WriteConfig2 = 0x3C, + DAC960_ReadConfigurationOnDisk = 0x4A, + DAC960_WriteConfigurationOnDisk = 0x4B, + DAC960_ReadConfiguration = 0x4E, + DAC960_ReadBackupConfiguration = 0x4D, + DAC960_WriteConfiguration = 0x4F, + DAC960_AddConfiguration = 0x4C, + DAC960_ReadConfigurationLabel = 0x48, + DAC960_WriteConfigurationLabel = 0x49, + /* Firmware Upgrade Related Commands */ + DAC960_LoadImage = 0x20, + DAC960_StoreImage = 0x21, + DAC960_ProgramImage = 0x22, + /* Diagnostic Commands */ + DAC960_SetDiagnosticMode = 0x31, + DAC960_RunDiagnostic = 0x32, + /* Subsystem Service Commands */ + DAC960_GetSubsystemData = 0x70, + DAC960_SetSubsystemParameters = 0x71 +} +__attribute__ ((packed)) +DAC960_CommandOpcode_T; + + +/* + Define the DAC960 Command Identifier type. +*/ + +typedef unsigned char DAC960_CommandIdentifier_T; + + +/* + Define the DAC960 Command Status Codes. +*/ + +#define DAC960_NormalCompletion 0x0000 /* Common */ +#define DAC960_CheckConditionReceived 0x0002 /* Common */ +#define DAC960_NoDeviceAtAddress 0x0102 /* Common */ +#define DAC960_InvalidDeviceAddress 0x0105 /* Common */ +#define DAC960_InvalidParameter 0x0105 /* Common */ +#define DAC960_IrrecoverableDataError 0x0001 /* I/O */ +#define DAC960_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */ +#define DAC960_AccessBeyondEndOfLogicalDrive 0x0105 /* I/O */ +#define DAC960_BadDataEncountered 0x010C /* I/O */ +#define DAC960_DeviceBusy 0x0008 /* DCDB */ +#define DAC960_DeviceNonresponsive 0x000E /* DCDB */ +#define DAC960_CommandTerminatedAbnormally 0x000F /* DCDB */ +#define DAC960_UnableToStartDevice 0x0002 /* Device */ +#define DAC960_InvalidChannelOrTargetOrModifier 0x0105 /* Device */ +#define DAC960_ChannelBusy 0x0106 /* Device */ +#define DAC960_ChannelNotStopped 0x0002 /* Device */ +#define DAC960_AttemptToRebuildOnlineDrive 0x0002 /* Consistency */ +#define DAC960_RebuildBadBlocksEncountered 0x0003 /* Consistency */ +#define DAC960_NewDiskFailedDuringRebuild 0x0004 /* Consistency */ +#define DAC960_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */ +#define DAC960_DependentDiskIsDead 0x0002 /* Consistency */ +#define DAC960_InconsistentBlocksFound 0x0003 /* Consistency */ +#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */ +#define DAC960_NoRebuildOrCheckInProgress 0x0105 /* Consistency */ +#define DAC960_RebuildInProgress_DataValid 0x0000 /* Consistency */ +#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */ +#define DAC960_RebuildFailed_BadBlocksOnOther 0x0003 /* Consistency */ +#define DAC960_RebuildFailed_NewDriveFailed 0x0004 /* Consistency */ +#define DAC960_RebuildSuccessful 0x0100 /* Consistency */ +#define DAC960_AddCapacityInProgress 0x0004 /* Consistency */ +#define DAC960_AddCapacityFailedOrSuspended 0x00F4 /* Consistency */ +#define DAC960_Config2ChecksumError 0x0002 /* Configuration */ +#define DAC960_ConfigurationSuspended 0x0106 /* Configuration */ +#define DAC960_FailedToConfigureNVRAM 0x0105 /* Configuration */ +#define DAC960_ConfigurationNotSavedStateChange 0x0106 /* Configuration */ +#define DAC960_SubsystemNotInstalled 0x0001 /* Subsystem */ +#define DAC960_SubsystemFailed 0x0002 /* Subsystem */ +#define DAC960_SubsystemBusy 0x0106 /* Subsystem */ + +typedef unsigned short DAC960_CommandStatus_T; + + +/* + Define the Enquiry reply structure. +*/ + +typedef struct DAC960_Enquiry +{ + unsigned char NumberOfLogicalDrives; /* Byte 0 */ + unsigned int :24; /* Bytes 1-3 */ + unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */ + unsigned short FlashAge; /* Bytes 132-133 */ + struct { + boolean DeferredWriteError:1; /* Byte 134 Bit 0 */ + boolean BatteryLow:1; /* Byte 134 Bit 1 */ + unsigned char :6; /* Byte 134 Bits 2-7 */ + } StatusFlags; + unsigned char :8; /* Byte 135 */ + unsigned char MinorFirmwareVersion; /* Byte 136 */ + unsigned char MajorFirmwareVersion; /* Byte 137 */ + enum { + DAC960_NoStandbyRebuildOrCheckInProgress = 0x00, + DAC960_StandbyRebuildInProgress = 0x01, + DAC960_BackgroundRebuildInProgress = 0x02, + DAC960_BackgroundCheckInProgress = 0x03, + DAC960_StandbyRebuildCompletedWithError = 0xFF, + DAC960_BackgroundRebuildOrCheckFailed_DriveFailed = 0xF0, + DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed = 0xF1, + DAC960_BackgroundRebuildOrCheckFailed_OtherCauses = 0xF2, + DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated = 0xF3 + } __attribute__ ((packed)) RebuildFlag; /* Byte 138 */ + unsigned char MaxCommands; /* Byte 139 */ + unsigned char OfflineLogicalDriveCount; /* Byte 140 */ + unsigned char :8; /* Byte 141 */ + unsigned short EventLogSequenceNumber; /* Bytes 142-143 */ + unsigned char CriticalLogicalDriveCount; /* Byte 144 */ + unsigned int :24; /* Bytes 145-147 */ + unsigned char DeadDriveCount; /* Byte 148 */ + unsigned char :8; /* Byte 149 */ + unsigned char RebuildCount; /* Byte 150 */ + struct { + unsigned char :3; /* Byte 151 Bits 0-2 */ + boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */ + unsigned char :3; /* Byte 151 Bits 4-6 */ + unsigned char :1; /* Byte 151 Bit 7 */ + } MiscFlags; + struct { + unsigned char TargetID; + unsigned char Channel; + } DeadDrives[21]; /* Bytes 152-194 */ + unsigned char Reserved[62]; /* Bytes 195-255 */ +} +__attribute__ ((packed)) +DAC960_Enquiry_T; + + +/* + Define the Enquiry2 reply structure. +*/ + +typedef struct DAC960_Enquiry2 +{ + struct { + enum { + DAC960_P_PD_PU = 0x01, + DAC960_PL = 0x02, + DAC960_PG = 0x10, + DAC960_PJ = 0x11, + DAC960_PR = 0x12, + DAC960_PT = 0x13, + DAC960_PTL0 = 0x14, + DAC960_PRL = 0x15, + DAC960_PTL1 = 0x16, + DAC1164_P = 0x20 + } __attribute__ ((packed)) SubModel; /* Byte 0 */ + unsigned char ActualChannels; /* Byte 1 */ + enum { + DAC960_FiveChannelBoard = 0x01, + DAC960_ThreeChannelBoard = 0x02, + DAC960_TwoChannelBoard = 0x03, + DAC960_ThreeChannelASIC_DAC = 0x04 + } __attribute__ ((packed)) Model; /* Byte 2 */ + enum { + DAC960_EISA_Controller = 0x01, + DAC960_MicroChannel_Controller = 0x02, + DAC960_PCI_Controller = 0x03, + DAC960_SCSItoSCSI_Controller = 0x08 + } __attribute__ ((packed)) ProductFamily; /* Byte 3 */ + } HardwareID; /* Bytes 0-3 */ + /* MajorVersion.MinorVersion-FirmwareType-TurnID */ + struct { + unsigned char MajorVersion; /* Byte 4 */ + unsigned char MinorVersion; /* Byte 5 */ + unsigned char TurnID; /* Byte 6 */ + char FirmwareType; /* Byte 7 */ + } FirmwareID; /* Bytes 4-7 */ + unsigned char :8; /* Byte 8 */ + unsigned int :24; /* Bytes 9-11 */ + unsigned char ConfiguredChannels; /* Byte 12 */ + unsigned char ActualChannels; /* Byte 13 */ + unsigned char MaxTargets; /* Byte 14 */ + unsigned char MaxTags; /* Byte 15 */ + unsigned char MaxLogicalDrives; /* Byte 16 */ + unsigned char MaxArms; /* Byte 17 */ + unsigned char MaxSpans; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + unsigned int :32; /* Bytes 20-23 */ + unsigned int MemorySize; /* Bytes 24-27 */ + unsigned int CacheSize; /* Bytes 28-31 */ + unsigned int FlashMemorySize; /* Bytes 32-35 */ + unsigned int NonVolatileMemorySize; /* Bytes 36-39 */ + struct { + enum { + DAC960_DRAM = 0x00, + DAC960_EDO = 0x01, + DAC960_SDRAM = 0x02 + } __attribute__ ((packed)) RamType:3; /* Byte 40 Bits 0-2 */ + enum { + DAC960_None = 0x00, + DAC960_Parity = 0x01, + DAC960_ECC = 0x02 + } __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */ + boolean FastPageMode:1; /* Byte 40 Bit 6 */ + boolean LowPowerMemory:1; /* Byte 40 Bit 7 */ + unsigned char :8; /* Bytes 41 */ + } MemoryType; + unsigned short ClockSpeed; /* Bytes 42-43 */ + unsigned short MemorySpeed; /* Bytes 44-45 */ + unsigned short HardwareSpeed; /* Bytes 46-47 */ + unsigned int :32; /* Bytes 48-51 */ + unsigned int :32; /* Bytes 52-55 */ + unsigned char :8; /* Byte 56 */ + unsigned char :8; /* Byte 57 */ + unsigned short :16; /* Bytes 58-59 */ + unsigned short MaxCommands; /* Bytes 60-61 */ + unsigned short MaxScatterGatherEntries; /* Bytes 62-63 */ + unsigned short MaxDriveCommands; /* Bytes 64-65 */ + unsigned short MaxIODescriptors; /* Bytes 66-67 */ + unsigned short MaxCombinedSectors; /* Bytes 68-69 */ + unsigned char Latency; /* Byte 70 */ + unsigned char :8; /* Byte 71 */ + unsigned char SCSITimeout; /* Byte 72 */ + unsigned char :8; /* Byte 73 */ + unsigned short MinFreeLines; /* Bytes 74-75 */ + unsigned int :32; /* Bytes 76-79 */ + unsigned int :32; /* Bytes 80-83 */ + unsigned char RebuildRateConstant; /* Byte 84 */ + unsigned char :8; /* Byte 85 */ + unsigned char :8; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ + unsigned int :32; /* Bytes 88-91 */ + unsigned int :32; /* Bytes 92-95 */ + unsigned short PhysicalDriveBlockSize; /* Bytes 96-97 */ + unsigned short LogicalDriveBlockSize; /* Bytes 98-99 */ + unsigned short MaxBlocksPerCommand; /* Bytes 100-101 */ + unsigned short BlockFactor; /* Bytes 102-103 */ + unsigned short CacheLineSize; /* Bytes 104-105 */ + struct { + enum { + DAC960_Narrow_8bit = 0x00, + DAC960_Wide_16bit = 0x01, + DAC960_Wide_32bit = 0x02 + } __attribute__ ((packed)) BusWidth:2; /* Byte 106 Bits 0-1 */ + enum { + DAC960_Fast = 0x00, + DAC960_Ultra = 0x01, + DAC960_Ultra2 = 0x02 + } __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */ + boolean Differential:1; /* Byte 106 Bit 4 */ + unsigned char :3; /* Byte 106 Bits 5-7 */ + } SCSICapability; + unsigned char :8; /* Byte 107 */ + unsigned int :32; /* Bytes 108-111 */ + unsigned short FirmwareBuildNumber; /* Bytes 112-113 */ + enum { + DAC960_AEMI = 0x01, + DAC960_OEM1 = 0x02, + DAC960_OEM2 = 0x04, + DAC960_OEM3 = 0x08, + DAC960_Conner = 0x10, + DAC960_SAFTE = 0x20 + } __attribute__ ((packed)) FaultManagementType; /* Byte 114 */ + unsigned char :8; /* Byte 115 */ + struct { + boolean Clustering:1; /* Byte 116 Bit 0 */ + boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */ + unsigned int :30; /* Bytes 116-119 */ + } FirmwareFeatures; + unsigned int :32; /* Bytes 120-123 */ + unsigned int :32; /* Bytes 124-127 */ +} +DAC960_Enquiry2_T; + + +/* + Define the Logical Drive State type. +*/ + +typedef enum +{ + DAC960_LogicalDrive_Online = 0x03, + DAC960_LogicalDrive_Critical = 0x04, + DAC960_LogicalDrive_Offline = 0xFF +} +__attribute__ ((packed)) +DAC960_LogicalDriveState_T; + + +/* + Define the Get Logical Drive Information reply structure. +*/ + +typedef struct DAC960_LogicalDriveInformation +{ + unsigned int LogicalDriveSize; /* Bytes 0-3 */ + DAC960_LogicalDriveState_T LogicalDriveState; /* Byte 4 */ + unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */ + boolean WriteBack:1; /* Byte 5 Bit 7 */ + unsigned int :16; /* Bytes 6-7 */ +} +DAC960_LogicalDriveInformation_T; + + +/* + Define the Perform Event Log Operation Types. +*/ + +typedef enum +{ + DAC960_GetEventLogEntry = 0x00 +} +__attribute__ ((packed)) +DAC960_PerformEventLogOpType_T; + + +/* + Define the Get Event Log Entry reply structure. +*/ + +typedef struct DAC960_EventLogEntry +{ + unsigned char MessageType; /* Byte 0 */ + unsigned char MessageLength; /* Byte 1 */ + unsigned char TargetID:5; /* Byte 2 Bits 0-4 */ + unsigned char Channel:3; /* Byte 2 Bits 5-7 */ + unsigned char LogicalUnit:6; /* Byte 3 Bits 0-5 */ + unsigned char :2; /* Byte 3 Bits 6-7 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */ + boolean Valid:1; /* Byte 6 Bit 7 */ + unsigned char SegmentNumber; /* Byte 7 */ + unsigned char SenseKey:4; /* Byte 8 Bits 0-3 */ + unsigned char :1; /* Byte 8 Bit 4 */ + boolean ILI:1; /* Byte 8 Bit 5 */ + boolean EOM:1; /* Byte 8 Bit 6 */ + boolean Filemark:1; /* Byte 8 Bit 7 */ + unsigned char Information[4]; /* Bytes 9-12 */ + unsigned char AdditionalSenseLength; /* Byte 13 */ + unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */ + unsigned char AdditionalSenseCode; /* Byte 18 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 19 */ + unsigned char Dummy[12]; /* Bytes 20-31 */ +} +DAC960_EventLogEntry_T; + + +/* + Define the Physical Device State type. +*/ + +typedef enum +{ + DAC960_Device_Dead = 0x00, + DAC960_Device_WriteOnly = 0x02, + DAC960_Device_Online = 0x03, + DAC960_Device_Standby = 0x10 +} +__attribute__ ((packed)) +DAC960_PhysicalDeviceState_T; + + +/* + Define the Get Device State reply structure. +*/ + +typedef struct DAC960_DeviceState +{ + boolean Present:1; /* Byte 0 Bit 0 */ + unsigned char :7; /* Byte 0 Bits 1-7 */ + enum { + DAC960_OtherType = 0x00, + DAC960_DiskType = 0x01, + DAC960_SequentialType = 0x02, + DAC960_CDROM_or_WORM_Type = 0x03 + } __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */ + boolean :1; /* Byte 1 Bit 2 */ + boolean Fast20:1; /* Byte 1 Bit 3 */ + boolean Sync:1; /* Byte 1 Bit 4 */ + boolean Fast:1; /* Byte 1 Bit 5 */ + boolean Wide:1; /* Byte 1 Bit 6 */ + boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */ + DAC960_PhysicalDeviceState_T DeviceState; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + unsigned char SynchronousMultiplier; /* Byte 4 */ + unsigned char SynchronousOffset:5; /* Byte 5 Bits 0-4 */ + unsigned char :3; /* Byte 5 Bits 5-7 */ + unsigned long DiskSize __attribute__ ((packed)); /* Bytes 6-9 */ +} +DAC960_DeviceState_T; + + +/* + Define the Get Rebuild Progress reply structure. +*/ + +typedef struct DAC960_RebuildProgress +{ + unsigned int LogicalDriveNumber; /* Bytes 0-3 */ + unsigned int LogicalDriveSize; /* Bytes 4-7 */ + unsigned int RemainingBlocks; /* Bytes 8-11 */ +} +DAC960_RebuildProgress_T; + + +/* + Define the Error Table Entry and Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTableEntry +{ + unsigned char ParityErrorCount; /* Byte 0 */ + unsigned char SoftErrorCount; /* Byte 1 */ + unsigned char HardErrorCount; /* Byte 2 */ + unsigned char MiscErrorCount; /* Byte 3 */ +} +DAC960_ErrorTableEntry_T; + + +/* + Define the Get Error Table reply structure. +*/ + +typedef struct DAC960_ErrorTable +{ + DAC960_ErrorTableEntry_T + ErrorTableEntries[DAC960_MaxChannels][DAC960_MaxTargets]; +} +DAC960_ErrorTable_T; + + +/* + Define the Config2 reply structure. +*/ + +typedef struct DAC960_Config2 +{ + unsigned char :1; /* Byte 0 Bit 0 */ + boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */ + unsigned char :5; /* Byte 0 Bits 2-6 */ + boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */ + boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */ + boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */ + boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */ + unsigned char :2; /* Byte 1 Bits 3-4 */ + boolean AEMI_ARM:1; /* Byte 1 Bit 5 */ + boolean AEMI_OFM:1; /* Byte 1 Bit 6 */ + unsigned char :1; /* Byte 1 Bit 7 */ + enum { + DAC960_OEMID_Mylex = 0x00, + DAC960_OEMID_IBM = 0x08, + DAC960_OEMID_HP = 0x0A, + DAC960_OEMID_DEC = 0x0C, + DAC960_OEMID_Siemens = 0x10, + DAC960_OEMID_Intel = 0x12 + } __attribute__ ((packed)) OEMID; /* Byte 2 */ + unsigned char OEMModelNumber; /* Byte 3 */ + unsigned char PhysicalSector; /* Byte 4 */ + unsigned char LogicalSector; /* Byte 5 */ + unsigned char BlockFactor; /* Byte 6 */ + boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */ + boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */ + unsigned char :2; /* Byte 7 Bits 2-3 */ + boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */ + unsigned char :1; /* Byte 7 Bit 5 */ + boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */ + boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */ + unsigned char DefaultRebuildRate; /* Byte 8 */ + unsigned char :8; /* Byte 9 */ + unsigned char BlocksPerCacheLine; /* Byte 10 */ + unsigned char BlocksPerStripe; /* Byte 11 */ + struct { + enum { + DAC960_Async = 0x00, + DAC960_Sync_8MHz = 0x01, + DAC960_Sync_5MHz = 0x02, + DAC960_Sync_10or20MHz = 0x03 /* Bits 0-1 */ + } __attribute__ ((packed)) Speed:2; + boolean Force8Bit:1; /* Bit 2 */ + boolean DisableFast20:1; /* Bit 3 */ + unsigned char :3; /* Bits 4-6 */ + boolean EnableTaggedQueuing:1; /* Bit 7 */ + } __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */ + unsigned char SCSIInitiatorID; /* Byte 18 */ + unsigned char :8; /* Byte 19 */ + enum { + DAC960_StartupMode_ControllerSpinUp = 0x00, + DAC960_StartupMode_PowerOnSpinUp = 0x01 + } __attribute__ ((packed)) StartupMode; /* Byte 20 */ + unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */ + unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */ + unsigned char Reserved1[29]; /* Bytes 23-51 */ + boolean BIOSDisabled:1; /* Byte 52 Bit 0 */ + boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */ + unsigned char :3; /* Byte 52 Bits 2-4 */ + enum { + DAC960_Geometry_128_32 = 0x00, + DAC960_Geometry_255_63 = 0x01, + DAC960_Geometry_Reserved1 = 0x02, + DAC960_Geometry_Reserved2 = 0x03 + } __attribute__ ((packed)) DriveGeometry:2; /* Byte 52 Bits 5-6 */ + unsigned char :1; /* Byte 52 Bit 7 */ + unsigned char Reserved2[9]; /* Bytes 53-61 */ + unsigned short Checksum; /* Bytes 62-63 */ +} +DAC960_Config2_T; + + +/* + Define the DCDB request structure. +*/ + +typedef struct DAC960_DCDB +{ + unsigned char TargetID:4; /* Byte 0 Bits 0-3 */ + unsigned char Channel:4; /* Byte 0 Bits 4-7 */ + enum { + DAC960_DCDB_NoDataTransfer = 0, + DAC960_DCDB_DataTransferDeviceToSystem = 1, + DAC960_DCDB_DataTransferSystemToDevice = 2, + DAC960_DCDB_IllegalDataTransfer = 3 + } __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */ + boolean EarlyStatus:1; /* Byte 1 Bit 2 */ + unsigned char :1; /* Byte 1 Bit 3 */ + enum { + DAC960_DCDB_Timeout_24_hours = 0, + DAC960_DCDB_Timeout_10_seconds = 1, + DAC960_DCDB_Timeout_60_seconds = 2, + DAC960_DCDB_Timeout_10_minutes = 3 + } __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */ + boolean NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */ + boolean DisconnectPermitted:1; /* Byte 1 Bit 7 */ + unsigned short TransferLength; /* Bytes 2-3 */ + DAC960_BusAddress_T BusAddress; /* Bytes 4-7 */ + unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */ + unsigned char TransferLengthHigh4:4; /* Byte 8 Bits 4-7 */ + unsigned char SenseLength; /* Byte 9 */ + unsigned char CDB[12]; /* Bytes 10-21 */ + unsigned char SenseData[64]; /* Bytes 22-85 */ + unsigned char Status; /* Byte 86 */ + unsigned char :8; /* Byte 87 */ +} +DAC960_DCDB_T; + + +/* + Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count + structure. +*/ + +typedef struct DAC960_ScatterGatherSegment +{ + DAC960_BusAddress_T SegmentDataPointer; /* Bytes 0-3 */ + DAC960_ByteCount_T SegmentByteCount; /* Bytes 4-7 */ +} +DAC960_ScatterGatherSegment_T; + + +/* + Define the 13 Byte DAC960 Command Mailbox structure. Bytes 13-15 are + not used. The Command Mailbox structure is padded to 16 bytes for + efficient access. +*/ + +typedef union DAC960_CommandMailbox +{ + unsigned int Words[4]; /* Words 0-3 */ + unsigned char Bytes[16]; /* Bytes 0-15 */ + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy[14]; /* Bytes 2-15 */ + } __attribute__ ((packed)) Common; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[6]; /* Bytes 2-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[5]; /* Bytes 2-6 */ + unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */ + boolean AutoRestore:1; /* Byte 7 Bit 7 */ + unsigned char Dummy2[8]; /* Bytes 8-15 */ + } __attribute__ ((packed)) Type3C; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Channel; /* Byte 2 */ + unsigned char TargetID; /* Byte 3 */ + DAC960_PhysicalDeviceState_T DeviceState:5; /* Byte 4 Bits 0-4 */ + unsigned char Modifier:3; /* Byte 4 Bits 5-7 */ + unsigned char Dummy1[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3D; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + DAC960_PerformEventLogOpType_T OperationType; /* Byte 2 */ + unsigned char OperationQualifier; /* Byte 3 */ + unsigned short SequenceNumber; /* Bytes 4-5 */ + unsigned char Dummy1[2]; /* Bytes 6-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy2[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3E; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char Dummy1[2]; /* Bytes 2-3 */ + unsigned char RebuildRateConstant; /* Byte 4 */ + unsigned char Dummy2[3]; /* Bytes 5-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char Dummy3[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) Type3R; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned short TransferLength; /* Bytes 2-3 */ + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char LogicalDriveNumber; /* Byte 12 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type4; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + struct { + unsigned short TransferLength:11; /* Bytes 2-3 */ + unsigned char LogicalDriveNumber:5; /* Byte 3 Bits 3-7 */ + } __attribute__ ((packed)) LD; + unsigned int LogicalBlockAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T BusAddress; /* Bytes 8-11 */ + unsigned char ScatterGatherCount:6; /* Byte 12 Bits 0-5 */ + enum { + DAC960_ScatterGather_32BitAddress_32BitByteCount = 0x0, + DAC960_ScatterGather_32BitAddress_16BitByteCount = 0x1, + DAC960_ScatterGather_32BitByteCount_32BitAddress = 0x2, + DAC960_ScatterGather_16BitByteCount_32BitAddress = 0x3 + } __attribute__ ((packed)) ScatterGatherType:2; /* Byte 12 Bits 6-7 */ + unsigned char Dummy[3]; /* Bytes 13-15 */ + } __attribute__ ((packed)) Type5; + struct { + DAC960_CommandOpcode_T CommandOpcode; /* Byte 0 */ + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 1 */ + unsigned char CommandOpcode2; /* Byte 2 */ + unsigned char :8; /* Byte 3 */ + DAC960_BusAddress_T CommandMailboxesBusAddress; /* Bytes 4-7 */ + DAC960_BusAddress_T StatusMailboxesBusAddress; /* Bytes 8-11 */ + unsigned char Dummy[4]; /* Bytes 12-15 */ + } __attribute__ ((packed)) TypeX; +} +DAC960_CommandMailbox_T; + + +/* + Define the DAC960 Driver IOCTL requests. +*/ + +#define DAC960_IOCTL_GET_CONTROLLER_COUNT 0xDAC001 +#define DAC960_IOCTL_GET_CONTROLLER_INFO 0xDAC002 +#define DAC960_IOCTL_EXECUTE_COMMAND 0xDAC003 + + +/* + Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure. +*/ + +typedef struct DAC960_ControllerInfo +{ + unsigned char ControllerNumber; + unsigned char PCI_Bus; + unsigned char PCI_Device; + unsigned char PCI_Function; + unsigned char IRQ_Channel; + unsigned char Channels; + DAC960_PCI_Address_T PCI_Address; + unsigned char ModelName[16]; + unsigned char FirmwareVersion[16]; +} +DAC960_ControllerInfo_T; + + +/* + Define the User Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_UserCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; +} +DAC960_UserCommand_T; + + +/* + Define the Kernel Mode DAC960_IOCTL_EXECUTE_COMMAND request structure. +*/ + +typedef struct DAC960_KernelCommand +{ + unsigned char ControllerNumber; + DAC960_CommandMailbox_T CommandMailbox; + int DataTransferLength; + void *DataTransferBuffer; + DAC960_DCDB_T *DCDB; + DAC960_CommandStatus_T CommandStatus; + void (*CompletionFunction)(struct DAC960_KernelCommand *); + void *CompletionData; +} +DAC960_KernelCommand_T; + + +/* + Import the Kernel Mode IOCTL interface. +*/ + +extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument); + + +/* + Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses. +*/ + +static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress) +{ + return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress); +} + + +/* + Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses. +*/ + +static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress) +{ + return (void *) bus_to_virt(BusAddress); +} + + +/* + DAC960_DriverVersion protects the private portion of this file. +*/ + +#ifdef DAC960_DriverVersion + + +/* + Define the maximum Driver Queue Depth and Controller Queue Depth supported + by any DAC960 model. +*/ + +#define DAC960_MaxDriverQueueDepth 127 +#define DAC960_MaxControllerQueueDepth 128 + + +/* + Define the maximum number of Scatter/Gather Segments supported by any + DAC960 model. +*/ + +#define DAC960_MaxScatterGatherSegments 33 + + +/* + Define the number of Command Mailboxes and Status Mailboxes used by the + Memory Mailbox Interface. +*/ + +#define DAC960_CommandMailboxCount 256 +#define DAC960_StatusMailboxCount 1024 + + +/* + Define the DAC960 Controller Monitoring Timer Interval. +*/ + +#define DAC960_MonitoringTimerInterval (10 * HZ) + + +/* + Define the DAC960 Controller Secondary Monitoring Interval. +*/ + +#define DAC960_SecondaryMonitoringInterval (60 * HZ) + + +/* + Define the DAC960 Controller Progress Reporting Interval. +*/ + +#define DAC960_ProgressReportingInterval (60 * HZ) + + +/* + Define the maximum number of Partitions allowed for each Logical Drive. +*/ + +#define DAC960_MaxPartitions 8 +#define DAC960_MaxPartitionsBits 3 + + +/* + Define macros to extract the Controller Number, Logical Drive Number, and + Partition Number from a Kernel Device, and to construct a Major Number, Minor + Number, and Kernel Device from the Controller Number, Logical Drive Number, + and Partition Number. There is one Major Number assigned to each Controller. + The associated Minor Number is divided into the Logical Drive Number and + Partition Number. +*/ + +#define DAC960_ControllerNumber(Device) \ + (MAJOR(Device) - DAC960_MAJOR) + +#define DAC960_LogicalDriveNumber(Device) \ + (MINOR(Device) >> DAC960_MaxPartitionsBits) + +#define DAC960_PartitionNumber(Device) \ + (MINOR(Device) & (DAC960_MaxPartitions - 1)) + +#define DAC960_MajorNumber(ControllerNumber) \ + (DAC960_MAJOR + (ControllerNumber)) + +#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \ + (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber)) + +#define DAC960_MinorCount (DAC960_MaxLogicalDrives \ + * DAC960_MaxPartitions) + +#define DAC960_KernelDevice(ControllerNumber, \ + LogicalDriveNumber, \ + PartitionNumber) \ + MKDEV(DAC960_MajorNumber(ControllerNumber), \ + DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber)) + + +/* + Define the DAC960 Controller fixed Block Size and Block Size Bits. +*/ + +#define DAC960_BlockSize 512 +#define DAC960_BlockSizeBits 9 + + +/* + Define the Controller Line, Status Buffer, Rebuild Progress, and + User Message Sizes. +*/ + +#define DAC960_LineBufferSize 100 +#define DAC960_StatusBufferSize 5000 +#define DAC960_RebuildProgressSize 200 +#define DAC960_UserMessageSize 200 + + +/* + Define the types of DAC960 Controllers that are supported. +*/ + +typedef enum +{ + DAC960_V5_Controller = 1, /* DAC1164P */ + DAC960_V4_Controller = 2, /* DAC960PTL/PJ/PG */ + DAC960_V3_Controller = 3 /* DAC960PU/PD/PL */ +} +DAC960_ControllerType_T; + + +/* + Define the Driver Message Levels. +*/ + +typedef enum DAC960_MessageLevel +{ + DAC960_AnnounceLevel = 0, + DAC960_InfoLevel = 1, + DAC960_NoticeLevel = 2, + DAC960_WarningLevel = 3, + DAC960_ErrorLevel = 4, + DAC960_ProgressLevel = 5, + DAC960_CriticalLevel = 6, + DAC960_UserCriticalLevel = 7 +} +DAC960_MessageLevel_T; + +static char + *DAC960_MessageLevelMap[] = + { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, + KERN_ERR, KERN_CRIT, KERN_CRIT, KERN_CRIT }; + + +/* + Define Driver Message macros. +*/ + +#define DAC960_Announce(Format, Arguments...) \ + DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments) + +#define DAC960_Info(Format, Arguments...) \ + DAC960_Message(DAC960_InfoLevel, Format, ##Arguments) + +#define DAC960_Notice(Format, Arguments...) \ + DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments) + +#define DAC960_Warning(Format, Arguments...) \ + DAC960_Message(DAC960_WarningLevel, Format, ##Arguments) + +#define DAC960_Error(Format, Arguments...) \ + DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments) + +#define DAC960_Progress(Format, Arguments...) \ + DAC960_Message(DAC960_ProgressLevel, Format, ##Arguments) + +#define DAC960_Critical(Format, Arguments...) \ + DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments) + +#define DAC960_UserCritical(Format, Arguments...) \ + DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments) + + +/* + Define types for some of the structures that interface with the rest + of the Linux Kernel and I/O Subsystem. +*/ + +typedef struct buffer_head BufferHeader_T; +typedef struct file File_T; +typedef struct file_operations FileOperations_T; +typedef struct gendisk GenericDiskInfo_T; +typedef struct hd_geometry DiskGeometry_T; +typedef struct hd_struct DiskPartition_T; +typedef struct inode Inode_T; +typedef struct inode_operations InodeOperations_T; +typedef kdev_t KernelDevice_T; +typedef struct notifier_block NotifierBlock_T; +typedef struct pci_dev PCI_Device_T; +typedef struct proc_dir_entry PROC_DirectoryEntry_T; +typedef unsigned long ProcessorFlags_T; +typedef struct pt_regs Registers_T; +typedef struct request IO_Request_T; +typedef struct semaphore Semaphore_T; +typedef struct super_block SuperBlock_T; +typedef struct timer_list Timer_T; +typedef struct wait_queue WaitQueue_T; + + +/* + Define the DAC960 Controller Status Mailbox structure. +*/ + +typedef union DAC960_StatusMailbox +{ + unsigned int Word; /* Bytes 0-3 */ + struct { + DAC960_CommandIdentifier_T CommandIdentifier; /* Byte 0 */ + unsigned char :7; /* Byte 1 Bits 0-6 */ + boolean Valid:1; /* Byte 1 Bit 7 */ + DAC960_CommandStatus_T CommandStatus; /* Bytes 2-3 */ + } Fields; +} +DAC960_StatusMailbox_T; + + +/* + Define the DAC960 Driver Command Types. +*/ + +typedef enum +{ + DAC960_ReadCommand = 1, + DAC960_WriteCommand = 2, + DAC960_ReadRetryCommand = 3, + DAC960_WriteRetryCommand = 4, + DAC960_MonitoringCommand = 5, + DAC960_ImmediateCommand = 6, + DAC960_QueuedCommand = 7 +} +DAC960_CommandType_T; + + +/* + Define the DAC960 Driver Command structure. +*/ + +typedef struct DAC960_Command +{ + DAC960_CommandType_T CommandType; + DAC960_CommandMailbox_T CommandMailbox; + DAC960_CommandStatus_T CommandStatus; + struct DAC960_Controller *Controller; + struct DAC960_Command *Next; + Semaphore_T *Semaphore; + unsigned int LogicalDriveNumber; + unsigned int BlockNumber; + unsigned int BlockCount; + unsigned int SegmentCount; + BufferHeader_T *BufferHeader; + DAC960_KernelCommand_T *KernelCommand; + DAC960_ScatterGatherSegment_T + ScatterGatherList[DAC960_MaxScatterGatherSegments]; +} +DAC960_Command_T; + + +/* + Define the DAC960 Driver Controller structure. +*/ + +typedef struct DAC960_Controller +{ + void *BaseAddress; + void *MemoryMappedAddress; + DAC960_ControllerType_T ControllerType; + DAC960_IO_Address_T IO_Address; + DAC960_PCI_Address_T PCI_Address; + unsigned char ControllerNumber; + unsigned char ControllerName[4]; + unsigned char ModelName[12]; + unsigned char FullModelName[18]; + unsigned char FirmwareVersion[14]; + unsigned char Bus; + unsigned char Device; + unsigned char Function; + unsigned char IRQ_Channel; + unsigned char Channels; + unsigned char MemorySize; + unsigned char LogicalDriveCount; + unsigned char GeometryTranslationHeads; + unsigned char GeometryTranslationSectors; + unsigned short ControllerQueueDepth; + unsigned short DriverQueueDepth; + unsigned short MaxBlocksPerCommand; + unsigned short MaxScatterGatherSegments; + unsigned short StripeSize; + unsigned short SegmentSize; + unsigned short NewEventLogSequenceNumber; + unsigned short OldEventLogSequenceNumber; + unsigned short InitialStatusLength; + unsigned short CurrentStatusLength; + unsigned short UserStatusLength; + unsigned short RebuildProgressLength; + unsigned int ControllerUsageCount; + unsigned int EnquiryIndex; + unsigned int LogicalDriveInformationIndex; + unsigned int ErrorTableIndex; + unsigned int DeviceStateIndex; + unsigned int DeviceStateChannel; + unsigned int DeviceStateTargetID; + unsigned long MonitoringTimerCount; + unsigned long SecondaryMonitoringTime; + unsigned long LastProgressReportTime; + boolean DualModeMemoryMailboxInterface; + boolean SAFTE_EnclosureManagementEnabled; + boolean ControllerInitialized; + boolean MonitoringCommandDeferred; + boolean NeedLogicalDriveInformation; + boolean NeedErrorTableInformation; + boolean NeedDeviceStateInformation; + boolean NeedRebuildProgress; + boolean NeedConsistencyCheckProgress; + boolean EphemeralProgressMessage; + Timer_T MonitoringTimer; + GenericDiskInfo_T GenericDiskInfo; + DAC960_Command_T *FreeCommands; + DAC960_CommandMailbox_T *FirstCommandMailbox; + DAC960_CommandMailbox_T *LastCommandMailbox; + DAC960_CommandMailbox_T *NextCommandMailbox; + DAC960_CommandMailbox_T *PreviousCommandMailbox1; + DAC960_CommandMailbox_T *PreviousCommandMailbox2; + DAC960_StatusMailbox_T *FirstStatusMailbox; + DAC960_StatusMailbox_T *LastStatusMailbox; + DAC960_StatusMailbox_T *NextStatusMailbox; + PROC_DirectoryEntry_T ControllerProcEntry; + PROC_DirectoryEntry_T InitialStatusProcEntry; + PROC_DirectoryEntry_T CurrentStatusProcEntry; + PROC_DirectoryEntry_T UserCommandProcEntry; + WaitQueue_T *CommandWaitQueue; + DAC960_Enquiry_T Enquiry[2]; + DAC960_ErrorTable_T ErrorTable[2]; + DAC960_EventLogEntry_T EventLogEntry; + DAC960_RebuildProgress_T RebuildProgress; + DAC960_CommandStatus_T LastRebuildStatus; + DAC960_LogicalDriveInformation_T + LogicalDriveInformation[2][DAC960_MaxLogicalDrives]; + DAC960_LogicalDriveState_T LogicalDriveInitialState[DAC960_MaxLogicalDrives]; + DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets]; + DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth]; + DiskPartition_T DiskPartitions[DAC960_MinorCount]; + int LogicalDriveUsageCount[DAC960_MaxLogicalDrives]; + int PartitionSizes[DAC960_MinorCount]; + int BlockSizes[DAC960_MinorCount]; + int MaxSectorsPerRequest[DAC960_MinorCount]; + int MaxSegmentsPerRequest[DAC960_MinorCount]; + boolean DirectCommandActive[DAC960_MaxChannels][DAC960_MaxTargets]; + char InitialStatusBuffer[DAC960_StatusBufferSize]; + char CurrentStatusBuffer[DAC960_StatusBufferSize]; + char UserStatusBuffer[DAC960_UserMessageSize]; + char RebuildProgressBuffer[DAC960_RebuildProgressSize]; +} +DAC960_Controller_T; + + +/* + DAC960_AcquireControllerLock acquires exclusive access to Controller. +*/ + +static inline +void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLock releases exclusive access to Controller. +*/ + +static inline +void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_AcquireControllerLockRF acquires exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_ReleaseControllerLockRF releases exclusive access to Controller, + but is only called from the request function with the io_request_lock held. +*/ + +static inline +void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ +} + + +/* + DAC960_AcquireControllerLockIH acquires exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_lock_irqsave(&io_request_lock, *ProcessorFlags); +} + + +/* + DAC960_ReleaseControllerLockIH releases exclusive access to Controller, + but is only called from the interrupt handler. +*/ + +static inline +void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, + ProcessorFlags_T *ProcessorFlags) +{ + spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags); +} + + +/* + Define the DAC960 V5 Controller Interface Register Offsets. +*/ + +#define DAC960_V5_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V5_InboundDoorBellRegisterOffset = 0x60, + DAC960_V5_OutboundDoorBellRegisterOffset = 0x61, + DAC960_V5_InterruptMaskRegisterOffset = 0x34, + DAC960_V5_CommandOpcodeRegisterOffset = 0x50, + DAC960_V5_CommandIdentifierRegisterOffset = 0x51, + DAC960_V5_MailboxRegister2Offset = 0x52, + DAC960_V5_MailboxRegister3Offset = 0x53, + DAC960_V5_MailboxRegister4Offset = 0x54, + DAC960_V5_MailboxRegister5Offset = 0x55, + DAC960_V5_MailboxRegister6Offset = 0x56, + DAC960_V5_MailboxRegister7Offset = 0x57, + DAC960_V5_MailboxRegister8Offset = 0x58, + DAC960_V5_MailboxRegister9Offset = 0x59, + DAC960_V5_MailboxRegister10Offset = 0x5A, + DAC960_V5_MailboxRegister11Offset = 0x5B, + DAC960_V5_MailboxRegister12Offset = 0x5C, + DAC960_V5_StatusCommandIdentifierRegOffset = 0x5D, + DAC960_V5_StatusRegisterOffset = 0x5E +} +DAC960_V5_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V5 Inbound Door Bell Register. +*/ + +typedef union DAC960_V5_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned char :3; /* Bits 5-7 */ + } Write; + struct { + boolean HardwareMailboxEmpty:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V5_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Outbound Door Bell Register. +*/ + +typedef union DAC960_V5_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned char :6; /* Bits 2-7 */ + } Read; +} +DAC960_V5_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V5 Interrupt Mask Register. +*/ + +typedef union DAC960_V5_InterruptMaskRegister +{ + unsigned char All; + struct { + unsigned char :2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned char :5; /* Bits 3-7 */ + } Bits; +} +DAC960_V5_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V5 Controller Interface Registers. +*/ + +static inline +void DAC960_V5_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxEmptyP(void *ControllerBaseAddress) +{ + DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxEmpty; +} + +static inline +void DAC960_V5_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V5_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V5_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V5_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V5_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = false; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V5_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.DisableInterrupts = true; + writeb(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V5_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readb(ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V5_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V5_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V5_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V5_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V5_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V5_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V5_StatusRegisterOffset); +} + +static inline +void DAC960_V5_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0x743C485E, + ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + +static inline +void DAC960_V5_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V5_CommandOpcodeRegisterOffset) != 0x743C485E) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V4 Controller Interface Register Offsets. +*/ + +#define DAC960_V4_RegisterWindowSize 0x2000 + +typedef enum +{ + DAC960_V4_InboundDoorBellRegisterOffset = 0x0020, + DAC960_V4_OutboundDoorBellRegisterOffset = 0x002C, + DAC960_V4_InterruptMaskRegisterOffset = 0x0034, + DAC960_V4_CommandOpcodeRegisterOffset = 0x1000, + DAC960_V4_CommandIdentifierRegisterOffset = 0x1001, + DAC960_V4_MailboxRegister2Offset = 0x1002, + DAC960_V4_MailboxRegister3Offset = 0x1003, + DAC960_V4_MailboxRegister4Offset = 0x1004, + DAC960_V4_MailboxRegister5Offset = 0x1005, + DAC960_V4_MailboxRegister6Offset = 0x1006, + DAC960_V4_MailboxRegister7Offset = 0x1007, + DAC960_V4_MailboxRegister8Offset = 0x1008, + DAC960_V4_MailboxRegister9Offset = 0x1009, + DAC960_V4_MailboxRegister10Offset = 0x100A, + DAC960_V4_MailboxRegister11Offset = 0x100B, + DAC960_V4_MailboxRegister12Offset = 0x100C, + DAC960_V4_StatusCommandIdentifierRegOffset = 0x1018, + DAC960_V4_StatusRegisterOffset = 0x101A +} +DAC960_V4_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V4 Inbound Door Bell Register. +*/ + +typedef union DAC960_V4_InboundDoorBellRegister +{ + unsigned int All; + struct { + boolean HardwareMailboxNewCommand:1; /* Bit 0 */ + boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + boolean MemoryMailboxNewCommand:1; /* Bit 4 */ + unsigned int :27; /* Bits 5-31 */ + } Write; + struct { + boolean HardwareMailboxFull:1; /* Bit 0 */ + unsigned int :31; /* Bits 1-31 */ + } Read; +} +DAC960_V4_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Outbound Door Bell Register. +*/ + +typedef union DAC960_V4_OutboundDoorBellRegister +{ + unsigned int All; + struct { + boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */ + boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Write; + struct { + boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */ + boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */ + unsigned int :30; /* Bits 2-31 */ + } Read; +} +DAC960_V4_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V4 Interrupt Mask Register. +*/ + +typedef union DAC960_V4_InterruptMaskRegister +{ + unsigned int All; + struct { + unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */ + boolean DisableInterrupts:1; /* Bit 2 */ + unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */ + unsigned int Reserved0:24; /* Bits 8-31 */ + } Bits; +} +DAC960_V4_InterruptMaskRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V4 Controller Interface Registers. +*/ + +static inline +void DAC960_V4_HardwareMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_MemoryMailboxNewCommand(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true; + writel(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.HardwareMailboxFull; +} + +static inline +void DAC960_V4_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true; + OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true; + writel(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V4_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable; +} + +static inline +boolean DAC960_V4_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable; +} + +static inline +void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = false; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = 0; + InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3; + InterruptMaskRegister.Bits.DisableInterrupts = true; + InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F; + writel(InterruptMaskRegister.All, + ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); +} + +static inline +boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister; + InterruptMaskRegister.All = + readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset); + return !InterruptMaskRegister.Bits.DisableInterrupts; +} + +static inline +void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox, + DAC960_CommandMailbox_T *CommandMailbox) +{ + NextCommandMailbox->Words[1] = CommandMailbox->Words[1]; + NextCommandMailbox->Words[2] = CommandMailbox->Words[2]; + NextCommandMailbox->Words[3] = CommandMailbox->Words[3]; + NextCommandMailbox->Words[0] = CommandMailbox->Words[0]; +} + +static inline +void DAC960_V4_WriteHardwareMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V4_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset); +} + +static inline +void DAC960_V4_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + writel(0xAABBFFFF, + ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset); + writel((unsigned long) Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox, + ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + +static inline +void DAC960_V4_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, + void **MemoryMailboxAddress, + short *NextCommandMailboxIndex, + short *NextStatusMailboxIndex) +{ + void *ControllerBaseAddress = Controller->BaseAddress; + if (readl(ControllerBaseAddress + + DAC960_V4_CommandOpcodeRegisterOffset) != 0xAABBFFFF) + return; + *MemoryMailboxAddress = + (void *) readl(ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset); + *NextCommandMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset); + *NextStatusMailboxIndex = + readw(ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset); +} + + +/* + Define the DAC960 V3 Controller Interface Register Offsets. +*/ + +#define DAC960_V3_RegisterWindowSize 0x80 + +typedef enum +{ + DAC960_V3_CommandOpcodeRegisterOffset = 0x00, + DAC960_V3_CommandIdentifierRegisterOffset = 0x01, + DAC960_V3_MailboxRegister2Offset = 0x02, + DAC960_V3_MailboxRegister3Offset = 0x03, + DAC960_V3_MailboxRegister4Offset = 0x04, + DAC960_V3_MailboxRegister5Offset = 0x05, + DAC960_V3_MailboxRegister6Offset = 0x06, + DAC960_V3_MailboxRegister7Offset = 0x07, + DAC960_V3_MailboxRegister8Offset = 0x08, + DAC960_V3_MailboxRegister9Offset = 0x09, + DAC960_V3_MailboxRegister10Offset = 0x0A, + DAC960_V3_MailboxRegister11Offset = 0x0B, + DAC960_V3_MailboxRegister12Offset = 0x0C, + DAC960_V3_StatusCommandIdentifierRegOffset = 0x0D, + DAC960_V3_StatusRegisterOffset = 0x0E, + DAC960_V3_InboundDoorBellRegisterOffset = 0x40, + DAC960_V3_OutboundDoorBellRegisterOffset = 0x41, + DAC960_V3_InterruptEnableRegisterOffset = 0x43 +} +DAC960_V3_RegisterOffsets_T; + + +/* + Define the structure of the DAC960 V3 Inbound Door Bell Register. +*/ + +typedef union DAC960_V3_InboundDoorBellRegister +{ + unsigned char All; + struct { + boolean NewCommand:1; /* Bit 0 */ + boolean AcknowledgeStatus:1; /* Bit 1 */ + boolean GenerateInterrupt:1; /* Bit 2 */ + boolean ControllerReset:1; /* Bit 3 */ + unsigned char :4; /* Bits 4-7 */ + } Write; + struct { + boolean MailboxFull:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_InboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Outbound Door Bell Register. +*/ + +typedef union DAC960_V3_OutboundDoorBellRegister +{ + unsigned char All; + struct { + boolean AcknowledgeInterrupt:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Write; + struct { + boolean StatusAvailable:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Read; +} +DAC960_V3_OutboundDoorBellRegister_T; + + +/* + Define the structure of the DAC960 V3 Interrupt Enable Register. +*/ + +typedef union DAC960_V3_InterruptEnableRegister +{ + unsigned char All; + struct { + boolean EnableInterrupts:1; /* Bit 0 */ + unsigned char :7; /* Bits 1-7 */ + } Bits; +} +DAC960_V3_InterruptEnableRegister_T; + + +/* + Define inline functions to provide an abstraction for reading and writing the + DAC960 V3 Controller Interface Registers. +*/ + +static inline +void DAC960_V3_NewCommand(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.NewCommand = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.AcknowledgeStatus = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_GenerateInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.GenerateInterrupt = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +void DAC960_V3_ControllerReset(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = 0; + InboundDoorBellRegister.Write.ControllerReset = true; + writeb(InboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress) +{ + DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister; + InboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset); + return InboundDoorBellRegister.Read.MailboxFull; +} + +static inline +void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = 0; + OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true; + writeb(OutboundDoorBellRegister.All, + ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); +} + +static inline +boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress) +{ + DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister; + OutboundDoorBellRegister.All = + readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset); + return OutboundDoorBellRegister.Read.StatusAvailable; +} + +static inline +void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = true; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = 0; + InterruptEnableRegister.Bits.EnableInterrupts = false; + writeb(InterruptEnableRegister.All, + ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); +} + +static inline +boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress) +{ + DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister; + InterruptEnableRegister.All = + readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset); + return InterruptEnableRegister.Bits.EnableInterrupts; +} + +static inline +void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress, + DAC960_CommandMailbox_T *CommandMailbox) +{ + writel(CommandMailbox->Words[0], + ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset); + writel(CommandMailbox->Words[1], + ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset); + writel(CommandMailbox->Words[2], + ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset); + writeb(CommandMailbox->Bytes[12], + ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset); +} + +static inline DAC960_CommandIdentifier_T +DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress) +{ + return readb(ControllerBaseAddress + + DAC960_V3_StatusCommandIdentifierRegOffset); +} + +static inline DAC960_CommandStatus_T +DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress) +{ + return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset); +} + + +/* + Define compatibility macros between Linux 2.0 and Linux 2.1. +*/ + +#if LINUX_VERSION_CODE < 0x20100 + +#define MODULE_PARM(Variable, Type) +#define ioremap_nocache(Offset, Size) vremap(Offset, Size) +#define iounmap(Address) vfree(Address) + +#endif + + +/* + Define prototypes for the forward referenced DAC960 Driver Internal Functions. +*/ + +static void DAC960_FinalizeController(DAC960_Controller_T *); +static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *); +static void DAC960_RequestFunction0(void); +static void DAC960_RequestFunction1(void); +static void DAC960_RequestFunction2(void); +static void DAC960_RequestFunction3(void); +static void DAC960_RequestFunction4(void); +static void DAC960_RequestFunction5(void); +static void DAC960_RequestFunction6(void); +static void DAC960_RequestFunction7(void); +static void DAC960_InterruptHandler(int, void *, Registers_T *); +static void DAC960_QueueMonitoringCommand(DAC960_Command_T *); +static void DAC960_MonitoringTimerFunction(unsigned long); +static int DAC960_Open(Inode_T *, File_T *); +static int DAC960_Release(Inode_T *, File_T *); +static int DAC960_IOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long); +static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *); +static void DAC960_Message(DAC960_MessageLevel_T, char *, + DAC960_Controller_T *, ...); +static void DAC960_CreateProcEntries(void); +static void DAC960_DestroyProcEntries(void); + + +/* + Export the Kernel Mode IOCTL interface. +*/ + +EXPORT_SYMBOL(DAC960_KernelIOCTL); + + +#endif /* DAC960_DriverVersion */ diff -u --recursive --new-file v2.2.10/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.2.10/linux/drivers/block/Makefile Mon Apr 12 16:18:27 1999 +++ linux/drivers/block/Makefile Mon Aug 9 12:04:38 1999 @@ -234,6 +234,22 @@ endif endif +ifeq ($(CONFIG_BLK_CPQ_DA),y) +L_OBJS += cpqarray.o +else + ifeq ($(CONFIG_BLK_CPQ_DA),m) + M_OBJS += cpqarray.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_DAC960),y) +LX_OBJS += DAC960.o +else + ifeq ($(CONFIG_BLK_DEV_DAC960),m) + MX_OBJS += DAC960.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_MD),y) LX_OBJS += md.o diff -u --recursive --new-file v2.2.10/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.2.10/linux/drivers/block/cpqarray.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cpqarray.c Mon Aug 9 12:04:38 1999 @@ -0,0 +1,1791 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) + +#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.5)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,5) +#define MAJOR_NR COMPAQ_SMART2_MAJOR +#include +#include +#include + +#include "cpqarray.h" +#include "ida_cmd.h" +#include "smart1,2.h" +#include "ida_ioctl.h" + +#define READ_AHEAD 128 +#define NR_CMDS 128 /* This could probably go as high as ~400 */ + +#define MAX_CTLR 8 +#define CTLR_SHIFT 8 + +static int nr_ctlr = 0; +static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static int eisa[8] = { 0, 0 ,0 ,0, 0, 0 ,0 ,0 }; + +#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) + +/* board_id = Subsystem Device ID & Vendor ID + * product = Marketing Name for the board + * access = Address of the struct of function pointers + */ +struct board_type products[] = { + { 0x0040110E, "IDA", &smart1_access }, + { 0x0140110E, "IDA-2", &smart1_access }, + { 0x1040110E, "IAES", &smart1_access }, + { 0x2040110E, "SMART", &smart1_access }, + { 0x3040110E, "SMART-2/E", &smart2e_access }, + { 0x40300E11, "SMART-2/P", &smart2_access }, + { 0x40310E11, "SMART-2SL", &smart2_access }, + { 0x40320E11, "Smart Array 3200", &smart2_access }, + { 0x40330E11, "Smart Array 3100ES", &smart2_access }, + { 0x40340E11, "Smart Array 221", &smart2_access }, + { 0x40400E11, "Integrated Array", &smart4_access }, + { 0x40500E11, "Smart Array 4200", &smart4_access }, + { 0x40510E11, "Smart Array 4250ES", &smart4_access }, +}; + +static struct hd_struct * ida; +static int * ida_sizes; +static int * ida_blocksizes; +static int * ida_hardsizes; +static struct gendisk ida_gendisk[MAX_CTLR]; + +struct proc_dir_entry *proc_array = NULL; + +/* Debug... */ +#define DBG(s) do { s } while(0) +/* Debug (general info)... */ +#define DBGINFO(s) do { } while(0) +/* Debug Paranoid... */ +#define DBGP(s) do { } while(0) +/* Debug Extra Paranoid... */ +#define DBGPX(s) do { } while(0) + +int cpqarray_init(void); +static int cpqarray_pci_detect(void); +static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn); +static ulong remap_pci_mem(ulong base, ulong size); +static int cpqarray_eisa_detect(void); +static int pollcomplete(int ctlr); +static void getgeometry(int ctlr); +static void start_fwbk(int ctlr); + +static cmdlist_t * cmd_alloc(ctlr_info_t *h); +static void cmd_free(ctlr_info_t *h, cmdlist_t *c); + +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int blk, + unsigned int blkcnt, + unsigned int log_unit ); + +static int ida_open(struct inode *inode, struct file *filep); +static int ida_release(struct inode *inode, struct file *filep); +static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); +static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io); + +static void do_ida_request(int i); +/* + * This is a hack. This driver eats a major number for each controller, and + * sets blkdev[xxx].request_fn to each one of these so the real request + * function knows what controller its working with. + */ +#define DO_IDA_REQUEST(x) { do_ida_request(x); } + +static void do_ida_request0(void) DO_IDA_REQUEST(0); +static void do_ida_request1(void) DO_IDA_REQUEST(1); +static void do_ida_request2(void) DO_IDA_REQUEST(2); +static void do_ida_request3(void) DO_IDA_REQUEST(3); +static void do_ida_request4(void) DO_IDA_REQUEST(4); +static void do_ida_request5(void) DO_IDA_REQUEST(5); +static void do_ida_request6(void) DO_IDA_REQUEST(6); +static void do_ida_request7(void) DO_IDA_REQUEST(7); + +static void start_io(ctlr_info_t *h); + +static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c); +static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c); +static inline void complete_buffers(struct buffer_head *bh, int ok); +static inline void complete_command(cmdlist_t *cmd, int timeout); + +static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs); +static void ida_timer(unsigned long tdata); +static int frevalidate_logvol(kdev_t dev); +static int revalidate_logvol(kdev_t dev, int maxusage); +static int revalidate_allvol(kdev_t dev); + +static void ida_procinit(int i); +static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); + +static void ida_geninit(struct gendisk *g) +{ + int ctlr = g-ida_gendisk; + int i,j; + drv_info_t *drv; + + for(i=0; idrv[i]; + if (!drv->nr_blks) + continue; + ida[(ctlr<nr_blks; + + for(j=0; j<16; j++) { + ida_blocksizes[(ctlr<blk_size; + } + ida_gendisk[ctlr].nr_real++; + } + +} + +struct file_operations ida_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + ida_ioctl, /* ioctl */ + NULL, /* mmap */ + ida_open, /* open code */ + NULL, + ida_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* Disk change */ + frevalidate_logvol, /* revalidate */ +}; + + +/* + * Get us a file in /proc/array that says something about each controller. + * Create /proc/array if it doesn't exist yet. + */ +static void ida_procinit(int i) +{ + struct proc_dir_entry *pd; + + if (proc_array == NULL) { + proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO, + &proc_root); + if (!proc_array) return; + } + + pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array); + if (!pd) return; + pd->read_proc = ida_proc_get_info; + pd->data = hba[i]; +} + +/* + * Report information about this controller. + */ +static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + off_t pos = 0; + off_t len = 0; + int size, i, ctlr; + ctlr_info_t *h = (ctlr_info_t*)data; + drv_info_t *drv; +#ifdef CPQ_PROC_PRINT_QUEUES + cmdlist_t *c; +#endif + + ctlr = h->ctlr; + size = sprintf(buffer, "%s: Compaq %s Controller\n" + " Board ID: %08lx\n" + " Firmware Revision: %c%c%c%c\n" + " Controller Sig: %08lx\n" + " Memory Address: %08lx\n" + " I/O Port: %04x\n" + " IRQ: %x\n" + " Logical drives: %d\n" + " Physical drives: %d\n\n" + " Current Q depth: %d\n" + " Max Q depth since init: %d\n\n", + h->devname, + h->product_name, + (unsigned long)h->board_id, + h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3], + (unsigned long)h->ctlr_sig, (unsigned long)h->vaddr, + (unsigned int) h->ioaddr, (unsigned int)h->intr, + h->log_drives, h->phys_drives, + h->Qdepth, h->maxQsinceinit); + + pos += size; len += size; + + size = sprintf(buffer+len, "Logical Drive Info:\n"); + pos += size; len += size; + + for(i=0; ilog_drives; i++) { + drv = &h->drv[i]; + size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n", + ctlr, i, drv->blk_size, drv->nr_blks); + pos += size; len += size; + } + +#ifdef CPQ_PROC_PRINT_QUEUES + size = sprintf(buffer+len, "\nCurrent Queues:\n"); + pos += size; len += size; + + c = h->reqQ; + size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size; + if (c) c=c->next; + while(c && c != h->reqQ) { + size = sprintf(buffer+len, "->%p", c); + pos += size; len += size; + c=c->next; + } + + c = h->cmpQ; + size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size; + if (c) c=c->next; + while(c && c != h->cmpQ) { + size = sprintf(buffer+len, "->%p", c); + pos += size; len += size; + c=c->next; + } + + size = sprintf(buffer+len, "\n"); pos += size; len += size; +#endif + size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n", + h->nr_allocs, h->nr_frees); + pos += size; len += size; + + *eof = 1; + *start = buffer+offset; + len -= offset; + if (len>length) + len = length; + return len; +} + +#ifdef MODULE + +MODULE_PARM(eisa, "1-8i"); +EXPORT_NO_SYMBOLS; + +/* This is a bit of a hack... */ +int init_module(void) +{ + int i, j; + if (cpqarray_init() == 0) /* all the block dev numbers already used */ + return -EIO; /* or no controllers were found */ + + for(i=0; iaccess.set_intr_mask(hba[i], 0); + free_irq(hba[i]->intr, hba[i]); + iounmap((void*)hba[i]->vaddr); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + del_timer(&hba[i]->timer); + remove_proc_entry(hba[i]->devname, proc_array); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->cmd_pool_bits); + + if (gendisk_head == &ida_gendisk[i]) { + gendisk_head = ida_gendisk[i].next; + } else { + for(g=gendisk_head; g; g=g->next) { + if (g->next == &ida_gendisk[i]) { + g->next = ida_gendisk[i].next; + break; + } + } + } + } + remove_proc_entry("array", &proc_root); + kfree(ida); + kfree(ida_sizes); + kfree(ida_hardsizes); + kfree(ida_blocksizes); + + +} +#endif /* MODULE */ + +/* + * This is it. Find all the controllers and register them. I really hate + * stealing all these major device numbers. + * returns the number of block devices registered. + */ +int cpqarray_init(void) +{ + void (*request_fns[MAX_CTLR])(void) = { + do_ida_request0, do_ida_request1, + do_ida_request2, do_ida_request3, + do_ida_request4, do_ida_request5, + do_ida_request6, do_ida_request7, + }; + int i; + int num_cntlrs_reg = 0; + + /* detect controllers */ + cpqarray_pci_detect(); + cpqarray_eisa_detect(); + + if (nr_ctlr == 0) + return(num_cntlrs_reg); + + printk(DRIVER_NAME "\n"); + printk("Found %d controller(s)\n", nr_ctlr); + + /* allocate space for disk structs */ + ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL); + + if(ida==NULL) + { + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_sizes==NULL) + { + kfree(ida); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + + ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_blocksizes==NULL) + { + kfree(ida); + kfree(ida_sizes); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + + ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL); + if(ida_hardsizes==NULL) + { + kfree(ida); + kfree(ida_sizes); + kfree(ida_blocksizes); + printk( KERN_ERR "cpqarray: out of memory"); + return(num_cntlrs_reg); + } + + memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16); + memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16); + memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR); + + /* + * register block devices + * Find disks and fill in structs + * Get an interrupt, set the Q depth and get into /proc + */ + for(i=0; i< nr_ctlr; i++) { + /* If this successful it should insure that we are the only */ + /* instance of the driver */ + if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) { + printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n", + MAJOR_NR+i); + continue; + } + + hba[i]->access.set_intr_mask(hba[i], 0); + if (request_irq(hba[i]->intr, do_ida_intr, + SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { + + printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", + hba[i]->intr, hba[i]->devname); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + continue; + } + num_cntlrs_reg++; + hba[i]->cmd_pool = (cmdlist_t *)kmalloc( + NR_CMDS * sizeof(cmdlist_t), GFP_KERNEL); + hba[i]->cmd_pool_bits = (__u32*)kmalloc( + ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); + + if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) + { + nr_ctlr = i; + if(hba[i]->cmd_pool_bits) + kfree(hba[i]->cmd_pool_bits); + if(hba[i]->cmd_pool) + kfree(hba[i]->cmd_pool); + free_irq(hba[i]->intr, hba[i]); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + num_cntlrs_reg--; + printk( KERN_ERR "cpqarray: out of memory"); + + /* If num_cntlrs_reg == 0, no controllers worked. + * init_module will fail, so clean up global + * memory that clean_module would do. + */ + if (num_cntlrs_reg == 0) + { + kfree(ida); + kfree(ida_sizes); + kfree(ida_hardsizes); + kfree(ida_blocksizes); + } + return(num_cntlrs_reg); + + } + memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t)); + memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); + printk(KERN_INFO "cpqarray: Finding drives on %s", + hba[i]->devname); + getgeometry(i); + start_fwbk(i); + + hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY); + + ida_procinit(i); + ida_gendisk[i].major = MAJOR_NR + i; + ida_gendisk[i].major_name = "ida"; + ida_gendisk[i].minor_shift = NWD_SHIFT; + ida_gendisk[i].max_p = 16; + ida_gendisk[i].max_nr = 16; + ida_gendisk[i].init = ida_geninit; + ida_gendisk[i].part = ida + (i*256); + ida_gendisk[i].sizes = ida_sizes + (i*256); + /* ida_gendisk[i].nr_real is handled by getgeometry */ + + blk_dev[MAJOR_NR+i].request_fn = request_fns[i]; + blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256); + hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256); + read_ahead[MAJOR_NR+i] = READ_AHEAD; + + /* Get on the disk list */ + ida_gendisk[i].next = gendisk_head; + gendisk_head = &ida_gendisk[i]; + + init_timer(&hba[i]->timer); + hba[i]->timer.expires = jiffies + IDA_TIMER; + hba[i]->timer.data = (unsigned long)hba[i]; + hba[i]->timer.function = ida_timer; + add_timer(&hba[i]->timer); + + } + /* done ! */ + return(num_cntlrs_reg); +} + +/* + * Find the controller and initialize it + * Cannot use the class code to search, because older array controllers use + * 0x018000 and new ones use 0x010400. So I might as well search for each + * each device IDs, being there are only going to be three of them. + */ +static int cpqarray_pci_detect(void) +{ + int index; + unchar bus=0, dev_fn=0; + +#define IDA_BOARD_TYPES 3 + static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, + PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ }; + static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX, + PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P }; + int brdtype; + + /* search for all PCI board types that could be for this driver */ + for(brdtype=0; brdtypedevname, "ida%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + nr_ctlr++; + + } + } + + return nr_ctlr; +} +/* + * Find the IO address of the controller, its IRQ and so forth. Fill + * in some basic stuff into the ctlr_info_t structure. + */ +static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +{ + ushort vendor_id, device_id, command; + unchar cache_line_size, latency_timer; + unchar irq, revision; + uint addr[6]; + __u32 board_id; + struct pci_dev *pdev; + + int i; + + pdev = pci_find_slot(bus, device_fn); + vendor_id = pdev->vendor; + device_id = pdev->device; + irq = pdev->irq; + + for(i=0; i<6; i++) + addr[i] = pdev->base_address[i]; + + (void) pcibios_read_config_word(bus, device_fn, + PCI_COMMAND,&command); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CLASS_REVISION,&revision); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CACHE_LINE_SIZE, &cache_line_size); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_LATENCY_TIMER, &latency_timer); + + (void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id); + +DBGINFO( + printk("vendor_id = %x\n", vendor_id); + printk("device_id = %x\n", device_id); + printk("command = %x\n", command); + for(i=0; i<6; i++) + printk("addr[%d] = %x\n", i, addr[i]); + printk("revision = %x\n", revision); + printk("irq = %x\n", irq); + printk("cache_line_size = %x\n", cache_line_size); + printk("latency_timer = %x\n", latency_timer); + printk("board_id = %x\n", board_id); +); + + c->intr = irq; + c->ioaddr = addr[0] & ~0x1; + + /* + * Memory base addr is first addr with the first bit _not_ set + */ + for(i=0; i<6; i++) + if (!(addr[i] & 0x1)) { + c->paddr = addr[i]; + break; + } + c->vaddr = remap_pci_mem(c->paddr, 128); + c->board_id = board_id; + + for(i=0; iproduct_name = products[i].product_name; + c->access = *(products[i].access); + break; + } + } + if (i == NR_PRODUCTS) { + printk(KERN_WARNING "cpqarray: Sorry, I don't know how" + " to access the SMART Array controller %08lx\n", + (unsigned long)board_id); + return -1; + } + + return 0; +} + +/* + * Map (physical) PCI mem into (virtual) kernel space + */ +static ulong remap_pci_mem(ulong base, ulong size) +{ + ulong page_base = ((ulong) base) & PAGE_MASK; + ulong page_offs = ((ulong) base) - page_base; + ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + + return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); +} + +/* + * Copy the contents of the ints[] array passed to us by init. + */ +void cpqarray_setup(char *str, int *ints) +{ + int i; + for(i=0; iioaddr = eisa[i]; + + /* + * Read the config register to find our interrupt + */ + intr = inb(eisa[i]+0xCC0) >> 4; + if (intr & 1) intr = 11; + else if (intr & 2) intr = 10; + else if (intr & 4) intr = 14; + else if (intr & 8) intr = 15; + + hba[nr_ctlr]->intr = intr; + sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr); + hba[nr_ctlr]->product_name = products[j].product_name; + hba[nr_ctlr]->access = *(products[j].access); + hba[nr_ctlr]->ctlr = nr_ctlr; + hba[nr_ctlr]->board_id = board_id; + +DBGINFO( + printk("i = %d, j = %d\n", i, j); + printk("irq = %x\n", intr); + printk("product name = %s\n", products[j].product_name); + printk("board_id = %x\n", board_id); +); + + nr_ctlr++; + i++; + } + + return nr_ctlr; +} + + +/* + * Open. Make sure the device is really there. + */ +static int ida_open(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + + DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); + if (ctlr > MAX_CTLR || hba[ctlr] == NULL) + return -ENXIO; + + if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) + + MINOR(inode->i_rdev)] == 0) + return -ENXIO; + + /* + * Root is allowed to open raw volume zero even if its not configured + * so array config can still work. I don't think I really like this, + * but I'm already using way to many device nodes to claim another one + * for "raw controller". + */ + if (suser() + && ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 + && MINOR(inode->i_rdev) != 0) + return -ENXIO; + + hba[ctlr]->drv[dsk].usage_count++; + hba[ctlr]->usage_count++; + MOD_INC_USE_COUNT; + return 0; +} + +/* + * Close. Sync first. + */ +static int ida_release(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + + DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) ); + fsync_dev(inode->i_rdev); + + hba[ctlr]->drv[dsk].usage_count--; + hba[ctlr]->usage_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} + +/* + * Get a request and submit it to the controller. + * This routine needs to grab all the requests it possibly can from the + * req Q and submit them. Interrupts are off (and need to be off) when you + * are in here (either via the dummy do_ida_request functions or by being + * called from the interrupt handler + */ +static void do_ida_request(int ctlr) +{ + ctlr_info_t *h = hba[ctlr]; + cmdlist_t *c; + int seg, sect; + char *lastdataend; + struct buffer_head *bh; + struct request *creq; + + creq = blk_dev[MAJOR_NR+ctlr].current_request; + if (creq == NULL || creq->rq_status == RQ_INACTIVE) + { + start_io(h); + return; + } + + if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || + ctlr > nr_ctlr || h == NULL) { + printk("cpqarray: doreq cmd for %d, %x at %p\n", + ctlr, creq->rq_dev, creq); + complete_buffers(creq->bh, 0); + start_io(h); + return; + } + + if ((c = cmd_alloc(h)) == NULL) + { + start_io(h); + return; + } + + bh = creq->bh; + + c->ctlr = ctlr; + c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + c->req.hdr.blk = ida[(ctlr<rq_dev)].start_sect + creq->sector; + c->bh = bh; +DBGPX( + if (bh == NULL) + panic("bh == NULL?"); + + printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors); +); + seg = 0; lastdataend = NULL; + sect = 0; + while(bh) { + sect += bh->b_size/512; +DBGPX( + if (bh->b_size % 512) { + printk("Oh damn. %d+%d, size = %d\n", creq->sector, sect, bh->b_size); + panic("b_size %% 512 != 0"); + } +); + if (bh->b_data == lastdataend) { + c->req.sg[seg-1].size += bh->b_size; + lastdataend += bh->b_size; + } else { + c->req.sg[seg].size = bh->b_size; + c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data); + lastdataend = bh->b_data + bh->b_size; + if (++seg == SG_MAX) + break; + } + bh = bh->b_reqnext; + } +DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); + c->req.hdr.sg_cnt = seg; + c->req.hdr.blk_cnt = sect; + + creq->sector += sect; + creq->nr_sectors -= sect; + + /* Ready the next request: + * Fix up creq if we still have more buffers in the buffer chain, or + * mark this request as done and ready the next one. + */ + if (creq->nr_sectors) { +DBGPX( + if (bh==NULL) { + printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n", + creq->sector, creq->nr_sectors, sect, seg); + panic("mother..."); + } +); + creq->bh = bh->b_reqnext; + bh->b_reqnext = NULL; +DBGPX( printk("More to do on same request %p\n", creq); ); + } else { +DBGPX( printk("Done with %p, queueing %p\n", creq, creq->next); ); + creq->rq_status = RQ_INACTIVE; + blk_dev[MAJOR_NR+ctlr].current_request = creq->next; + wake_up(&wait_for_request); + } + + c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE; + c->type = CMD_RWREQ; + + /* Put the request on the tail of the request queue */ + addQ(&h->reqQ, c); + h->Qdepth++; + if (h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; + + start_io(h); +} + +/* + * start_io submits everything on a controller's request queue + * and moves it to the completion queue. + * + * Interrupts had better be off if you're in here + */ +static void start_io(ctlr_info_t *h) +{ + cmdlist_t *c; + + while((c = h->reqQ) != NULL) { + /* Can't do anything if we're busy */ + if (h->access.fifo_full(h) == 0) + return; + + /* Get the first entry from the request Q */ + removeQ(&h->reqQ, c); + h->Qdepth--; + + /* Tell the controller to do our bidding */ + h->access.submit_command(h, c); + + /* Get onto the completion Q */ + addQ(&h->cmpQ, c); + } +} + +static inline void complete_buffers(struct buffer_head *bh, int ok) +{ + struct buffer_head *xbh; + while(bh) { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + + bh->b_end_io(bh, ok); + + bh = xbh; + } +} +/* + * Mark all buffers that cmd was responsible for + */ +static inline void complete_command(cmdlist_t *cmd, int timeout) +{ + char buf[80]; + int ok=1; + + if (cmd->req.hdr.rcode & RCODE_NONFATAL && + (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) { + sprintf(buf, "Non Fatal error on ida/c%dd%d\n", + cmd->ctlr, cmd->hdr.unit); + console_print(buf); + hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN; + } + if (cmd->req.hdr.rcode & RCODE_FATAL) { + sprintf(buf, "Fatal error on ida/c%dd%d\n", + cmd->ctlr, cmd->hdr.unit); + console_print(buf); + ok = 0; + } + if (cmd->req.hdr.rcode & RCODE_INVREQ) { + sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n", + cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd, + cmd->req.hdr.blk, cmd->req.hdr.blk_cnt, + cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode); + console_print(buf); + ok = 0; + } + if (timeout) ok = 0; + complete_buffers(cmd->bh, ok); +} + +/* + * The controller will interrupt us upon completion of commands. + * Find the command on the completion queue, remove it, tell the OS and + * try to queue up more IO + */ +static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + ctlr_info_t *h = dev_id; + cmdlist_t *c; + unsigned long istat; + unsigned long flags; + __u32 a,a1; + + + istat = h->access.intr_pending(h); + /* Is this interrupt for us? */ + if (istat == 0) + return; + + /* + * If there are completed commands in the completion queue, + * we had better do something about it. + */ + spin_lock_irqsave(&io_request_lock, flags); + if (istat & FIFO_NOT_EMPTY) { + while((a = h->access.command_completed(h))) { + a1 = a; a &= ~3; + if ((c = h->cmpQ) == NULL) + { + printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1); + continue; + } + while(c->busaddr != a) { + c = c->next; + if (c == h->cmpQ) + break; + } + /* + * If we've found the command, take it off the + * completion Q and free it + */ + if (c->busaddr == a) { + removeQ(&h->cmpQ, c); + if (c->type == CMD_RWREQ) { + complete_command(c, 0); + cmd_free(h, c); + } else if (c->type == CMD_IOCTL_PEND) { + c->type = CMD_IOCTL_DONE; + } + continue; + } + } + } + + /* + * See if we can queue up some more IO + */ + do_ida_request(h->ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +/* + * This timer was for timing out requests that haven't happened after + * IDA_TIMEOUT. That wasn't such a good idea. This timer is used to + * reset a flags structure so we don't flood the user with + * "Non-Fatal error" messages. + */ +static void ida_timer(unsigned long tdata) +{ + ctlr_info_t *h = (ctlr_info_t*)tdata; + + h->timer.expires = jiffies + IDA_TIMER; + add_timer(&h->timer); + h->misc_tflags = 0; +} + +/* + * ida_ioctl does some miscellaneous stuff like reporting drive geometry, + * setting readahead and submitting commands from userspace to the controller. + */ +static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int error; + int diskinfo[4]; + struct hd_geometry *geo = (struct hd_geometry *)arg; + ida_ioctl_t *io = (ida_ioctl_t*)arg; + ida_ioctl_t my_io; + + switch(cmd) { + case HDIO_GETGEO: + if (hba[ctlr]->drv[dsk].cylinders) { + diskinfo[0] = hba[ctlr]->drv[dsk].heads; + diskinfo[1] = hba[ctlr]->drv[dsk].sectors; + diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; + } else { + diskinfo[0] = 0xff; + diskinfo[1] = 0x3f; + diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f); + } + put_user(diskinfo[0], &geo->heads); + put_user(diskinfo[1], &geo->sectors); + put_user(diskinfo[2], &geo->cylinders); + put_user(ida[(ctlr<i_rdev)].start_sect, &geo->start); + return 0; + case IDAGETDRVINFO: + return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t)); + case BLKGETSIZE: + if (!arg) return -EINVAL; + put_user(ida[(ctlr<i_rdev)].nr_sects, (long*)arg); + return 0; + case BLKRASET: + if (!suser()) return -EACCES; + if (!(inode->i_rdev)) return -EINVAL; + if (arg>0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return 0; + case BLKRAGET: + if (!arg) return -EINVAL; + put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg); + return 0; + case BLKRRPART: + return revalidate_logvol(inode->i_rdev, 1); + case IDAPASSTHRU: + if (!suser()) return -EPERM; + error = copy_from_user(&my_io, io, sizeof(my_io)); + if (error) return error; + error = ida_ctlr_ioctl(ctlr, dsk, &my_io); + if (error) return error; + error = copy_to_user(io, &my_io, sizeof(my_io)); + return error; + case IDAGETCTLRSIG: + if (!arg) return -EINVAL; + put_user(hba[ctlr]->ctlr_sig, (int*)arg); + return 0; + case IDAREVALIDATEVOLS: + return revalidate_allvol(inode->i_rdev); + case IDADRIVERVERSION: + if (!arg) return -EINVAL; + put_user(DRIVER_VERSION, (unsigned long*)arg); + return 0; + + RO_IOCTLS(inode->i_rdev, arg); + + default: + return -EBADRQC; + } + +} +/* + * ida_ctlr_ioctl is for passing commands to the controller from userspace. + * The command block (io) has already been copied to kernel space for us, + * however, any elements in the sglist need to be copied to kernel space + * or copied back to userspace. + * + * Only root may perform a controller passthru command, however I'm not doing + * any serious sanity checking on the arguments. Doing an IDA_WRITE_MEDIA and + * putting a 64M buffer in the sglist is probably a *bad* idea. + */ +static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io) +{ + ctlr_info_t *h = hba[ctlr]; + cmdlist_t *c; + void *p = NULL; + unsigned long flags; + int error; + + if ((c = cmd_alloc(NULL)) == NULL) + return -ENOMEM; + c->ctlr = ctlr; + c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + c->req.hdr.cmd = io->cmd; + c->req.hdr.blk = io->blk; + c->req.hdr.blk_cnt = io->blk_cnt; + c->type = CMD_IOCTL_PEND; + + /* Pre submit processing */ + switch(io->cmd) { + case PASSTHRU_A: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } + copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); + c->req.bp = virt_to_bus(&(io->c)); + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + case IDA_READ: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } + + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + case IDA_WRITE: + case IDA_WRITE_MEDIA: + case DIAG_PASS_THRU: + p = kmalloc(io->sg[0].size, GFP_KERNEL); + if (!p) + { + error = -ENOMEM; + cmd_free(NULL, c); + return(error); + } + copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size); + c->req.sg[0].size = io->sg[0].size; + c->req.sg[0].addr = virt_to_bus(p); + c->req.hdr.sg_cnt = 1; + break; + default: + c->req.sg[0].size = sizeof(io->c); + c->req.sg[0].addr = virt_to_bus(&io->c); + c->req.hdr.sg_cnt = 1; + } + + /* Put the request on the tail of the request queue */ + spin_lock_irqsave(&io_request_lock, flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wait for completion */ + while(c->type != CMD_IOCTL_DONE) + schedule(); + + /* Post submit processing */ + switch(io->cmd) { + case PASSTHRU_A: + case IDA_READ: + case DIAG_PASS_THRU: + copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size); + /* fall through and free p */ + case IDA_WRITE: + case IDA_WRITE_MEDIA: + kfree(p); + break; + default: + /* Nothing to do */ + } + + io->rcode = c->req.hdr.rcode; + cmd_free(NULL, c); + return(0); +} + +/* + * Commands are pre-allocated in a large block. Here we use a simple bitmap + * scheme to suballocte them to the driver. Operations that are not time + * critical (and can wait for kmalloc and possibly sleep) can pass in NULL + * as the first argument to get a new command. + */ +static cmdlist_t * cmd_alloc(ctlr_info_t *h) +{ + cmdlist_t * c; + int i; + + if (h == NULL) { + c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL); + if(c==NULL) + return NULL; + } else { + do { + i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS); + if (i == NR_CMDS) + return NULL; + } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0); + c = h->cmd_pool + i; + h->nr_allocs++; + } + + memset(c, 0, sizeof(cmdlist_t)); + c->busaddr = virt_to_bus(c); + return c; +} + +static void cmd_free(ctlr_info_t *h, cmdlist_t *c) +{ + int i; + + if (h == NULL) { + kfree(c); + } else { + i = c - h->cmd_pool; + clear_bit(i%32, h->cmd_pool_bits+(i/32)); + h->nr_frees++; + } +} + +/*********************************************************************** + name: sendcmd + Send a command to an IDA using the memory mapped FIFO interface + and wait for it to complete. + This routine should only be called at init time. +***********************************************************************/ +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int blk, + unsigned int blkcnt, + unsigned int log_unit ) +{ + cmdlist_t *c; + int complete; + unsigned long temp; + unsigned long i; + ctlr_info_t *info_p = hba[ctlr]; + + c = cmd_alloc(info_p); + c->ctlr = ctlr; + c->hdr.unit = log_unit; + c->hdr.prio = 0; + c->hdr.size = sizeof(rblk_t) >> 2; + c->size += sizeof(rblk_t); + + /* The request information. */ + c->req.hdr.next = 0; + c->req.hdr.rcode = 0; + c->req.bp = 0; + c->req.hdr.sg_cnt = 1; + c->req.hdr.reserved = 0; + + if (size == 0) + c->req.sg[0].size = 512; + else + c->req.sg[0].size = size; + + c->req.hdr.blk = blk; + c->req.hdr.blk_cnt = blkcnt; + c->req.hdr.cmd = (unsigned char) cmd; + c->req.sg[0].addr = (__u32) virt_to_bus(buff); + /* + * Disable interrupt + */ + info_p->access.set_intr_mask(info_p, 0); + /* Make sure there is room in the command FIFO */ + /* Actually it should be completely empty at this time. */ + for (i = 200000; i > 0; i--) { + temp = info_p->access.fifo_full(info_p); + if (temp != 0) { + break; + } + udelay(10); +DBG( + printk(KERN_WARNING "cpqarray ida%d: idaSendPciCmd FIFO full," + " waiting!\n", ctlr); +); + } + /* + * Send the cmd + */ + info_p->access.submit_command(info_p, c); + complete = pollcomplete(ctlr); + if (complete != 1) { + if (complete != c->busaddr) { + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd " + "Invalid command list address returned! (%08lx)\n", + ctlr, (unsigned long)complete); + cmd_free(info_p, c); + return (IO_ERROR); + } + } else { + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd Timeout out, " + "No command list address returned!\n", + ctlr); + cmd_free(info_p, c); + return (IO_ERROR); + } + + if (c->req.hdr.rcode & 0x00FE) { + if (!(c->req.hdr.rcode & BIG_PROBLEM)) { + printk( KERN_WARNING + "cpqarray ida%d: idaSendPciCmd, error: " + "Controller failed at init time " + "cmd: 0x%x, return code = 0x%x\n", + ctlr, c->req.hdr.cmd, c->req.hdr.rcode); + + cmd_free(info_p, c); + return (IO_ERROR); + } + } + cmd_free(info_p, c); + return (IO_OK); +} + +static int frevalidate_logvol(kdev_t dev) +{ + return revalidate_logvol(dev, 0); +} + +/* + * revalidate_allvol is for online array config utilities. After a + * utility reconfigures the drives in the array, it can use this function + * (through an ioctl) to make the driver zap any previous disk structs for + * that controller and get new ones. + * + * Right now I'm using the getgeometry() function to do this, but this + * function should probably be finer grained and allow you to revalidate one + * particualar logical volume (instead of all of them on a particular + * controller). + */ +static int revalidate_allvol(kdev_t dev) +{ + int ctlr, i; + unsigned long flags; + + ctlr = MAJOR(dev) - MAJOR_NR; + if (MINOR(dev) != 0) + return -ENXIO; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->usage_count > 1) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cpqarray: Device busy for volume" + " revalidation (usage=%d)\n", hba[ctlr]->usage_count); + return -EBUSY; + } + spin_unlock_irqrestore(&io_request_lock, flags); + hba[ctlr]->usage_count++; + + /* + * Set the partition and block size structures for all volumes + * on this controller to zero. We will reread all of this data + */ + memset(ida+(ctlr*256), 0, sizeof(struct hd_struct)*NWD*16); + memset(ida_sizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(ida_hardsizes+(ctlr*256), 0, sizeof(int)*NWD*16); + memset(hba[ctlr]->drv, 0, sizeof(drv_info_t)*NWD); + ida_gendisk[ctlr].nr_real = 0; + + /* + * Tell the array controller not to give us any interupts while + * we check the new geometry. Then turn interrupts back on when + * we're done. + */ + hba[ctlr]->access.set_intr_mask(hba[ctlr], 0); + getgeometry(ctlr); + hba[ctlr]->access.set_intr_mask(hba[ctlr], FIFO_NOT_EMPTY); + + ida_geninit(&ida_gendisk[ctlr]); + for(i=0; iusage_count--; + return 0; +} + +/* Borrowed and adapted from sd.c */ +static int revalidate_logvol(kdev_t dev, int maxusage) +{ + int ctlr, target; + struct gendisk *gdev; + unsigned long flags; + int max_p; + int start; + int i; + + target = DEVICE_NR(dev); + ctlr = MAJOR(dev) - MAJOR_NR; + gdev = &ida_gendisk[ctlr]; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->drv[target].usage_count > maxusage) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cpqarray: Device busy for " + "revalidation (usage=%d)\n", + hba[ctlr]->drv[target].usage_count); + return -EBUSY; + } + + hba[ctlr]->drv[target].usage_count++; + spin_unlock_irqrestore(&io_request_lock, flags); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + + for(i=max_p; i>=0; i--) { + int minor = start+i; + kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); + struct super_block *sb = get_super(devi); + sync_dev(devi); + if (sb) invalidate_inodes(sb); + invalidate_buffers(devi); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + + /* reset the blocksize so we can read the partition table */ + blksize_size[MAJOR_NR+ctlr][minor] = 1024; + } + + gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blks; + resetup_one_dev(gdev, target); + hba[ctlr]->drv[target].usage_count--; + return 0; +} + + +/******************************************************************** + name: pollcomplete + Wait polling for a command to complete. + The memory mapped FIFO is polled for the completion. + Used only at init time, interrupts disabled. + ********************************************************************/ +static int pollcomplete(int ctlr) +{ + int done; + int i; + + /* Wait (up to 2 seconds) for a command to complete */ + + for (i = 200000; i > 0; i--) { + done = hba[ctlr]->access.command_completed(hba[ctlr]); + if (done == 0) { + udelay(10); /* a short fixed delay */ + } else + return (done); + } + /* Invalid address to tell caller we ran out of time */ + return 1; +} +/***************************************************************** + start_fwbk + Starts controller firmwares background processing. + Currently only the Integrated Raid controller needs this done. + If the PCI mem address registers are written to after this, + data corruption may occur +*****************************************************************/ +static void start_fwbk(int ctlr) +{ + id_ctlr_t *id_ctlr_buf; + int ret_code; + + if( hba[ctlr]->board_id != 0x40400E11) + /* Not a Integrated Raid, so there is nothing for us to do */ + return; + printk(KERN_DEBUG "cpqarray: Starting firmware's background" + " processing\n"); + /* Command does not return anything, but idasend command needs a + buffer */ + id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + if(id_ctlr_buf==NULL) + { + printk(KERN_WARNING "cpqarray: Out of memory. " + "Unable to start background processing.\n"); + return; + } + ret_code = sendcmd(RESUME_BACKGROUND_ACTIVITY, ctlr, + id_ctlr_buf, 0, 0, 0, 0); + if(ret_code != IO_OK) + printk(KERN_WARNING "cpqarray: Unable to start" + " background processing\n"); + kfree(id_ctlr_buf); +} +/***************************************************************** + getgeometry + Get ida logical volume geometry from the controller + This is a large bit of code which once existed in two flavors, + It is used only at init time. +*****************************************************************/ +static void getgeometry(int ctlr) +{ + id_log_drv_t *id_ldrive; + id_ctlr_t *id_ctlr_buf; + sense_log_drv_stat_t *id_lstatus_buf; + config_t *sense_config_buf; + unsigned int log_unit, log_index; + int ret_code, size; + drv_info_t *drv; + ctlr_info_t *info_p = hba[ctlr]; + + info_p->log_drv_map = 0; + + id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL); + if(id_ldrive == NULL) + { + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL); + if(id_ctlr_buf == NULL) + { + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + + id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL); + if(id_lstatus_buf == NULL) + { + kfree(id_ctlr_buf); + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + + sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL); + if(sense_config_buf == NULL) + { + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + printk( KERN_ERR "cpqarray: out of memory.\n"); + return; + } + + memset(id_ldrive, 0, sizeof(id_log_drv_t)); + memset(id_ctlr_buf, 0, sizeof(id_ctlr_t)); + memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t)); + memset(sense_config_buf, 0, sizeof(config_t)); + + info_p->phys_drives = 0; + info_p->log_drv_map = 0; + info_p->drv_assign_map = 0; + info_p->drv_spare_map = 0; + info_p->mp_failed_drv_map = 0; /* only initialized here */ + /* Get controllers info for this logical drive */ + ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0); + if (ret_code == IO_ERROR) { + /* + * If can't get controller info, set the logical drive map to 0, + * so the idastubopen will fail on all logical drives + * on the controller. + */ + /* Free all the buffers and return */ + printk(KERN_ERR "cpqarray: error sending ID controller\n"); + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; + } + + info_p->log_drives = id_ctlr_buf->nr_drvs;; + *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev); + info_p->ctlr_sig = id_ctlr_buf->cfg_sig; + + printk(" (%s)\n", info_p->product_name); + /* + * Initialize logical drive map to zero + */ + log_index = 0; + /* + * Get drive geometry for all logical drives + */ + if (id_ctlr_buf->nr_drvs > 16) + printk(KERN_WARNING "cpqarray ida%d: This driver supports " + "16 logical drives per controller.\n. " + " Additional drives will not be " + "detected\n", ctlr); + + for (log_unit = 0; + (log_index < id_ctlr_buf->nr_drvs) + && (log_unit < NWD); + log_unit++) { + + size = sizeof(sense_log_drv_stat_t); + + /* + Send "Identify logical drive status" cmd + */ + ret_code = sendcmd(SENSE_LOG_DRV_STAT, + ctlr, id_lstatus_buf, size, 0, 0, log_unit); + if (ret_code == IO_ERROR) { + /* + If can't get logical drive status, set + the logical drive map to 0, so the + idastubopen will fail for all logical drives + on the controller. + */ + info_p->log_drv_map = 0; + printk( KERN_WARNING + "cpqarray ida%d: idaGetGeometry - Controller" + " failed to report status of logical drive %d\n" + "Access to this controller has been disabled\n", + ctlr, log_unit); + /* Free all the buffers and return */ + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; + } + /* + Make sure the logical drive is configured + */ + if (id_lstatus_buf->status != LOG_NOT_CONF) { + ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive, + sizeof(id_log_drv_t), 0, 0, log_unit); + /* + If error, the bit for this + logical drive won't be set and + idastubopen will return error. + */ + if (ret_code != IO_ERROR) { + drv = &info_p->drv[log_unit]; + drv->blk_size = id_ldrive->blk_size; + drv->nr_blks = id_ldrive->nr_blks; + drv->cylinders = id_ldrive->drv.cyl; + drv->heads = id_ldrive->drv.heads; + drv->sectors = id_ldrive->drv.sect_per_track; + info_p->log_drv_map |= (1 << log_unit); + + printk(KERN_INFO "cpqarray ida/c%dd%d: blksz=%d nr_blks=%d\n", + ctlr, log_unit, drv->blk_size, drv->nr_blks); + ret_code = sendcmd(SENSE_CONFIG, + ctlr, sense_config_buf, + sizeof(config_t), 0, 0, log_unit); + if (ret_code == IO_ERROR) { + info_p->log_drv_map = 0; + /* Free all the buffers and return */ + printk(KERN_ERR "cpqarray: error sending sense config\n"); + kfree(sense_config_buf); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + kfree(id_ldrive); + return; + + } + info_p->phys_drives = + sense_config_buf->ctlr_phys_drv; + info_p->drv_assign_map + |= sense_config_buf->drv_asgn_map; + info_p->drv_assign_map + |= sense_config_buf->spare_asgn_map; + info_p->drv_spare_map + |= sense_config_buf->spare_asgn_map; + } /* end of if no error on id_ldrive */ + log_index = log_index + 1; + } /* end of if logical drive configured */ + } /* end of for log_unit */ + kfree(sense_config_buf); + kfree(id_ldrive); + kfree(id_lstatus_buf); + kfree(id_ctlr_buf); + return; +} diff -u --recursive --new-file v2.2.10/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.2.10/linux/drivers/block/cpqarray.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cpqarray.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,120 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef CPQARRAY_H +#define CPQARRAY_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#endif + +#include "ida_cmd.h" + +#define IO_OK 0 +#define IO_ERROR 1 +#define NWD 16 +#define NWD_SHIFT 4 + +#define IDA_TIMER (5*HZ) +#define IDA_TIMEOUT (10*HZ) + +#define MISC_NONFATAL_WARN 0x01 + +typedef struct { + unsigned blk_size; + unsigned nr_blks; + unsigned cylinders; + unsigned heads; + unsigned sectors; + int usage_count; +} drv_info_t; + +#ifdef __KERNEL__ + +struct ctlr_info; +typedef struct ctlr_info ctlr_info_t; + +struct access_method { + void (*submit_command)(ctlr_info_t *h, cmdlist_t *c); + void (*set_intr_mask)(ctlr_info_t *h, unsigned long val); + unsigned long (*fifo_full)(ctlr_info_t *h); + unsigned long (*intr_pending)(ctlr_info_t *h); + unsigned long (*command_completed)(ctlr_info_t *h); +}; + +struct board_type { + __u32 board_id; + char *product_name; + struct access_method *access; +}; + +struct ctlr_info { + int ctlr; + char devname[8]; + __u32 log_drv_map; + __u32 drv_assign_map; + __u32 drv_spare_map; + __u32 mp_failed_drv_map; + + char firm_rev[4]; + int ctlr_sig; + + int log_drives; + int phys_drives; + + __u32 board_id; + char *product_name; + + __u32 vaddr; + __u32 paddr; + __u32 ioaddr; + int intr; + int usage_count; + drv_info_t drv[NWD]; + struct proc_dir_entry *proc; + + struct access_method access; + + cmdlist_t *reqQ; + cmdlist_t *cmpQ; + cmdlist_t *cmd_pool; + __u32 *cmd_pool_bits; + + unsigned int Qdepth; + unsigned int maxQsinceinit; + + unsigned int nr_requests; + unsigned int nr_allocs; + unsigned int nr_frees; + struct timer_list timer; + unsigned int misc_tflags; +}; +#endif + +#endif /* CPQARRAY_H */ diff -u --recursive --new-file v2.2.10/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.2.10/linux/drivers/block/genhd.c Mon Apr 12 16:18:27 1999 +++ linux/drivers/block/genhd.c Mon Aug 9 12:04:38 1999 @@ -30,6 +30,7 @@ #include #include +#include /* * Many architectures don't like unaligned accesses, which is @@ -58,6 +59,9 @@ extern int chr_dev_init(void); extern int blk_dev_init(void); +#ifdef CONFIG_BLK_DEV_DAC960 +extern void DAC960_Initialize(void); +#endif extern int scsi_dev_init(void); extern int net_dev_init(void); @@ -65,6 +69,20 @@ extern void note_bootable_part(kdev_t dev, int part); #endif +static char *raid_name (struct gendisk *hd, int minor, int major_base, + char *buf) +{ + int ctlr = hd->major - major_base; + int disk = minor >> hd->minor_shift; + int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) + sprintf(buf, "%s/c%dd%d", hd->major_name, ctlr, disk); + else + sprintf(buf, "%s/c%dd%dp%d", hd->major_name, ctlr, disk, + part); + return buf; +} + /* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk @@ -81,6 +99,8 @@ * IDE devices use multiple major numbers, but the drives * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. * This requires special handling here. + * + * MD devices are named md0, md1, ... md15, fix it up here. */ switch (hd->major) { case IDE5_MAJOR: @@ -96,6 +116,8 @@ case IDE0_MAJOR: maj = "hd"; break; + case MD_MAJOR: + unit -= 'a'-'0'; } part = minor & ((1 << hd->minor_shift) - 1); if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { @@ -108,6 +130,13 @@ return buf; } } + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= + COMPAQ_SMART2_MAJOR+7) { + return raid_name (hd, minor, COMPAQ_SMART2_MAJOR, buf); + } + if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) { + return raid_name (hd, minor, DAC960_MAJOR, buf); + } if (part) sprintf(buf, "%s%c%d", maj, unit, part); else @@ -115,11 +144,16 @@ return buf; } -static void add_partition (struct gendisk *hd, int minor, int start, int size) +static void add_partition (struct gendisk *hd, int minor, + int start, int size, int type) { - char buf[8]; - hd->part[minor].start_sect = start; - hd->part[minor].nr_sects = size; + char buf[MAX_DISKNAME_LEN]; + struct hd_struct *p = hd->part+minor; + + p->start_sect = start; + p->nr_sects = size; + p->type = type; + printk(" %s", disk_name(hd, minor, buf)); } @@ -140,49 +174,49 @@ static unsigned int get_ptable_blocksize(kdev_t dev) { - int ret = 1024; + int ret = 1024; - /* - * See whether the low-level driver has given us a minumum blocksize. - * If so, check to see whether it is larger than the default of 1024. - */ - if (!blksize_size[MAJOR(dev)]) - { - return ret; - } + /* + * See whether the low-level driver has given us a minumum blocksize. + * If so, check to see whether it is larger than the default of 1024. + */ + if (!blksize_size[MAJOR(dev)]) + return ret; - /* - * Check for certain special power of two sizes that we allow. - * With anything larger than 1024, we must force the blocksize up to - * the natural blocksize for the device so that we don't have to try - * and read partial sectors. Anything smaller should be just fine. - */ + /* + * Check for certain special power of two sizes that we allow. + * With anything larger than 1024, we must force the blocksize up to + * the natural blocksize for the device so that we don't have to try + * and read partial sectors. Anything smaller should be just fine. + */ - switch( blksize_size[MAJOR(dev)][MINOR(dev)] ) - { - case 2048: - ret = 2048; - break; - case 4096: - ret = 4096; - break; - case 8192: - ret = 8192; - break; - case 1024: - case 512: - case 256: - case 0: - /* - * These are all OK. - */ - break; - default: - panic("Strange blocksize for partition table\n"); - } + switch( blksize_size[MAJOR(dev)][MINOR(dev)] ) { + case 2048: + ret = 2048; + break; + + case 4096: + ret = 4096; + break; + + case 8192: + ret = 8192; + break; + + case 1024: + case 512: + case 256: + case 0: + /* + * These are all OK. + */ + break; - return ret; + default: + panic("Strange blocksize for partition table\n"); + } + return ret; } #ifdef CONFIG_MSDOS_PARTITION @@ -255,7 +289,8 @@ first_sector + first_size)) continue; - add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); + add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size, ptype(SYS_IND(p))); current_minor++; if ((current_minor & mask) == 0) goto done; @@ -319,7 +354,8 @@ * one but add_partition starts relative to sector * zero of the disk. Therefore, must add the offset * of the current partition */ - add_partition(hd, current_minor, s->s_start+offset, s->s_size); + add_partition(hd, current_minor, + s->s_start+offset, s->s_size, 0); current_minor++; } brelse(bh); @@ -365,7 +401,7 @@ } /* if the bsd partition is not currently known to linux, we end * up here */ - add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size); + add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size, 0); current_minor++; } /* @@ -432,7 +468,7 @@ break; if (p->s_label != UNIXWARE_FS_UNUSED) { - add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); + add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p), 0); current_minor++; } p++; @@ -552,7 +588,8 @@ for (i=1 ; i<=4 ; minor++,i++,p++) { if (!NR_SECTS(p)) continue; - add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size); + add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size, + ptype(SYS_IND(p))); if (is_extended_partition(p)) { printk(" <"); /* @@ -619,7 +656,8 @@ break; if (!(START_SECT(p) && NR_SECTS(p))) continue; - add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); + add_partition(hd, current_minor, START_SECT(p), + NR_SECTS(p), 0); } } printk("\n"); @@ -677,12 +715,10 @@ label = (struct disklabel *) (bh->b_data+64); partition = label->d_partitions; if (label->d_magic != DISKLABELMAGIC) { - printk("magic: %08x\n", label->d_magic); brelse(bh); return 0; } if (label->d_magic2 != DISKLABELMAGIC) { - printk("magic2: %08x\n", label->d_magic2); brelse(bh); return 0; } @@ -692,7 +728,7 @@ if (partition->p_size) add_partition(hd, current_minor, first_sector+partition->p_offset, - partition->p_size); + partition->p_size, 0); current_minor++; } printk("\n"); @@ -711,7 +747,14 @@ struct buffer_head *bh; struct sun_disklabel { unsigned char info[128]; /* Informative text string */ - unsigned char spare[292]; /* Boot information etc. */ + unsigned char spare0[14]; + struct sun_disklabelinfo { + unsigned char spare1; + unsigned char id; + unsigned char spare2; + unsigned char flags; + } infos[8]; + unsigned char spare1[246]; /* Boot information etc. */ unsigned short rspeed; /* Disk rotational speed */ unsigned short pcylcount; /* Physical cylinder count */ unsigned short sparecyl; /* extra sects per cylinder */ @@ -765,7 +808,8 @@ st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc; num_sectors = be32_to_cpu(p->num_sectors); if (num_sectors) - add_partition(hd, current_minor, st_sector, num_sectors); + add_partition(hd, current_minor, st_sector, + num_sectors, ptype(label->infos[i].id)); current_minor++; } printk("\n"); @@ -776,14 +820,11 @@ #endif /* CONFIG_SUN_PARTITION */ #ifdef CONFIG_SGI_PARTITION -#include static int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) { - int i, csum; - unsigned int *ui; - unsigned int start, blocks, cs; - int magic; + int i, csum, magic; + unsigned int *ui, start, blocks, cs; struct buffer_head *bh; struct sgi_disklabel { int magic_mushroom; /* Big fat spliff... */ @@ -841,7 +882,7 @@ start = be32_to_cpu(p->first_block); if(!blocks) continue; - add_partition(hd, current_minor, start, blocks); + add_partition(hd, current_minor, start, blocks, 0); current_minor++; } printk("\n"); @@ -852,7 +893,6 @@ #endif #ifdef CONFIG_AMIGA_PARTITION -#include #include static __inline__ u32 @@ -923,27 +963,30 @@ blk = htonl(pb->pb_Next); if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block( (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { - + /* Tell Kernel about it */ if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 - htonl(pb->pb_Environment[9])) * htonl(pb->pb_Environment[3]) * htonl(pb->pb_Environment[5]))) { + brelse(bh); continue; } start_sect = htonl(pb->pb_Environment[9]) * htonl(pb->pb_Environment[3]) * htonl(pb->pb_Environment[5]); - add_partition(hd,current_minor,start_sect,nr_sects); + add_partition(hd,current_minor, + start_sect,nr_sects,0); current_minor++; res = 1; } brelse(bh); } printk("\n"); - break; } + else + brelse(bh); } rdb_done: @@ -1056,7 +1099,7 @@ blocks_in_map = be32_to_cpu(part->map_count); add_partition(hd, current_minor, fsec + be32_to_cpu(part->start_block) * (secsize/512), - be32_to_cpu(part->block_count) * (secsize/512)); + be32_to_cpu(part->block_count) * (secsize/512), 0); #ifdef CONFIG_PPC /* @@ -1147,7 +1190,7 @@ } add_partition(hd, minor, partsect + xrs->part[0].st, - xrs->part[0].siz); + xrs->part[0].siz, 0); if (!(xrs->part[1].flg & 1)) { /* end of linked partition list */ @@ -1173,7 +1216,7 @@ else { /* we don't care about other id's */ - add_partition (hd, minor, pi->st, pi->siz); + add_partition (hd, minor, pi->st, pi->siz, 0); } } } @@ -1200,7 +1243,7 @@ memcmp (pi->id, "RAW", 3) == 0) ) { part_fmt = 2; - add_partition (hd, minor, pi->st, pi->siz); + add_partition (hd, minor, pi->st, pi->siz, 0); } } printk(" >"); @@ -1215,11 +1258,59 @@ } #endif /* CONFIG_ATARI_PARTITION */ +#ifdef CONFIG_ULTRIX_PARTITION + +static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) +{ + int i, minor = current_minor; + struct buffer_head *bh; + struct ultrix_disklabel { + long pt_magic; /* magic no. indicating part. info exits */ + int pt_valid; /* set by driver if pt is current */ + struct pt_info { + int pi_nblocks; /* no. of sectors */ + unsigned long pi_blkoff; /* block offset for start */ + } pt_part[8]; + } *label; + +#define PT_MAGIC 0x032957 /* Partition magic number */ +#define PT_VALID 1 /* Indicates if struct is valid */ + +#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \ + /get_ptable_blocksize(dev))) + + bh = bread (dev, SBLOCK, get_ptable_blocksize(dev)); + if (!bh) { + printk (" unable to read block 0x%lx\n", SBLOCK); + return -1; + } + + label = (struct ultrix_disklabel *)(bh->b_data + + get_ptable_blocksize(dev) + - sizeof(struct ultrix_disklabel)); + + if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { + for (i=0; i<8; i++, minor++) + if (label->pt_part[i].pi_nblocks) + add_partition(hd, minor, + label->pt_part[i].pi_blkoff, + label->pt_part[i].pi_nblocks); + brelse(bh); + printk ("\n"); + return 1; + } else { + brelse(bh); + return 0; + } +} + +#endif /* CONFIG_ULTRIX_PARTITION */ + static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; unsigned long first_sector; - char buf[8]; + char buf[MAX_DISKNAME_LEN]; if (first_time) printk("Partition check:\n"); @@ -1264,6 +1355,10 @@ if(sgi_partition(hd, dev, first_sector)) return; #endif +#ifdef CONFIG_ULTRIX_PARTITION + if(ultrix_partition(hd, dev, first_sector)) + return; +#endif printk(" unknown partition table\n"); } @@ -1323,6 +1418,7 @@ __initfunc(void device_setup(void)) { extern void console_map_init(void); + extern void cpqarray_init(void); #ifdef CONFIG_PARPORT extern int parport_init(void); #endif @@ -1340,6 +1436,9 @@ chr_dev_init(); blk_dev_init(); sti(); +#ifdef CONFIG_BLK_DEV_DAC960 + DAC960_Initialize(); +#endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); @@ -1347,6 +1446,9 @@ #ifdef CONFIG_SCSI scsi_dev_init(); #endif +#ifdef CONFIG_BLK_CPQ_DA + cpqarray_init(); +#endif #ifdef CONFIG_INET net_dev_init(); #endif @@ -1373,7 +1475,7 @@ int get_partition_list(char * page) { struct gendisk *p; - char buf[32]; + char buf[MAX_DISKNAME_LEN]; int n, len; len = sprintf(page, "major minor #blocks name\n\n"); diff -u --recursive --new-file v2.2.10/linux/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h --- v2.2.10/linux/drivers/block/ida_cmd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/ida_cmd.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,347 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef ARRAYCMD_H +#define ARRAYCMD_H + +#include +#if 0 +#include +#endif + +/* for the Smart Array 42XX cards */ +#define S42XX_REQUEST_PORT_OFFSET 0x40 +#define S42XX_REPLY_INTR_MASK_OFFSET 0x34 +#define S42XX_REPLY_PORT_OFFSET 0x44 +#define S42XX_INTR_STATUS 0x30 + +#define S42XX_INTR_OFF 0x08 +#define S42XX_INTR_PENDING 0x08 + +#define COMMAND_FIFO 0x04 +#define COMMAND_COMPLETE_FIFO 0x08 +#define INTR_MASK 0x0C +#define INTR_STATUS 0x10 +#define INTR_PENDING 0x14 + +#define FIFO_NOT_EMPTY 0x01 +#define FIFO_NOT_FULL 0x02 + +#define BIG_PROBLEM 0x40 +#define LOG_NOT_CONF 2 + +#pragma pack(1) +typedef struct { + __u32 size; + __u32 addr; +} sg_t; + +#define RCODE_NONFATAL 0x02 +#define RCODE_FATAL 0x04 +#define RCODE_INVREQ 0x10 +typedef struct { + __u16 next; + __u8 cmd; + __u8 rcode; + __u32 blk; + __u16 blk_cnt; + __u8 sg_cnt; + __u8 reserved; +} rhdr_t; + +#define SG_MAX 32 +typedef struct { + rhdr_t hdr; + sg_t sg[SG_MAX]; + __u32 bp; +} rblk_t; + +typedef struct { + __u8 unit; + __u8 prio; + __u16 size; +} chdr_t; + +#define CMD_RWREQ 0x00 +#define CMD_IOCTL_PEND 0x01 +#define CMD_IOCTL_DONE 0x02 + +typedef struct cmdlist { + chdr_t hdr; + rblk_t req; + __u32 size; + int retry_cnt; + __u32 busaddr; + int ctlr; + struct cmdlist *prev; + struct cmdlist *next; + struct buffer_head *bh; + int type; +} cmdlist_t; + +#define ID_CTLR 0x11 +typedef struct { + __u8 nr_drvs; + __u32 cfg_sig; + __u8 firm_rev[4]; + __u8 rom_rev[4]; + __u8 hw_rev; + __u32 bb_rev; + __u32 drv_present_map; + __u32 ext_drv_map; + __u32 board_id; + __u8 cfg_error; + __u32 non_disk_bits; + __u8 bad_ram_addr; + __u8 cpu_rev; + __u8 pdpi_rev; + __u8 epic_rev; + __u8 wcxc_rev; + __u8 marketing_rev; + __u8 ctlr_flags; + __u8 host_flags; + __u8 expand_dis; + __u8 scsi_chips; + __u32 max_req_blocks; + __u32 ctlr_clock; + __u8 drvs_per_bus; + __u16 big_drv_present_map[8]; + __u16 big_ext_drv_map[8]; + __u16 big_non_disk_map[8]; + __u16 task_flags; + __u8 icl_bus; + __u8 red_modes; + __u8 cur_red_mode; + __u8 red_ctlr_stat; + __u8 red_fail_reason; + __u8 reserved[403]; +} id_ctlr_t; + +typedef struct { + __u16 cyl; + __u8 heads; + __u8 xsig; + __u8 psectors; + __u16 wpre; + __u8 maxecc; + __u8 drv_ctrl; + __u16 pcyls; + __u8 pheads; + __u16 landz; + __u8 sect_per_track; + __u8 cksum; +} drv_param_t; + +#define ID_LOG_DRV 0x10 +typedef struct { + __u16 blk_size; + __u32 nr_blks; + drv_param_t drv; + __u8 fault_tol; + __u8 reserved; + __u8 bios_disable; +} id_log_drv_t; + +#define ID_LOG_DRV_EXT 0x18 +typedef struct { + __u32 log_drv_id; + __u8 log_drv_label[64]; + __u8 reserved[418]; +} id_log_drv_ext_t; + +#define SENSE_LOG_DRV_STAT 0x12 +typedef struct { + __u8 status; + __u32 fail_map; + __u16 read_err[32]; + __u16 write_err[32]; + __u8 drv_err_data[256]; + __u8 drq_timeout[32]; + __u32 blks_to_recover; + __u8 drv_recovering; + __u16 remap_cnt[32]; + __u32 replace_drv_map; + __u32 act_spare_map; + __u8 spare_stat; + __u8 spare_repl_map[32]; + __u32 repl_ok_map; + __u8 media_exch; + __u8 cache_fail; + __u8 expn_fail; + __u8 unit_flags; + __u16 big_fail_map[8]; + __u16 big_remap_map[8]; + __u16 big_repl_map[8]; + __u16 big_act_spare_map[8]; + __u8 big_spar_repl_map[128]; + __u16 big_repl_ok_map[8]; + __u8 big_drv_rebuild; + __u8 reserved[36]; +} sense_log_drv_stat_t; + +#define START_RECOVER 0x13 + +#define ID_PHYS_DRV 0x15 +typedef struct { + __u8 scsi_bus; + __u8 scsi_id; + __u16 blk_size; + __u32 nr_blks; + __u32 rsvd_blks; + __u8 drv_model[40]; + __u8 drv_sn[40]; + __u8 drv_fw[8]; + __u8 scsi_iq_bits; + __u8 compaq_drv_stmp; + __u8 last_fail; + __u8 phys_drv_flags; + __u8 phys_drv_flags1; + __u8 scsi_lun; + __u8 phys_drv_flags2; + __u8 reserved; + __u32 spi_speed_rules; + __u8 phys_connector[2]; + __u8 phys_box_on_bus; + __u8 phys_bay_in_box; +} id_phys_drv_t; + +#define BLINK_DRV_LEDS 0x16 +typedef struct { + __u32 blink_duration; + __u32 reserved; + __u8 blink[256]; + __u8 reserved1[248]; +} blink_drv_leds_t; + +#define SENSE_BLINK_LEDS 0x17 +typedef struct { + __u32 blink_duration; + __u32 btime_elap; + __u8 blink[256]; + __u8 reserved1[248]; +} sense_blink_leds_t; + +#define IDA_READ 0x20 +#define IDA_WRITE 0x30 +#define IDA_WRITE_MEDIA 0x31 +#define RESET_TO_DIAG 0x40 +#define DIAG_PASS_THRU 0x41 + +#define SENSE_CONFIG 0x50 +#define SET_CONFIG 0x51 +typedef struct { + __u32 cfg_sig; + __u16 compat_port; + __u8 data_dist_mode; + __u8 surf_an_ctrl; + __u16 ctlr_phys_drv; + __u16 log_unit_phys_drv; + __u16 fault_tol_mode; + __u8 phys_drv_param[16]; + drv_param_t drv; + __u32 drv_asgn_map; + __u16 dist_factor; + __u32 spare_asgn_map; + __u8 reserved[6]; + __u16 os; + __u8 ctlr_order; + __u8 extra_info; + __u32 data_offs; + __u8 parity_backedout_write_drvs; + __u8 parity_dist_mode; + __u8 parity_shift_fact; + __u8 bios_disable_flag; + __u32 blks_on_vol; + __u32 blks_per_drv; + __u8 scratch[16]; + __u16 big_drv_map[8]; + __u16 big_spare_map[8]; + __u8 ss_source_vol; + __u8 mix_drv_cap_range; + struct { + __u16 big_drv_map[8]; + __u32 blks_per_drv; + __u16 fault_tol_mode; + __u16 dist_factor; + } MDC_range[4]; + __u8 reserved1[248]; +} config_t; + +#define BYPASS_VOL_STATE 0x52 +#define SS_CREATE_VOL 0x53 +#define CHANGE_CONFIG 0x54 +#define SENSE_ORIG_CONF 0x55 +#define REORDER_LOG_DRV 0x56 +typedef struct { + __u8 old_units[32]; +} reorder_log_drv_t; + +#define LABEL_LOG_DRV 0x57 +typedef struct { + __u8 log_drv_label[64]; +} label_log_drv_t; + +#define SS_TO_VOL 0x58 + +#define SET_SURF_DELAY 0x60 +typedef struct { + __u16 delay; + __u8 reserved[510]; +} surf_delay_t; + +#define SET_OVERHEAT_DELAY 0x61 +typedef struct { + __u16 delay; +} overhead_delay_t; + +#define SET_MP_DELAY +typedef struct { + __u16 delay; + __u8 reserved[510]; +} mp_delay_t; + +#define PASSTHRU_A 0x91 +typedef struct { + __u8 target; + __u8 bus; + __u8 lun; + __u32 timeout; + __u32 flags; + __u8 status; + __u8 error; + __u8 cdb_len; + __u8 sense_error; + __u8 sense_key; + __u32 sense_info; + __u8 sense_code; + __u8 sense_qual; + __u8 residual; + __u8 reserved[4]; + __u8 cdb[12]; +} scsi_param_t; + +#define RESUME_BACKGROUND_ACTIVITY 0x99 +#pragma pack() + +#endif /* ARRAYCMD_H */ diff -u --recursive --new-file v2.2.10/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h --- v2.2.10/linux/drivers/block/ida_ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/ida_ioctl.h Mon Aug 9 12:04:38 1999 @@ -0,0 +1,83 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ +#ifndef IDA_IOCTL_H +#define IDA_IOCTL_H + +#include "ida_cmd.h" +#include "cpqarray.h" + +#define IDAGETDRVINFO 0x27272828 +#define IDAPASSTHRU 0x28282929 +#define IDAGETCTLRSIG 0x29293030 +#define IDAREVALIDATEVOLS 0x30303131 +#define IDADRIVERVERSION 0x31313232 + +/* + * Normally, the ioctl determines the logical unit for this command by + * the major,minor number of the fd passed to ioctl. If you need to send + * a command to a different/nonexistant unit (such as during config), you + * can override the normal behavior by setting the unit valid bit. (Normally, + * it should be zero) The controller the command is sent to is still + * determined by the major number of the open device. + */ + +#define UNITVALID 0x80 +typedef struct { + __u8 cmd; + __u8 rcode; + __u8 unit; + __u32 blk; + __u16 blk_cnt; + +/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */ + struct { + void *addr; + size_t size; + } sg[SG_MAX]; + int sg_cnt; + + union ctlr_cmds { + drv_info_t drv; + unsigned char buf[512]; + + id_ctlr_t id_ctlr; + drv_param_t drv_param; + id_log_drv_t id_log_drv; + id_log_drv_ext_t id_log_drv_ext; + sense_log_drv_stat_t sense_log_drv_stat; + id_phys_drv_t id_phys_drv; + blink_drv_leds_t blink_drv_leds; + sense_blink_leds_t sense_blink_leds; + config_t config; + reorder_log_drv_t reorder_log_drv; + label_log_drv_t label_log_drv; + surf_delay_t surf_delay; + overhead_delay_t overhead_delay; + mp_delay_t mp_delay; + scsi_param_t scsi_param; + } c; +} ida_ioctl_t; + +#endif /* IDA_IOCTL_H */ diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.2.10/linux/drivers/block/ide-cd.c Mon Apr 12 16:18:26 1999 +++ linux/drivers/block/ide-cd.c Mon Aug 9 12:04:38 1999 @@ -2121,20 +2121,23 @@ msf.cdmsf_frame0); /* Make sure the TOC is up to date. */ - stat = cdrom_read_toc (drive, NULL); - if (stat) return stat; + if (cmd != CDROMREADRAW) { + stat = cdrom_read_toc (drive, NULL); + if (stat) + return stat; - toc = info->toc; + toc = info->toc; - if (lba < 0 || lba >= toc->capacity) - return -EINVAL; + if (lba < 0 || lba >= toc->capacity) + return -EINVAL; + } buf = (char *) kmalloc (blocksize, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize, - NULL); + stat = cdrom_read_block (drive, format, lba, 1, buf, + blocksize, NULL); if (stat == 0) { if (cmd == CDROMREADMODE2) { diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.2.10/linux/drivers/block/ide-floppy.c Wed Dec 23 07:54:22 1998 +++ linux/drivers/block/ide-floppy.c Mon Aug 9 12:04:38 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.8 Dec 7, 1997 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * - * Copyright (C) 1996, 1997 Gadi Oxman + * Copyright (C) 1996 - 1999 Gadi Oxman */ /* @@ -26,9 +26,12 @@ * Issue START command only if TEST UNIT READY fails. * Add work-around for IOMEGA ZIP revision 21.D. * Remove idefloppy_get_capabilities(). + * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of + * bytes requested on each interrupt to be zero. + * Thanks to for pointing this out. */ -#define IDEFLOPPY_VERSION "0.8" +#define IDEFLOPPY_VERSION "0.9" #include #include @@ -1001,7 +1004,7 @@ pc->retries++; pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ + bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { @@ -1524,9 +1527,19 @@ floppy->pc = floppy->pc_stack; if (gcw.drq_type == 1) set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags); - if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 && - ((strcmp(drive->id->fw_rev, "21.D") == 0) || - (strcmp(drive->id->fw_rev, "23.D") == 0))) { + /* + * We used to check revisions here. At this point however + * I'm giving up. Just assume they are all broken, its easier. + * + * The actual reason for the workarounds was likely + * a driver bug after all rather than a firmware bug, + * and the workaround below used to hide it. It should + * be fixed as of version 1.9, but to be on the safe side + * we'll leave the limitation below for the 2.2.x tree. + */ + + if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) + { for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; } diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.2.10/linux/drivers/block/ide-pmac.c Wed Mar 10 21:48:46 1999 +++ linux/drivers/block/ide-pmac.c Mon Aug 9 12:04:57 1999 @@ -61,30 +61,39 @@ void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) { - int i, r; + int i, ix; *p = 0; if (base == 0) return; + + for (ix = 0; ix < MAX_HWIFS; ++ix) + if (base == pmac_ide_regbase[ix]) + break; + + if (ix >= MAX_HWIFS) { + /* Probably a PCI interface... */ + for (i = 0; i < 8; ++i) + *p++ = base + i; + /* XXX is this right? */ + *p = 0; + if (irq != 0) + *irq = 0; + return; + } + /* we check only for -EINVAL meaning that we have found a matching bay but with the wrong device type */ - r = check_media_bay_by_base(base, MB_CD); - if (r == -EINVAL) + i = check_media_bay_by_base(base, MB_CD); + if (i == -EINVAL) return; for (i = 0; i < 8; ++i) *p++ = base + i * 0x10; *p = base + 0x160; - if (irq != NULL) { - *irq = 0; - for (i = 0; i < MAX_HWIFS; ++i) { - if (base == pmac_ide_regbase[i]) { - *irq = pmac_ide_irq[i]; - break; - } - } - } + if (irq != NULL) + *irq = pmac_ide_irq[ix]; } void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) @@ -96,10 +105,10 @@ pio = ide_get_best_pio_mode(drive, pio, 4, &d); switch (pio) { case 4: - out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025); + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025); break; default: - out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526); + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526); break; } } @@ -142,14 +151,36 @@ *pp = removables; for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { + struct device_node *tp; + + /* + * If this node is not under a mac-io or dbdma node, + * leave it to the generic PCI driver. + */ + for (tp = np->parent; tp != 0; tp = tp->parent) + if (tp->type && (strcmp(tp->type, "mac-io") == 0 + || strcmp(tp->type, "dbdma") == 0)) + break; + if (tp == 0) + continue; + if (np->n_addrs == 0) { printk(KERN_WARNING "ide: no address for device %s\n", np->full_name); continue; } - - base = (unsigned long) ioremap(np->addrs[0].address, 0x200); - + + /* + * If this slot is taken (e.g. by ide-pci.c) try the next one. + */ + while (i < MAX_HWIFS + && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0) + ++i; + if (i >= MAX_HWIFS) + break; + + base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE; + /* XXX This is bogus. Should be fixed in the registry by checking the kind of host interrupt controller, a bit like gatwick fixes in irq.c diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.2.10/linux/drivers/block/ide-tape.c Fri Jan 8 10:04:58 1999 +++ linux/drivers/block/ide-tape.c Mon Aug 9 12:04:39 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-tape.c Version 1.14 Dec 30, 1998 + * linux/drivers/block/ide-tape.c Version 1.15 Jul 4, 1999 * - * Copyright (C) 1995 - 1998 Gadi Oxman + * Copyright (C) 1995 - 1999 Gadi Oxman * * This driver was constructed as a student project in the software laboratory * of the faculty of electrical engineering in the Technion - Israel's @@ -214,6 +214,9 @@ * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives. * Replace cli()/sti() with hwgroup spinlocks. + * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup + * spinlock with private per-tape spinlock. + * Fix use of freed memory. * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -693,6 +696,7 @@ int excess_bh_size; /* Wasted space in each stage */ unsigned int flags; /* Status/Action flags */ + spinlock_t spinlock; /* protects the ide-tape queue */ } idetape_tape_t; /* @@ -1439,7 +1443,7 @@ #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_add_stage_tail\n"); #endif /* IDETAPE_DEBUG_LOG */ - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); stage->next=NULL; if (tape->last_stage != NULL) tape->last_stage->next=stage; @@ -1450,7 +1454,7 @@ tape->next_stage=tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } /* @@ -1552,7 +1556,9 @@ ide_drive_t *drive = hwgroup->drive; struct request *rq = hwgroup->rq; idetape_tape_t *tape = drive->driver_data; + unsigned long flags; int error; + int remove_stage = 0; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_end_request\n"); @@ -1567,6 +1573,7 @@ if (error) tape->failed_pc = NULL; + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_data_request == rq) { /* The request was a pipelined data transfer request */ tape->active_stage = NULL; tape->active_data_request = NULL; @@ -1577,7 +1584,7 @@ if (error == IDETAPE_ERROR_EOD) idetape_abort_pipeline (drive); } - idetape_remove_stage_head (drive); + remove_stage = 1; } if (tape->next_stage != NULL) { idetape_active_next_stage (drive); @@ -1595,6 +1602,9 @@ idetape_increase_max_pipeline_stages (drive); } ide_end_drive_cmd (drive, 0, 0); + if (remove_stage) + idetape_remove_stage_head (drive); + spin_unlock_irqrestore(&tape->spinlock, flags); } /* @@ -2335,6 +2345,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) { struct semaphore sem = MUTEX_LOCKED; + idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) { @@ -2343,9 +2354,9 @@ } #endif /* IDETAPE_DEBUG_BUGS */ rq->sem = &sem; - spin_unlock(&HWGROUP(drive)->spinlock); + spin_unlock(&tape->spinlock); down(&sem); - spin_lock_irq(&HWGROUP(drive)->spinlock); + spin_lock_irq(&tape->spinlock); } /* @@ -2419,10 +2430,10 @@ */ return (idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh)); } - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); rq_ptr = &tape->first_stage->rq; bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); @@ -2471,12 +2482,12 @@ * Pay special attention to possible race conditions. */ while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) { - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (idetape_pipeline_active (tape)) { idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } else { - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); idetape_insert_pipeline_into_queue (drive); if (idetape_pipeline_active (tape)) continue; @@ -2533,11 +2544,11 @@ if (tape->first_stage == NULL) return; - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); tape->next_stage = NULL; if (idetape_pipeline_active (tape)) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); while (tape->first_stage != NULL) idetape_remove_stage_head (drive); @@ -2557,7 +2568,7 @@ if (!idetape_pipeline_active (tape)) idetape_insert_pipeline_into_queue (drive); - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (!idetape_pipeline_active (tape)) goto abort; #if IDETAPE_DEBUG_BUGS @@ -2567,7 +2578,7 @@ #endif /* IDETAPE_DEBUG_BUGS */ idetape_wait_for_request(drive, &tape->last_stage->rq); abort: - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); } static void idetape_pad_zeros (ide_drive_t *drive, int bcount) @@ -2812,10 +2823,10 @@ * Wait until the first read-ahead request * is serviced. */ - spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags); + spin_lock_irqsave(&tape->spinlock, flags); if (tape->active_stage == tape->first_stage) idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags); + spin_unlock_irqrestore(&tape->spinlock, flags); if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) count++; @@ -3559,6 +3570,8 @@ u16 speed; struct idetape_id_gcw gcw; + memset (tape, 0, sizeof (idetape_tape_t)); + tape->spinlock = (spinlock_t)SPIN_LOCK_UNLOCKED; drive->driver_data = tape; drive->ready_stat = 0; /* An ATAPI device ignores DRDY */ drive->dsc_overlap = 1; diff -u --recursive --new-file v2.2.10/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.2.10/linux/drivers/block/ide.c Sun Jun 13 10:40:27 1999 +++ linux/drivers/block/ide.c Mon Aug 9 12:04:39 1999 @@ -1416,6 +1416,17 @@ hwgroup->handler = NULL; (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]); del_timer(&(hwgroup->timer)); + { + struct request *rq; + unsigned long block, sectors; + + if ((rq = hwgroup->rq) != NULL) { + block = rq->sector; + block += drive->part[MINOR(rq->rq_dev)&PARTN_MASK].start_sect + drive->sect0; + sectors = drive->using_dma ? rq->nr_sectors : drive->mult_count ? drive->mult_count : 1; + } + } + spin_unlock_irqrestore(&hwgroup->spinlock, flags); if (drive->unmask) ide__sti(); /* local CPU only */ diff -u --recursive --new-file v2.2.10/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.2.10/linux/drivers/block/ll_rw_blk.c Thu Mar 11 23:20:14 1999 +++ linux/drivers/block/ll_rw_blk.c Mon Aug 9 12:04:39 1999 @@ -108,6 +108,11 @@ */ int * max_sectors[MAX_BLKDEV] = { NULL, NULL, }; +/* + * Max number of segments per request + */ +int * max_segments[MAX_BLKDEV] = { NULL, NULL, }; + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -115,6 +120,13 @@ return max_sectors[MAJOR(dev)][MINOR(dev)]; } +static inline int get_max_segments(kdev_t dev) +{ + if (!max_segments[MAJOR(dev)]) + return MAX_SEGMENTS; + return max_segments[MAJOR(dev)][MINOR(dev)]; +} + /* * Is called with the request spinlock aquired. * NOTE: the device-specific queue() functions @@ -266,7 +278,7 @@ } static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, - short disk_index) + short disk_index) { kstat.dk_drive[disk_index]++; if (cmd == READ) { @@ -291,24 +303,31 @@ void add_request(struct blk_dev_struct * dev, struct request * req) { + int major = MAJOR(req->rq_dev); + int minor = MINOR(req->rq_dev); struct request * tmp, **current_request; short disk_index; unsigned long flags; int queue_new_request = 0; - switch (MAJOR(req->rq_dev)) { + switch (major) { + case DAC960_MAJOR+0: + disk_index = (minor & 0x00f8) >> 3; + if (disk_index < 4) + drive_stat_acct(req->cmd, req->nr_sectors, disk_index); + break; case SCSI_DISK0_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x00f0) >> 4; + disk_index = (minor & 0x00f0) >> 4; if (disk_index < 4) drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE0_MAJOR: /* same as HD_MAJOR */ case XT_DISK_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x0040) >> 6; + disk_index = (minor & 0x0040) >> 6; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; case IDE1_MAJOR: - disk_index = ((MINOR(req->rq_dev) & 0x0040) >> 6) + 2; + disk_index = ((minor & 0x0040) >> 6) + 2; drive_stat_acct(req->cmd, req->nr_sectors, disk_index); default: break; @@ -346,8 +365,12 @@ tmp->next = req; /* for SCSI devices, call request_fn unconditionally */ - if (scsi_blk_major(MAJOR(req->rq_dev))) + if (scsi_blk_major(major) || + (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) || + (major >= COMPAQ_SMART2_MAJOR+0 && + major <= COMPAQ_SMART2_MAJOR+7)) queue_new_request = 1; + out: if (queue_new_request) (dev->request_fn)(); @@ -357,29 +380,39 @@ /* * Has to be called with the request spinlock aquired */ -static inline void attempt_merge (struct request *req, int max_sectors) +static inline void attempt_merge (struct request *req, + int max_sectors, + int max_segments) { struct request *next = req->next; + int total_segments; if (!next) return; if (req->sector + req->nr_sectors != next->sector) return; - if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors) + if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || + req->nr_sectors + next->nr_sectors > max_sectors) + return; + total_segments = req->nr_segments + next->nr_segments; + if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) + total_segments--; + if (total_segments > max_segments) return; req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors += next->nr_sectors; + req->nr_segments = total_segments; next->rq_status = RQ_INACTIVE; req->next = next->next; wake_up (&wait_for_request); } -void make_request(int major,int rw, struct buffer_head * bh) +void make_request(int major, int rw, struct buffer_head * bh) { unsigned int sector, count; struct request * req; - int rw_ahead, max_req, max_sectors; + int rw_ahead, max_req, max_sectors, max_segments; unsigned long flags; count = bh->b_size >> 9; @@ -397,15 +430,20 @@ if (maxsector < count || maxsector - count < sector) { bh->b_state &= (1 << BH_Lock); - /* This may well happen - the kernel calls bread() - without checking the size of the device, e.g., - when mounting a device. */ + /* This may well happen - the kernel calls bread() + without checking the size of the device, e.g., + when mounting a device. */ printk(KERN_INFO - "attempt to access beyond end of device\n"); + "attempt to access beyond end of device\n"); printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", - kdevname(bh->b_rdev), rw, - (sector + count)>>1, - blk_size[major][MINOR(bh->b_rdev)]); + kdevname(bh->b_rdev), rw, + (sector + count)>>1, + blk_size[major][MINOR(bh->b_rdev)]); + printk(KERN_INFO "dev %s blksize=%d blocknr=%ld sector=%ld size=%ld count=%d\n", + kdevname(bh->b_dev), + blksize_size[major][MINOR(bh->b_dev)], + bh->b_blocknr, bh->b_rsector, bh->b_size, bh->b_count); + goto end_io; } } @@ -437,13 +475,13 @@ break; default: printk(KERN_ERR "make_request: bad block dev cmd," - " must be R/W/RA/WA\n"); + " must be R/W/RA/WA\n"); goto end_io; } /* look for a free request. */ /* Loop uses two requests, 1 for loop and 1 for the real device. - * Cut max_req in half to avoid running out and deadlocking. */ + * Cut max_req in half to avoid running out and deadlocking. */ if ((major == LOOP_MAJOR) || (major == NBD_MAJOR)) max_req >>= 1; @@ -451,6 +489,7 @@ * Try to coalesce the new request with old requests */ max_sectors = get_max_sectors(bh->b_rdev); + max_segments = get_max_segments(bh->b_rdev); /* * Now we acquire the request spinlock, we have to be mega careful @@ -497,6 +536,22 @@ case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: + case DAC960_MAJOR+0: + case DAC960_MAJOR+1: + case DAC960_MAJOR+2: + case DAC960_MAJOR+3: + case DAC960_MAJOR+4: + case DAC960_MAJOR+5: + case DAC960_MAJOR+6: + case DAC960_MAJOR+7: + case COMPAQ_SMART2_MAJOR+0: + case COMPAQ_SMART2_MAJOR+1: + case COMPAQ_SMART2_MAJOR+2: + case COMPAQ_SMART2_MAJOR+3: + case COMPAQ_SMART2_MAJOR+4: + case COMPAQ_SMART2_MAJOR+5: + case COMPAQ_SMART2_MAJOR+6: + case COMPAQ_SMART2_MAJOR+7: do { if (req->sem) @@ -509,13 +564,25 @@ continue; /* Can we add it to the end of this request? */ if (req->sector + req->nr_sectors == sector) { + if (req->bhtail->b_data + req->bhtail->b_size + != bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } req->bhtail->b_reqnext = bh; req->bhtail = bh; req->nr_sectors += count; /* Can we now merge this req with the next? */ - attempt_merge(req, max_sectors); + attempt_merge(req, max_sectors, max_segments); /* or to the beginning? */ } else if (req->sector - count == sector) { + if (bh->b_data + bh->b_size + != req->bh->b_data) { + if (req->nr_segments < max_segments) + req->nr_segments++; + else continue; + } bh->b_reqnext = req->bh; req->bh = bh; req->buffer = bh->b_data; @@ -549,6 +616,7 @@ req->errors = 0; req->sector = sector; req->nr_sectors = count; + req->nr_segments = 1; req->current_nr_sectors = count; req->buffer = bh->b_data; req->sem = NULL; diff -u --recursive --new-file v2.2.10/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.2.10/linux/drivers/block/loop.c Sun May 30 10:17:03 1999 +++ linux/drivers/block/loop.c Mon Aug 9 12:04:39 1999 @@ -27,7 +27,13 @@ * - Should use an own CAP_* category instead of CAP_SYS_ADMIN * - Should use the underlying filesystems/devices read function if possible * to support read ahead (and for write) - */ + * + * WARNING/FIXME: + * - The block number as IV passing to low level transfer functions is broken: + * it passes the underlying device's block number instead of the + * offset. This makes it change for a given block when the file is + * moved/restored/copied and also doesn't work over NFS. + */ #include @@ -107,7 +113,7 @@ static int xor_status(struct loop_device *lo, struct loop_info *info) { - if (info->lo_encrypt_key_size < 0) + if (info->lo_encrypt_key_size <= 0) return -EINVAL; return 0; } @@ -369,6 +375,10 @@ a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { + if (!inode->i_op->bmap) { + printk(KERN_ERR "loop: device has no block access/not implemented\n"); + goto out_putf; + } /* Backed by a regular file - we need to hold onto a file structure for this file. We'll use it to @@ -504,8 +514,6 @@ if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; type = info.lo_encrypt_type; - if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR) - return -EINVAL; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; err = loop_release_xfer(lo); diff -u --recursive --new-file v2.2.10/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.2.10/linux/drivers/block/nbd.c Tue Mar 9 16:58:05 1999 +++ linux/drivers/block/nbd.c Mon Aug 9 12:04:39 1999 @@ -401,7 +401,7 @@ return 0; case NBD_SET_SIZE_BLOCKS: nbd_sizes[dev] = arg; - nbd_bytesizes[dev] = arg << nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev]; return 0; case NBD_DO_IT: if (!lo->file) diff -u --recursive --new-file v2.2.10/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.2.10/linux/drivers/block/rd.c Thu Apr 29 11:53:41 1999 +++ linux/drivers/block/rd.c Mon Aug 9 12:04:39 1999 @@ -517,7 +517,7 @@ } if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { - printk("RAMDISK: image too big! (%d/%d blocks)\n", + printk("RAMDISK: image too big! (%d/%ld blocks)\n", nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); goto done; } diff -u --recursive --new-file v2.2.10/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h --- v2.2.10/linux/drivers/block/smart1,2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/smart1,2.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,274 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 1998 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + * If you want to make changes, improve or add functionality to this + * driver, you'll probably need the Compaq Array Controller Interface + * Specificiation (Document number ECG086/1198) + */ + +/* + * This file contains the controller communication implementation for + * Compaq SMART-1 and SMART-2 controllers. To the best of my knowledge, + * this should support: + * + * PCI: + * SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200 + * Integerated SMART Array Controller, SMART-4200, SMART-4250ES + * + * EISA: + * SMART-2/E, SMART, IAES, IDA-2, IDA + */ + +/* + * Memory mapped FIFO interface (SMART 42xx cards) + */ +static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET); +} + +/* + * This card is the oposite of the other cards. + * 0 turns interrupts on... + * 0x08 turns them off... + */ +static void smart4_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val) + { /* Turn interrupts on */ + writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); + } else /* Turn them off */ + { + writel( S42XX_INTR_OFF, + h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); + } +} + +/* + * For this card fifo is full if reading this port returns 0! + * + */ +static unsigned long smart4_fifo_full(ctlr_info_t *h) +{ + + return (~readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); +} + +/* This type of controller returns -1 if the fifo is empty, + * Not 0 like the others. + * And we need to let it know we read a value out + */ +static unsigned long smart4_completed(ctlr_info_t *h) +{ + long register_value + = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET); + + /* Fifo is empty */ + if( register_value == -1) + return 0; + + /* Need to let it know we got the reply */ + /* We do this by writing a 0 to the port we just read from */ + writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET); + + return ((unsigned long) register_value); +} + + /* + * This hardware returns interrupt pending at a different place and + * it does not tell us if the fifo is empty, we will have check + * that by getting a 0 back from the comamnd_completed call. + */ +static unsigned long smart4_intr_pending(ctlr_info_t *h) +{ + unsigned long register_value = + readl(h->vaddr + S42XX_INTR_STATUS); + + if( register_value & S42XX_INTR_PENDING) + return FIFO_NOT_EMPTY; + return 0 ; +} + +static struct access_method smart4_access = { + smart4_submit_command, + smart4_intr_mask, + smart4_fifo_full, + smart4_intr_pending, + smart4_completed, +}; + +/* + * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards) + */ +static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + writel(c->busaddr, h->vaddr + COMMAND_FIFO); +} + +static void smart2_intr_mask(ctlr_info_t *h, unsigned long val) +{ + writel(val, h->vaddr + INTR_MASK); +} + +static unsigned long smart2_fifo_full(ctlr_info_t *h) +{ + return readl(h->vaddr + COMMAND_FIFO); +} + +static unsigned long smart2_completed(ctlr_info_t *h) +{ + return readl(h->vaddr + COMMAND_COMPLETE_FIFO); +} + +static unsigned long smart2_intr_pending(ctlr_info_t *h) +{ + return readl(h->vaddr + INTR_PENDING); +} + +static struct access_method smart2_access = { + smart2_submit_command, + smart2_intr_mask, + smart2_fifo_full, + smart2_intr_pending, + smart2_completed, +}; + +/* + * IO access for SMART-2/E cards + */ +static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + outl(c->busaddr, h->ioaddr + COMMAND_FIFO); +} + +static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val) +{ + outl(val, h->ioaddr + INTR_MASK); +} + +static unsigned long smart2e_fifo_full(ctlr_info_t *h) +{ + return inl(h->ioaddr + COMMAND_FIFO); +} + +static unsigned long smart2e_completed(ctlr_info_t *h) +{ + return inl(h->ioaddr + COMMAND_COMPLETE_FIFO); +} + +static unsigned long smart2e_intr_pending(ctlr_info_t *h) +{ + return inl(h->ioaddr + INTR_PENDING); +} + +static struct access_method smart2e_access = { + smart2e_submit_command, + smart2e_intr_mask, + smart2e_fifo_full, + smart2e_intr_pending, + smart2e_completed, +}; + +/* + * IO access for older SMART-1 type cards + */ +#define SMART1_SYSTEM_MASK 0xC8E +#define SMART1_SYSTEM_DOORBELL 0xC8F +#define SMART1_LOCAL_MASK 0xC8C +#define SMART1_LOCAL_DOORBELL 0xC8D +#define SMART1_INTR_MASK 0xC89 +#define SMART1_LISTADDR 0xC90 +#define SMART1_LISTLEN 0xC94 +#define SMART1_TAG 0xC97 +#define SMART1_COMPLETE_ADDR 0xC98 +#define SMART1_LISTSTATUS 0xC9E + +#define CHANNEL_BUSY 0x01 +#define CHANNEL_CLEAR 0x02 + +static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c) +{ + /* + * This __u16 is actually a bunch of control flags on SMART + * and below. We want them all to be zero. + */ + c->hdr.size = 0; + + outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL); + + outl(c->busaddr, h->ioaddr + SMART1_LISTADDR); + outw(c->size, h->ioaddr + SMART1_LISTLEN); + + outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); +} + +static void smart1_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val == 1) { + outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL); + outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL); + outb(0x01, h->ioaddr + SMART1_INTR_MASK); + outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK); + } else { + outb(0, h->ioaddr + 0xC8E); + } +} + +static unsigned long smart1_fifo_full(ctlr_info_t *h) +{ + unsigned char chan; + chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; + return chan; +} + +static unsigned long smart1_completed(ctlr_info_t *h) +{ + unsigned char status; + unsigned long cmd; + + if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { + outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL); + + cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR); + status = inb(h->ioaddr + SMART1_LISTSTATUS); + + outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL); + + if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; + } else { + cmd = 0; + } + return cmd; +} + +static unsigned long smart1_intr_pending(ctlr_info_t *h) +{ + unsigned char chan; + chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; + return chan; +} + +static struct access_method smart1_access = { + smart1_submit_command, + smart1_intr_mask, + smart1_fifo_full, + smart1_intr_pending, + smart1_completed, +}; diff -u --recursive --new-file v2.2.10/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.2.10/linux/drivers/cdrom/cdrom.c Thu Apr 29 11:53:41 1999 +++ linux/drivers/cdrom/cdrom.c Mon Aug 9 12:04:39 1999 @@ -1145,8 +1145,10 @@ ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0)); strcpy(cdrom_drive_info+pos,"\n\n"); - *lenp=pos+3; - + pos += 3; + if (*lenp > pos) + *lenp = pos; + return proc_dostring(ctl, write, filp, buffer, lenp); } diff -u --recursive --new-file v2.2.10/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.2.10/linux/drivers/char/Config.in Fri May 7 11:05:30 1999 +++ linux/drivers/char/Config.in Mon Aug 9 12:05:09 1999 @@ -28,6 +28,9 @@ tristate 'Digiboard PC/Xx Support' CONFIG_DIGI fi tristate 'Cyclades async mux support' CONFIG_CYCLADES + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then + bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR + fi bool 'Stallion multiport serial support' CONFIG_STALDRV if [ "$CONFIG_STALDRV" = "y" ]; then tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION @@ -38,6 +41,7 @@ if [ "$CONFIG_SPECIALIX" != "n" ]; then bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS fi + tristate 'Specialix SX (and SI) card support' CONFIG_SX tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m @@ -144,6 +148,11 @@ dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 + fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate 'SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV + fi fi dep_tristate 'Typhoon Radio (a.k.a. EcoRadio)' CONFIG_RADIO_TYPHOON $CONFIG_VIDEO_DEV if [ "$CONFIG_PROC_FS" = "y" ]; then diff -u --recursive --new-file v2.2.10/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.2.10/linux/drivers/char/Makefile Fri May 7 11:05:30 1999 +++ linux/drivers/char/Makefile Mon Aug 9 12:05:09 1999 @@ -30,16 +30,30 @@ ifeq ($(CONFIG_SERIAL),y) ifeq ($(CONFIG_SUN_SERIAL),) - LX_OBJS += serial.o + ifeq ($(CONFIG_SGI_SERIAL),) + ifeq ($(CONFIG_DECSTATION),) + ifeq ($(CONFIG_BAGET_MIPS),) + LX_OBJS += serial.o + endif + endif + endif endif else ifeq ($(CONFIG_SERIAL),m) ifeq ($(CONFIG_SUN_SERIAL),) - MX_OBJS += serial.o + ifeq ($(CONFIG_SGI_SERIAL),) + ifeq ($(CONFIG_DECSTATION),) + ifeq ($(CONFIG_BAGET_MIPS),) + MX_OBJS += serial.o + endif + endif + endif endif endif endif +ifndef CONFIG_DECSTATION +ifndef CONFIG_BAGET_MIPS ifndef CONFIG_SUN_KEYBOARD ifdef CONFIG_VT LX_OBJS += keyboard.o @@ -57,6 +71,8 @@ ifdef CONFIG_MAGIC_SYSRQ LX_OBJS += sysrq.o endif +endif +endif ifeq ($(CONFIG_ATARI_DSP56K),y) L_OBJS += dsp56k.o @@ -156,6 +172,14 @@ endif endif +ifeq ($(CONFIG_SX),y) +L_OBJS += sx.o generic_serial.o +else + ifeq ($(CONFIG_SX),m) + M_OBJS += sx.o + endif +endif + ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) L_OBJS += atixlmouse.o else @@ -362,6 +386,14 @@ endif endif +ifeq ($(CONFIG_VIDEO_VINO),y) +L_OBJS += vino.o +else + ifeq ($(CONFIG_VIDEO_VINO),m) + M_OBJS += vino.o + endif +endif + ifeq ($(CONFIG_RADIO_AZTECH),y) L_OBJS += radio-aztech.o else @@ -477,6 +509,10 @@ MOD_SUB_DIRS += hfmodem endif +endif + +ifeq ($(CONFIG_DZ),y) + L_OBJS += dz.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.2.10/linux/drivers/char/bttv.c Mon Jun 7 16:18:17 1999 +++ linux/drivers/char/bttv.c Mon Aug 9 12:04:57 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #if LINUX_VERSION_CODE >= 0x020100 #include @@ -81,8 +80,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 +109,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 +128,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 */ -static inline unsigned long uvirt_to_phys(unsigned long adr) +/* [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. + */ + +/* 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 +216,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 +234,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; } @@ -535,19 +563,21 @@ /* MIRO PCTV pro */ { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}}, /* ADS Technologies Channel Surfer TV (and maybe TV+FM) */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, + { 3, 4, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* AVerMedia TVCapture 98 */ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* Aimslab VHX */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, /* Zoltrix TV-Max */ - { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, + { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}}, /* Pixelview PlayTV (bt878) */ { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, /* "Leadtek WinView 601", */ { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, /* AVEC Intercapture */ { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, + /* LifeView FlyKit w/o Tuner */ + { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}} }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -823,30 +853,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 +911,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 +920,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 +984,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 +1021,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 +1037,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 +1067,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 +1080,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 +1192,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 +1217,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 +1327,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 +1521,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); @@ -1661,12 +1708,13 @@ struct video_capability b; strcpy(b.name,btv->video_dev.name); b.type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| VID_TYPE_TELETEXT| VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; + VID_TYPE_SCALES| + ((tvcards[btv->type].tuner != -1) + ? VID_TYPE_TUNER : 0); b.channels = tvcards[btv->type].video_inputs; b.audios = tvcards[btv->type].audio_inputs; b.maxwidth = tvnorms[btv->win.norm].swidth; @@ -2268,7 +2316,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; @@ -3100,7 +3148,7 @@ break; } printk("%s\n",btv->video_dev.name); - audio(btv, AUDIO_MUTE); + audio(btv, AUDIO_INTERN); } @@ -3110,44 +3158,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 +3213,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 +3378,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 +3434,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 +3452,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 +3549,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 +3567,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 +3591,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 +3870,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 --recursive --new-file v2.2.10/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.2.10/linux/drivers/char/bttv.h Mon Jun 7 16:18:17 1999 +++ linux/drivers/char/bttv.h Mon Aug 9 12:04:39 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 --recursive --new-file v2.2.10/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.2.10/linux/drivers/char/bw-qcam.c Fri Mar 26 13:57:41 1999 +++ linux/drivers/char/bw-qcam.c Mon Aug 9 12:04:39 1999 @@ -159,6 +159,8 @@ struct qcam_device *q; q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; q->pport = port; q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL, diff -u --recursive --new-file v2.2.10/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.2.10/linux/drivers/char/c-qcam.c Wed Dec 16 12:53:13 1998 +++ linux/drivers/char/c-qcam.c Mon Aug 9 12:04:39 1999 @@ -641,6 +641,8 @@ struct qcam_device *q; q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL); + if(q==NULL) + return NULL; q->pport = port; q->pdev = parport_register_device(port, "c-qcam", NULL, NULL, diff -u --recursive --new-file v2.2.10/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.2.10/linux/drivers/char/cyclades.c Mon May 24 22:38:02 1999 +++ linux/drivers/char/cyclades.c Mon Aug 9 12:04:39 1999 @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $"; +"$Revision: 2.2.2.3 $$Date: 1999/06/28 11:13:29 $"; /* * linux/drivers/char/cyclades.c @@ -31,6 +31,16 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.2.3 1999/06/28 11:13:29 ivan + * Added support for interrupt mode operation for the Z cards; + * Removed the driver inactivity control for the Z; + * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when + * the Z firmware is not loaded yet; + * Replaced the "manual" Z Tx flush buffer by a call to a FW command of + * same functionality; + * Implemented workaround for IRQ setting loss on the PCI configuration + * registers after a PCI bridge EEPROM reload (affects PLX9060 only); + * * Revision 2.2.2.2 1999/05/14 17:18:15 ivan * /proc entry location changed to /proc/tty/driver/cyclades; * Added support to shared IRQ's (only for PCI boards); @@ -528,7 +538,7 @@ constant in the definition below. No other change is necessary to support more boards/ports. */ -#define NR_PORTS 128 +#define NR_PORTS 256 #define ZE_V1_NPORTS 64 #define ZO_V1 0 @@ -810,13 +820,15 @@ #ifndef CONFIG_COBALT_27 static void cy_probe(int, void *, struct pt_regs *); #endif /* CONFIG_COBALT_27 */ -static void cyz_poll(unsigned long); #ifdef CYCLOM_SHOW_STATUS static void show_status(int); #endif static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); +#ifndef CONFIG_CYZ_INTR +static void cyz_poll(unsigned long); + /* The Cyclades-Z polling cycle is defined by this variable */ static long cyz_polling_cycle = CZ_DEF_POLL; @@ -825,6 +837,7 @@ cyz_timerlist = { NULL, NULL, 0, 0, cyz_poll }; +#endif /* CONFIG_CYZ_INTR */ /************************************************** error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long)); @@ -1197,7 +1210,7 @@ if((cinfo = (struct cyclades_card *)dev_id) == 0){ #ifdef CY_DEBUG_INTERRUPTS - printk("cy_interrupt: spurious interrupt %d\n\r", irq); + printk("cyy_interrupt: spurious interrupt %d\n\r", irq); #endif return; /* spurious interrupt */ } @@ -1229,7 +1242,7 @@ } if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); + printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); #endif /* determine the channel & change to that context */ save_xir = (u_char) cy_readb(base_addr+(CyRIR<flip.char_buf_ptr++ = 0; /* If the flip buffer itself is - overflowing, we still loose + overflowing, we still lose the next incoming character. */ if(tty->flip.count @@ -1356,7 +1369,7 @@ is empty, we know we can always stuff a dozen characters. */ #ifdef CY_DEBUG_INTERRUPTS - printk("cy_interrupt: xmit intr, chip %d\n\r", chip); + printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); #endif /* determine the channel & change to that context */ @@ -1636,12 +1649,285 @@ } /* cyz_update_channel */ #endif - +#ifdef CONFIG_CYZ_INTR static void cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + struct tty_struct *tty; + struct cyclades_card *cinfo; + struct cyclades_port *info; + static volatile struct FIRM_ID *firm_id; + static volatile struct ZFW_CTRL *zfw_ctrl; + static volatile struct BOARD_CTRL *board_ctrl; + static volatile struct CH_CTRL *ch_ctrl; + static volatile struct BUF_CTRL *buf_ctrl; + uclong channel; + ucchar cmd; + uclong param; + uclong hw_ver, fw_ver; + char data; + volatile int char_count, special_count; +#ifdef BLOCKMOVE + int small_count; +#endif + volatile uclong tx_put, tx_get, tx_bufsize; + volatile uclong rx_put, rx_get, rx_bufsize; + + if((cinfo = (struct cyclades_card *)dev_id) == 0){ +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: spurious interrupt %d\n\r", irq); +#endif + return; /* spurious interrupt */ + } + + firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + if (!ISZLOADED(*cinfo)) { +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: board not yet loaded (INT %d).\n\r", irq); +#endif + return; + } + + zfw_ctrl = (struct ZFW_CTRL *) + (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr)); + board_ctrl = &(zfw_ctrl->board_ctrl); + fw_ver = cy_readl(&board_ctrl->fw_version); + hw_ver = cy_readl(&((struct RUNTIME_9060 *) + (cinfo->ctl_addr))->mail_box_0); + + while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { + special_count = 0; + info = &cy_port[channel + cinfo->first_line]; + if((tty = info->tty) == 0) continue; + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); + + switch(cmd){ + case C_CM_PR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_FR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_RXBRK: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + *tty->flip.char_buf_ptr++ = 0; + special_count++; + break; + case C_CM_MDCD: + if (info->flags & ASYNC_CHECK_CD){ + if ((fw_ver > 241 ? + ((u_long)param) : + cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) { + /* SP("Open Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_OPEN_WAKEUP); + }else if(!((info->flags + & ASYNC_CALLOUT_ACTIVE) + &&(info->flags + & ASYNC_CALLOUT_NOHUP))){ + /* SP("Hangup\n"); */ + cy_sched_event(info, + Cy_EVENT_HANGUP); + } + } + break; + case C_CM_MCTS: + if (info->flags & ASYNC_CTS_FLOW) { + if(info->tty->hw_stopped){ + if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){ + /* cy_start isn't used because... + HW flow is handled by the board */ + /* SP("Write Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_WRITE_WAKEUP); + } + }else{ + if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){ + /* cy_stop isn't used because + HW flow is handled by the board */ + /* SP("Write stop\n"); */ + } + } + } + break; + case C_CM_MRI: + break; + case C_CM_MDSR: + break; +#ifdef Z_WAKE + case C_CM_IOCTLW: + cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP); + break; +#endif + case C_CM_RXHIWM: + case C_CM_RXNNDT: + /* Reception Interrupt */ +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r", + info->card, channel); +#endif + + rx_get = cy_readl(&buf_ctrl->rx_get); + rx_put = cy_readl(&buf_ctrl->rx_put); + rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); + if (rx_put >= rx_get) + char_count = rx_put - rx_get; + else + char_count = rx_put - rx_get + rx_bufsize; + + if ( char_count ){ + +#ifdef CY_ENABLE_MONITORING + info->mon.int_count++; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + info->idle_stats.recv_bytes += char_count; + info->idle_stats.recv_idle = jiffies; + if( tty == 0){ + /* flush received characters */ + rx_get = (rx_get + char_count) & (rx_bufsize - 1); + /* SP("-"); */ + info->rflush_count++; + }else{ +#ifdef BLOCKMOVE + /* we'd like to use memcpy(t, f, n) and memset(s, c, count) + for performance, but because of buffer boundaries, there + may be several steps to the operation */ + while(0 < (small_count + = cy_min((rx_bufsize - rx_get), + cy_min((TTY_FLIPBUF_SIZE - tty->flip.count), + char_count)))){ + + memcpy_fromio(tty->flip.char_buf_ptr, + (char *)(cinfo->base_addr + + cy_readl(&buf_ctrl->rx_bufaddr) + + rx_get), + small_count); + + tty->flip.char_buf_ptr += small_count; + memset(tty->flip.flag_buf_ptr, + TTY_NORMAL, + small_count); + tty->flip.flag_buf_ptr += small_count; + rx_get = (rx_get + small_count) & (rx_bufsize - 1); + char_count -= small_count; + tty->flip.count += small_count; + } +#else + while(char_count--){ + if (tty->flip.count >= TTY_FLIPBUF_SIZE){ + break; + } + data = cy_readb(cinfo->base_addr + + cy_readl(&buf_ctrl->rx_bufaddr) + rx_get); + rx_get = (rx_get + 1) & (rx_bufsize - 1); + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; + } +#endif + queue_task(&tty->flip.tqueue, &tq_timer); + } + /* Update rx_get */ + cy_writel(&buf_ctrl->rx_get, rx_get); + } + break; + case C_CM_TXBEMPTY: + case C_CM_TXLOWWM: + case C_CM_INTBACK: + /* Transmission Interrupt */ +#ifdef CY_DEBUG_INTERRUPTS + printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r", + info->card, channel); +#endif + + tx_get = cy_readl(&buf_ctrl->tx_get); + tx_put = cy_readl(&buf_ctrl->tx_put); + tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); + if (tx_put >= tx_get) + char_count = tx_get - tx_put - 1 + tx_bufsize; + else + char_count = tx_get - tx_put - 1; + + if ( char_count ){ + + if( tty == 0 ){ + goto ztxdone; + } + + if(info->x_char) { /* send special char */ + data = info->x_char; + + cy_writeb((cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + info->x_char = 0; + char_count--; + } +#ifdef BLOCKMOVE + while(0 < (small_count + = cy_min((tx_bufsize - tx_put), + cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail), + cy_min(info->xmit_cnt, char_count))))){ + + memcpy_toio((char *)(cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), + &info->xmit_buf[info->xmit_tail], + small_count); + + tx_put = (tx_put + small_count) & (tx_bufsize - 1); + char_count -= small_count; + info->xmit_cnt -= small_count; + info->xmit_tail = + (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1); + } +#else + while (info->xmit_cnt && char_count){ + data = info->xmit_buf[info->xmit_tail]; + info->xmit_cnt--; + info->xmit_tail = + (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + + cy_writeb(cinfo->base_addr + + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, + data); + tx_put = (tx_put + 1) & (tx_bufsize - 1); + char_count--; + } + +#endif + ztxdone: + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + /* Update tx_put */ + cy_writel(&buf_ctrl->tx_put, tx_put); + } + break; + case C_CM_FATAL: + /* should do something with this !!! */ + break; + } + if(special_count){ + queue_task(&tty->flip.tqueue, &tq_timer); + } + } + + return; } /* cyz_interrupt */ +#else /* CONFIG_CYZ_INTR */ static void cyz_poll(unsigned long arg) @@ -1675,7 +1961,6 @@ firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); if (!ISZLOADED(*cinfo)) { - cinfo->inact_ctrl = 0; continue; } @@ -1686,12 +1971,6 @@ hw_ver = cy_readl(&((struct RUNTIME_9060 *) (cinfo->ctl_addr))->mail_box_0); - /* Enables the firmware inactivity control */ - if ((fw_ver > 0x00000310L) && (!cinfo->inact_ctrl)) { - param = cyz_issue_cmd( &cy_card[card], 0L, C_CM_TINACT, 0L); - cinfo->inact_ctrl = 1; - } - while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1){ char_count = 0; info = &cy_port[ channel + cinfo->first_line ]; @@ -1922,17 +2201,13 @@ } /* poll every 40 ms */ cyz_timerlist.expires = jiffies + cyz_polling_cycle; - - /* refresh inactivity counter */ - if (cinfo->inact_ctrl) { - cy_writel(&board_ctrl->inactivity, (uclong) ZF_TINACT); - } } add_timer(&cyz_timerlist); return; } /* cyz_poll */ +#endif /* CONFIG_CYZ_INTR */ /********** End of block of Cyclades-Z specific code *********/ /***********************************************************/ @@ -2053,12 +2328,27 @@ cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE); #ifdef Z_WAKE +#ifdef CONFIG_CYZ_INTR cy_writel(&ch_ctrl[channel].intr_enable, - C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW); + C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT| + C_IN_IOCTLW| + C_IN_MDCD|C_IN_MCTS); #else cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_IOCTLW| C_IN_MDCD|C_IN_MCTS); -#endif +#endif /* CONFIG_CYZ_INTR */ +#else +#ifdef CONFIG_CYZ_INTR + cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT| + C_IN_MDCD|C_IN_MCTS); +#else + cy_writel(&ch_ctrl[channel].intr_enable, + C_IN_MDCD|C_IN_MCTS); +#endif /* CONFIG_CYZ_INTR */ +#endif /* Z_WAKE */ + retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */ if (retval != 0){ @@ -2126,11 +2416,21 @@ cy_readb(base_addr+(CySRER<card].intr_enabled) { + retval = cyz_issue_cmd(&cy_card[info->card], + 0, C_CM_IRQ_ENBL, 0L); + if (retval != 0){ + printk("cyc:IRQ enable retval was %x\n", retval); + } + cy_card[info->card].intr_enabled = 1; + } + } +#endif /* CONFIG_CYZ_INTR */ } #ifdef CY_DEBUG_OTHER printk("cyc:cy_open ttyC%d\n", info->line); /* */ @@ -3798,14 +4114,14 @@ if (break_state == -1) { if (!info->breakon) { info->breakon = 1; - if (!info->xmit_cnt ) { + if (!info->xmit_cnt) { start_xmit(info); } } } else { if (!info->breakoff) { info->breakoff = 1; - if (!info->xmit_cnt ) { + if (!info->xmit_cnt) { start_xmit(info); } } @@ -4053,6 +4369,7 @@ case CYGETCD1400VER: ret_val = info->chip_rev; break; +#ifndef CONFIG_CYZ_INTR case CYZSETPOLLCYCLE: cyz_polling_cycle = (arg * HZ) / 1000; ret_val = 0; @@ -4060,6 +4377,7 @@ case CYZGETPOLLCYCLE: ret_val = (cyz_polling_cycle * 1000) / HZ; break; +#endif /* CONFIG_CYZ_INTR */ case CYSETWAIT: info->closing_wait = (unsigned short)arg * HZ/100; ret_val = 0; @@ -4333,7 +4651,7 @@ cy_flush_buffer(struct tty_struct *tty) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int card, channel; + int card, channel, retval; unsigned long flags; #ifdef CY_DEBUG_IO @@ -4351,19 +4669,10 @@ if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board buffers as well */ - static volatile struct FIRM_ID *firm_id; - static volatile struct ZFW_CTRL *zfw_ctrl; - static volatile struct CH_CTRL *ch_ctrl; - static volatile struct BUF_CTRL *buf_ctrl; - - firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS); - zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr + - cy_readl(&firm_id->zfwctrl_addr)); - ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); - buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); - - while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put)) - cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get)); + retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L); + if (retval != 0) { + printk("cyc: flush_buffer retval was %x\n", retval); + } } wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) @@ -4872,10 +5181,11 @@ return(i); } +#ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { - if(request_irq(cy_pci_irq,cyz_interrupt, - SA_SHIRQ,"Cyclades-Z",&cy_card[j])) + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { + if(request_irq(cy_pci_irq, cyz_interrupt, + SA_SHIRQ, "Cyclades-Z", &cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4884,6 +5194,7 @@ return(i); } } +#endif /* CONFIG_CYZ_INTR */ /* set cy_card */ @@ -4896,7 +5207,7 @@ /* print message */ /* don't report IRQ if board is no IRQ */ - if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", j+1,(ulong)cy_pci_addr2, (ulong)(cy_pci_addr2 + CyPCI_Zwin - 1), @@ -4908,6 +5219,11 @@ } printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); +#ifdef CONFIG_CYZ_INTR + /* Enable interrupts on the PLX chip */ + cy_writew(cy_pci_addr0+0x68, + cy_readw(cy_pci_addr0+0x68)|0x0900); +#endif /* CONFIG_CYZ_INTR */ cy_next_channel += cy_pci_nchan; } } @@ -4927,10 +5243,6 @@ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0); printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n"); #endif - /* The following clears the firmware id word. This ensures - that the driver will not attempt to talk to the board - until it has been properly initialized. - */ PAUSE /* This must be the new Cyclades-Ze/PCI. */ cy_pci_nchan = ZE_V1_NPORTS; @@ -4955,10 +5267,11 @@ return(i); } +#ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { - if(request_irq(cy_pci_irq,cyz_interrupt, - SA_SHIRQ,"Cyclades-Z",&cy_card[j])) + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { + if(request_irq(cy_pci_irq, cyz_interrupt, + SA_SHIRQ, "Cyclades-Z", &cy_card[j])) { printk("Could not allocate IRQ%d ", cy_pci_irq); @@ -4967,6 +5280,7 @@ return(i); } } +#endif /* CONFIG_CYZ_INTR */ /* set cy_card */ cy_card[j].base_addr = cy_pci_addr2; @@ -4978,7 +5292,7 @@ /* print message */ /* don't report IRQ if board is no IRQ */ - if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) { printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", j+1,(ulong)cy_pci_addr2, (ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1), @@ -4990,6 +5304,11 @@ } printk("%d channels starting from port %d.\n", cy_pci_nchan,cy_next_channel); +#ifdef CONFIG_CYZ_INTR + /* Enable interrupts on the PLX chip */ + cy_writew(cy_pci_addr0+0x68, + cy_readw(cy_pci_addr0+0x68)|0x0900); +#endif /* CONFIG_CYZ_INTR */ cy_next_channel += cy_pci_nchan; } if (ZeIndex != 0) { @@ -5219,6 +5538,7 @@ mailbox = cy_readl(&((struct RUNTIME_9060 *) cy_card[board].ctl_addr)->mail_box_0); nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; + cinfo->intr_enabled = 0; for (port = cinfo->first_line ; port < cinfo->first_line + nports; port++) @@ -5342,15 +5662,17 @@ } } } - - if ( number_z_boards && !cyz_timeron){ - cyz_timeron++; + +#ifndef CONFIG_CYZ_INTR + if (number_z_boards && !cyz_timeron){ + cyz_timeron++; cyz_timerlist.expires = jiffies + 1; add_timer(&cyz_timerlist); #ifdef CY_PCI_DEBUG printk("Cyclades-Z polling initialized\n"); #endif } +#endif /* CONFIG_CYZ_INTR */ #ifdef CY_PROC ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0); @@ -5377,10 +5699,12 @@ int e1, e2; unsigned long flags; +#ifndef CONFIG_CYZ_INTR if (cyz_timeron){ cyz_timeron = 0; del_timer(&cyz_timerlist); } +#endif /* CONFIG_CYZ_INTR */ save_flags(flags); cli(); remove_bh(CYCLADES_BH); @@ -5396,6 +5720,9 @@ for (i = 0; i < NR_CARDS; i++) { if (cy_card[i].base_addr != 0 +#ifndef CONFIG_CYZ_INTR + && cy_card[i].num_chips != -1 /* not a Z card */ +#endif /* CONFIG_CYZ_INTR */ && cy_card[i].irq) { free_irq(cy_card[i].irq, &cy_card[i]); diff -u --recursive --new-file v2.2.10/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.2.10/linux/drivers/char/dz.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/dz.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1601 @@ +/* + * dz.c: Serial port driver for DECStations equiped + * with the DZ chipset. + * + * Copyright (C) 1998 Olivier A. D. Lebaillif + * + * Email: olivier.lebaillif@ifrsys.com + * + * [31-AUG-98] triemer + * Changed IRQ to use Harald's dec internals interrupts.h + * removed base_addr code - moving address assignment to setup.c + * Changed name of dz_init to rs_init to be consistent with tc code + * [13-NOV-98] triemer fixed code to receive characters + * after patches by harald to irq code. + * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout + * field from "current" - somewhere between 2.1.121 and 2.1.131 + */ + +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* for definition of SERIAL */ +#include + +/* for definition of struct console */ +#ifdef CONFIG_SERIAL_CONSOLE +#define CONSOLE_LINE (3) +#include +#endif /* ifdef CONFIG_SERIAL_CONSOLE */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_DZ 1 +#ifdef DEBUG_DZ +#include +#include +#include +#include +#include +#include +#include + +extern int (*prom_printf) (char *,...); +#endif + + + +#include "dz.h" + +#define DZ_INTR_DEBUG 1 + +DECLARE_TASK_QUEUE(tq_serial); + +extern struct wait_queue *keypress_wait; +static struct dz_serial *lines[4]; +static unsigned char tmp_buffer[256]; + + + +#ifdef DEBUG_DZ +/* + * debugging code to send out chars via prom + */ +static void debug_console( const char *s,int count) +{ + unsigned i; + + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} +#endif + +/* + * ------------------------------------------------------------ + * dz_in () and dz_out () + * + * These routines are used to access the registers of the DZ + * chip, hiding relocation differences between implementation. + * ------------------------------------------------------------ + */ + +static inline unsigned short dz_in (struct dz_serial *info, unsigned offset) +{ + volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset); + return *addr; +} + +static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned short value) +{ + + volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset); + *addr = value; + +} + +/* + * ------------------------------------------------------------ + * rs_stop () and rs_start () + * + * These routines are called before setting or resetting + * tty->stopped. They enable or disable transmitter interrupts, + * as necessary. + * ------------------------------------------------------------ + */ + +static void dz_stop (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + unsigned short mask, tmp; + + + mask = 1 << info->line; + tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + + tmp &= ~mask; /* clear the TX flag */ + dz_out (info, DZ_TCR, tmp); +} + +static void dz_start (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + unsigned short mask, tmp; + + mask = 1 << info->line; + tmp = dz_in (info, DZ_TCR); /* read the TX flag */ + + tmp |= mask; /* set the TX flag */ + dz_out (info, DZ_TCR, tmp); + +} + +/* + * ------------------------------------------------------------ + * Here starts the interrupt handling routines. All of the + * following subroutines are declared as inline and are folded + * into dz_interrupt. They were separated out for readability's + * sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer dz.c + * + * and look at the resulting assemble code in serial.s. + * + * ------------------------------------------------------------ + */ + +/* + * ------------------------------------------------------------ + * dz_sched_event () + * + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + * ------------------------------------------------------------ + */ +static inline void dz_sched_event (struct dz_serial *info, int event) +{ + info->event |= 1 << event; + queue_task (&info->tqueue, &tq_serial); + mark_bh (SERIAL_BH); +} + +/* + * ------------------------------------------------------------ + * receive_char () + * + * This routine deals with inputs from any lines. + * ------------------------------------------------------------ + */ +static inline void receive_chars (struct dz_serial *info_in) +{ + + struct dz_serial *info; + struct tty_struct *tty = 0; + struct async_icount *icount; + int ignore = 0; + unsigned short status, tmp; + unsigned char ch; + + /* this code is going to be a problem... + the call to tty_flip_buffer is going to need + to be rethought... + */ + do + { + status = dz_in (info_in, DZ_RBUF); + info = lines[LINE(status)]; + + /* punt so we don't get duplicate characters */ + if (!(status & DZ_DVAL)) + goto ignore_char; + + + ch = UCHAR(status); /* grab the char */ + +#ifdef 0 + if (info->is_console) { + if (ch == 0) return; /* it's a break ... */ + + wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */ + } +#endif + + tty = info->tty; /* now tty points to the proper dev */ + icount = &info->icount; + + if (!tty) break; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = 0; + icount->rx++; + + /* keep track of the statistics */ + if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) { + if (status & DZ_PERR) /* parity error */ + icount->parity++; + else if (status & DZ_FERR) /* frame error */ + icount->frame++; + if (status & DZ_OERR) /* overrun error */ + icount->overrun++; + + /* check to see if we should ignore the character + and mask off conditions that should be ignored + */ + + if (status & info->ignore_status_mask) { + if (++ignore > 100 ) break; + goto ignore_char; + } + + /* mask off the error conditions we want to ignore */ + tmp = status & info->read_status_mask; + + if (tmp & DZ_PERR) + { + *tty->flip.flag_buf_ptr = TTY_PARITY; + debug_console("PERR\n",5); + } + else if (tmp & DZ_FERR) + { + *tty->flip.flag_buf_ptr = TTY_FRAME; + debug_console("FERR\n",5); + } + if (tmp & DZ_OERR) + { + debug_console("OERR\n",5); + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + } while (status & DZ_DVAL); + + if (tty) + tty_flip_buffer_push(tty); +} + +/* + * ------------------------------------------------------------ + * transmit_char () + * + * This routine deals with outputs to any lines. + * ------------------------------------------------------------ + */ +static inline void transmit_chars (struct dz_serial *info) +{ + unsigned char tmp; + + + + if (info->x_char) { /* XON/XOFF chars */ + dz_out (info, DZ_TDR, info->x_char); + info->icount.tx++; + info->x_char = 0; + return; + } + + /* if nothing to do or stopped or hardware stopped */ + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { + dz_stop (info->tty); + return; + } + + /* if something to do ... (rember the dz has no output fifo so we go one char at a time :-< */ + tmp = (unsigned short)info->xmit_buf[info->xmit_tail++]; + dz_out (info, DZ_TDR, tmp); + info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1); + info->icount.tx++; + + if (--info->xmit_cnt < WAKEUP_CHARS) + dz_sched_event (info, DZ_EVENT_WRITE_WAKEUP); + + + /* Are we done */ + if (info->xmit_cnt <= 0) dz_stop (info->tty); +} + +/* + * ------------------------------------------------------------ + * check_modem_status () + * + * Only valid for the MODEM line duh ! + * ------------------------------------------------------------ + */ +static inline void check_modem_status (struct dz_serial *info) +{ + unsigned short status; + + /* if not ne modem line just return */ + if (info->line != DZ_MODEM) return; + + status = dz_in (info, DZ_MSR); + + /* it's easy, since DSR2 is the only bit in the register */ + if (status) info->icount.dsr++; +} + +/* + * ------------------------------------------------------------ + * dz_interrupt () + * + * this is the main interrupt routine for the DZ chip. + * It deals with the multiple ports. + * ------------------------------------------------------------ + */ +static void dz_interrupt (int irq, void *dev, struct pt_regs *regs) +{ + struct dz_serial *info; + unsigned short status; + + status = dz_in ((struct dz_serial *)dev, DZ_CSR); /* get the reason why we just got an irq */ + info = lines[LINE(status)]; /* re-arrange info the proper port */ + + if (status & DZ_RDONE) + receive_chars (info); /* the receive function */ + + if (status & DZ_TRDY) + transmit_chars (info); +} + +/* + * ------------------------------------------------------------------- + * Here ends the DZ interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh (void) +{ + run_task_queue (&tq_serial); +} + +static void do_softint (void *private_data) +{ + struct dz_serial *info = (struct dz_serial *)private_data; + struct tty_struct *tty = info->tty; + + if (!tty) return; + + if (test_and_clear_bit (DZ_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + wake_up_interruptible (&tty->write_wait); + } +} + +/* + * ------------------------------------------------------------------- + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * ------------------------------------------------------------------- + */ +static void do_serial_hangup (void *private_data) +{ + struct dz_serial *info = (struct dz_serial *)private_data; + struct tty_struct *tty = info->tty;; + + if (!tty) return; + + tty_hangup (tty); +} + +/* + * ------------------------------------------------------------------- + * startup () + * + * various initialization tasks + * ------------------------------------------------------------------- + */ +static int startup (struct dz_serial *info) +{ + unsigned long page, flags; + unsigned short tmp; + + if (info->is_initialized) return 0; + + save_flags (flags); + cli (); + + if (!info->port) { + if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags); + restore_flags (flags); + return -ENODEV; + } + + if (!info->xmit_buf) { + page = get_free_page (GFP_KERNEL); + if (!page) { + restore_flags (flags); + return -ENOMEM; + } + info->xmit_buf = (unsigned char *)page; + } + + if (info->tty) clear_bit (TTY_IO_ERROR, &info->tty->flags); + + /* enable the interrupt and the scanning */ + tmp = dz_in (info, DZ_CSR); + tmp |= (DZ_RIE | DZ_TIE | DZ_MSE); + dz_out (info, DZ_CSR, tmp); + + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* set up the speed */ + change_speed (info); + + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. + */ + + /* clear the line transmitter buffer + I can't figure out why I need to do this - but + its necessary - in order for the console portion + and the interrupt portion to live happily side by side. + */ + + info->is_initialized = 1; + + restore_flags (flags); + return 0; +} + +/* + * ------------------------------------------------------------------- + * shutdown () + * + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + * ------------------------------------------------------------------- + */ +static void shutdown (struct dz_serial *info) +{ + unsigned long flags; + unsigned short tmp; + + if (!info->is_initialized) return; + + save_flags (flags); + cli (); + + dz_stop (info->tty); + + + + info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */ + dz_out (info, DZ_LPR, info->cflags); + + if (info->xmit_buf) { /* free Tx buffer */ + free_page ((unsigned long)info->xmit_buf); + info->xmit_buf = 0; + } + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + tmp = dz_in (info, DZ_TCR); + if (tmp & DZ_MODEM_DTR) { + tmp &= ~DZ_MODEM_DTR; + dz_out (info, DZ_TCR, tmp); + } + } + + if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags); + + info->is_initialized = 0; + restore_flags (flags); +} + +/* + * ------------------------------------------------------------------- + * change_speed () + * + * set the baud rate. + * ------------------------------------------------------------------- + */ +static void change_speed (struct dz_serial *info) +{ + unsigned long flags; + unsigned cflag; + int baud; + + if (!info->tty || !info->tty->termios) return; + + save_flags (flags); + cli (); + + info->cflags = info->line; + + cflag = info->tty->termios->c_cflag; + + switch (cflag & CSIZE) { + case CS5: info->cflags |= DZ_CS5; break; + case CS6: info->cflags |= DZ_CS6; break; + case CS7: info->cflags |= DZ_CS7; break; + case CS8: + default: info->cflags |= DZ_CS8; + } + + if (cflag & CSTOPB) info->cflags |= DZ_CSTOPB; + if (cflag & PARENB) info->cflags |= DZ_PARENB; + if (cflag & PARODD) info->cflags |= DZ_PARODD; + + baud = tty_get_baud_rate (info->tty); + switch (baud) { + case 50 : info->cflags |= DZ_B50; break; + case 75 : info->cflags |= DZ_B75; break; + case 110 : info->cflags |= DZ_B110; break; + case 134 : info->cflags |= DZ_B134; break; + case 150 : info->cflags |= DZ_B150; break; + case 300 : info->cflags |= DZ_B300; break; + case 600 : info->cflags |= DZ_B600; break; + case 1200: info->cflags |= DZ_B1200; break; + case 1800: info->cflags |= DZ_B1800; break; + case 2000: info->cflags |= DZ_B2000; break; + case 2400: info->cflags |= DZ_B2400; break; + case 3600: info->cflags |= DZ_B3600; break; + case 4800: info->cflags |= DZ_B4800; break; + case 7200: info->cflags |= DZ_B7200; break; + case 9600: + default : info->cflags |= DZ_B9600; + } + + info->cflags |= DZ_RXENAB; + dz_out (info, DZ_LPR, info->cflags); + + /* setup accept flag */ + info->read_status_mask = DZ_OERR; + if (I_INPCK(info->tty)) + info->read_status_mask |= (DZ_FERR | DZ_PERR); + + /* characters to ignore */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= (DZ_FERR | DZ_PERR); + + restore_flags (flags); +} + +/* + * ------------------------------------------------------------------- + * dz_flush_char () + * + * Flush the buffer. + * ------------------------------------------------------------------- + */ +static void dz_flush_chars (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + unsigned long flags; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) + return; + + save_flags (flags); + cli (); + + dz_start (info->tty); + + restore_flags (flags); +} + + +/* + * ------------------------------------------------------------------- + * dz_write () + * + * main output routine. + * ------------------------------------------------------------------- + */ +static int dz_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + unsigned long flags; + int c, ret = 0; + + if (!tty ) return ret; + if (!info->xmit_buf) return ret; + if (!tmp_buf) tmp_buf = tmp_buffer; + + + + if (from_user) { + + down (&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); + if (c <= 0) break; + + c -= copy_from_user (tmp_buf, buf, c); + if (!c) { + if (!ret) ret = -EFAULT; + break; + } + + save_flags (flags); + cli (); + + c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1)); + info->xmit_cnt += c; + + restore_flags(flags); + + buf += c; + count -= c; + ret += c; + } + + up (&tmp_buf_sem); + } else { + + + while (1) { + save_flags (flags); + cli (); + + c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags (flags); + break; + } + memcpy (info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1)); + info->xmit_cnt += c; + + restore_flags (flags); + + buf += c; + count -= c; + ret += c; + } + } + + + if (info->xmit_cnt) + { + if (!tty->stopped) + { + if (!tty->hw_stopped) + { + dz_start (info->tty); + } + } + } + return ret; +} + +/* + * ------------------------------------------------------------------- + * dz_write_room () + * + * compute the amount of space available for writing. + * ------------------------------------------------------------------- + */ +static int dz_write_room (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + int ret; + + ret = DZ_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) ret = 0; + return ret; +} + +/* + * ------------------------------------------------------------------- + * dz_chars_in_buffer () + * + * compute the amount of char left to be transmitted + * ------------------------------------------------------------------- + */ +static int dz_chars_in_buffer (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + return info->xmit_cnt; +} + +/* + * ------------------------------------------------------------------- + * dz_flush_buffer () + * + * Empty the output buffer + * ------------------------------------------------------------------- + */ +static void dz_flush_buffer (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + cli (); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti (); + + wake_up_interruptible (&tty->write_wait); + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * ------------------------------------------------------------ + * dz_throttle () and dz_unthrottle () + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled (or not). + * ------------------------------------------------------------ + */ +static void dz_throttle (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); +} + +static void dz_unthrottle (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } +} + +static void dz_send_xchar (struct tty_struct *tty, char ch) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + info->x_char = ch; + + if (ch) dz_start (info->tty); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl () and friends + * ------------------------------------------------------------ + */ +static int get_serial_info (struct dz_serial *info, struct serial_struct *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset (&tmp, 0, sizeof(tmp)); + + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = SERIAL; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + + return copy_to_user (retinfo, &tmp, sizeof(*retinfo)); +} + +static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info) +{ + struct serial_struct new_serial; + struct dz_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + + copy_from_user (&new_serial, new_info, sizeof(new_serial)); + old_info = *info; + + if (!suser()) + return -EPERM; + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + + retval = startup (info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info (struct dz_serial *info, unsigned int *value) +{ + unsigned short status = dz_in (info, DZ_LPR); + + return put_user (status, value); +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break (struct dz_serial *info, int duration) +{ + unsigned long flags; + unsigned short tmp, mask; + + if (!info->port) + return; + + mask = 1 << info->line; + tmp = dz_in (info, DZ_TCR); + tmp |= mask; + + current->state = TASK_INTERRUPTIBLE; + + save_flags (flags); + cli(); + + dz_out (info, DZ_TCR, tmp); + + schedule_timeout(jiffies + duration); + + tmp &= ~mask; + dz_out (info, DZ_TCR, tmp); + + restore_flags (flags); +} + +static int dz_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +{ + int error; + struct dz_serial * info = (struct dz_serial *)tty->driver_data; + int retval; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change (tty); + if (retval) + return retval; + tty_wait_until_sent (tty, 0); + if (!arg) + send_break (info, HZ/4); /* 1/4 second */ + return 0; + + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change (tty); + if (retval) + return retval; + tty_wait_until_sent (tty, 0); + send_break (info, arg ? arg*(HZ/10) : HZ/4); + return 0; + + case TIOCGSOFTCAR: + error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long)); + if (error) + return error; + put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); + return 0; + + case TIOCSSOFTCAR: + error = get_user (arg, (unsigned long *)arg); + if (error) + return error; + tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + return 0; + + case TIOCGSERIAL: + error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct)); + if (error) + return error; + return get_serial_info (info, (struct serial_struct *)arg); + + case TIOCSSERIAL: + return set_serial_info (info, (struct serial_struct *) arg); + + case TIOCSERGETLSR: /* Get line status register */ + error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(unsigned int)); + if (error) + return error; + else + return get_lsr_info (info, (unsigned int *)arg); + + case TIOCSERGSTRUCT: + error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct dz_serial)); + if (error) + return error; + copy_to_user((struct dz_serial *)arg, info, sizeof(struct dz_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static void dz_set_termios (struct tty_struct *tty, + struct termios *old_termios) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + change_speed (info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + dz_start (tty); + } +} + +/* + * ------------------------------------------------------------ + * dz_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we turn off + * the transmit enable and receive enable flags. + * ------------------------------------------------------------ + */ +static void dz_close (struct tty_struct *tty, struct file *filp) +{ + struct dz_serial * info = (struct dz_serial *)tty->driver_data; + unsigned long flags; + + if (!info) return; + + save_flags (flags); + cli(); + + if (tty_hung_up_p (filp)) { + restore_flags (flags); + return; + } + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("dz_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + + if (info->count) { + restore_flags (flags); + return; + } + info->flags |= DZ_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & DZ_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & DZ_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + + if (info->closing_wait != DZ_CLOSING_WAIT_NONE) + tty_wait_until_sent (tty, info->closing_wait); + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ + + shutdown (info); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer (tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer (tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(jiffies + info->close_delay); + } + wake_up_interruptible (&info->open_wait); + } + + info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); + wake_up_interruptible (&info->close_wait); + + restore_flags (flags); +} + +/* + * dz_hangup () --- called by tty_hangup() when a hangup is signaled. + */ +static void dz_hangup (struct tty_struct *tty) +{ + struct dz_serial *info = (struct dz_serial *)tty->driver_data; + + dz_flush_buffer (tty); + shutdown (info); + info->event = 0; + info->count = 0; + info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible (&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz_serial *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & DZ_CLOSING) { + interruptible_sleep_on (&info->close_wait); + return -EAGAIN; + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & DZ_NORMAL_ACTIVE) + return -EBUSY; + + if ((info->flags & DZ_CALLOUT_ACTIVE) && + (info->flags & DZ_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + + if ((info->flags & DZ_CALLOUT_ACTIVE) && + (info->flags & DZ_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= DZ_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & DZ_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= DZ_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & DZ_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * dz_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue (&info->open_wait, &wait); + + info->count--; + info->blocked_open++; + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p (filp) || !(info->is_initialized)) { + retval = -EAGAIN; + break; + } + if (!(info->flags & DZ_CALLOUT_ACTIVE) && + !(info->flags & DZ_CLOSING) && do_clocal) + break; + if (signal_pending (current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue (&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; + + if (retval) + return retval; + info->flags |= DZ_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port. It also performs the + * serial-specific initialization for the tty structure. + */ +static int dz_open (struct tty_struct *tty, struct file *filp) +{ + struct dz_serial *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + + /* The dz lines for the mouse/keyboard must be + * opened using their respective drivers. + */ + if ((line < 0) || (line >= DZ_NB_PORT)) + return -ENODEV; + + if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE)) + return -ENODEV; + + info = lines[line]; + info->count++; + + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + retval = startup (info); + if (retval) + return retval; + + + + retval = block_til_ready (tty, filp, info); + if (retval) + return retval; + + if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_speed (info); + + } + + info->session = current->session; + info->pgrp = current->pgrp; + return 0; +} + +static void show_serial_version (void) +{ + printk("%s%s\n", dz_name, dz_version); +} + + +__initfunc(int dz_init(void)) +{ + int i, flags; + struct dz_serial *info; + + /* Setup base handler, and timer table. */ + init_bh (SERIAL_BH, do_serial_bh); + + show_serial_version (); + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = DZ_NB_PORT; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + + serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = dz_open; + serial_driver.close = dz_close; + serial_driver.write = dz_write; + serial_driver.flush_chars = dz_flush_chars; + serial_driver.write_room = dz_write_room; + serial_driver.chars_in_buffer = dz_chars_in_buffer; + serial_driver.flush_buffer = dz_flush_buffer; + serial_driver.ioctl = dz_ioctl; + serial_driver.throttle = dz_throttle; + serial_driver.unthrottle = dz_unthrottle; + serial_driver.send_xchar = dz_send_xchar; + serial_driver.set_termios = dz_set_termios; + serial_driver.stop = dz_stop; + serial_driver.start = dz_start; + serial_driver.hangup = dz_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (tty_register_driver (&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver (&callout_driver)) + panic("Couldn't register callout driver\n"); + save_flags(flags); cli(); + + i = 0; + for (info = &multi[i]; i < DZ_NB_PORT; i++) + { + lines[i] = info; + info->magic = SERIAL_MAGIC; + + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + info->port = (unsigned long) KN01_DZ11_BASE; + else + info->port = (unsigned long) KN02_DZ11_BASE; + + info->line = i; + info->tty = 0; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; + info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + + /* If we are pointing to address zero then punt - not correctly + set up in setup.c to handle this. */ + if (! info->port) + return 0; + + printk("ttyS%02d at 0x%04x (irq = %d)\n", info->line, info->port, SERIAL); + } + + /* reset the chip */ +#ifndef CONFIG_SERIAL_CONSOLE + dz_out(info, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR) ; + wbflush(); + + /* enable scanning */ + dz_out(info, DZ_CSR, DZ_MSE); +#endif + + /* order matters here... the trick is that flags + is updated... in request_irq - to immediatedly obliterate + it is unwise. */ + restore_flags(flags); + + + if (request_irq (SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) + panic ("Unable to register DZ interrupt\n"); + + return 0; +} + +#ifdef CONFIG_SERIAL_CONSOLE +static void dz_console_put_char (unsigned char ch) +{ + long flags; + int loops = 2500; + unsigned short tmp = ch; + /* this code sends stuff out to serial device - spinning its + wheels and waiting. */ + + /* force the issue - point it at lines[3]*/ + dz_console=&multi[CONSOLE_LINE]; + + save_flags(flags); + cli(); + + + /* spin our wheels */ + while (((dz_in(dz_console,DZ_TCR) & DZ_TRDY) != DZ_TRDY) && loops--) + ; + + /* Actually transmit the character. */ + dz_out (dz_console, DZ_TDR, tmp); + + restore_flags(flags); +} +/* + * ------------------------------------------------------------------- + * dz_console_print () + * + * dz_console_print is registered for printk. + * ------------------------------------------------------------------- + */ +static void dz_console_print (struct console *cons, + const char *str, + unsigned int count) +{ +#ifdef DEBUG_DZ + prom_printf((char *)str); +#endif + while (count--) + { + if (*str == '\n') + dz_console_put_char ('\r'); + dz_console_put_char (*str++); + } +} + +static int dz_console_wait_key(struct console *co) +{ + return 0; +} + +static kdev_t dz_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +__initfunc(static int dz_console_setup(struct console *co, char *options)) +{ + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + char *s; + unsigned short mask,tmp; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) + parity = *s++; + if (*s) + bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= DZ_B1200; + break; + case 2400: + cflag |= DZ_B2400; + break; + case 4800: + cflag |= DZ_B4800; + break; + case 9600: + default: + cflag |= DZ_B9600; + break; + } + switch(bits) { + case 7: + cflag |= DZ_CS7; + break; + default: + case 8: + cflag |= DZ_CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= DZ_PARODD; + break; + case 'e': case 'E': + cflag |= DZ_PARENB; + break; + } + co->cflag = cflag; + + /* TOFIX: force to console line */ + dz_console = &multi[CONSOLE_LINE]; + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + dz_console->port = KN01_DZ11_BASE; + else + dz_console->port = KN02_DZ11_BASE; + dz_console->line = CONSOLE_LINE; + + dz_out(dz_console, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) + ; + + /* enable scanning */ + dz_out(dz_console, DZ_CSR, DZ_MSE); + + /* Set up flags... */ + dz_console->cflags = 0; + dz_console->cflags |= DZ_B9600; + dz_console->cflags |= DZ_CS8; + dz_console->cflags |= DZ_PARENB; + dz_out (dz_console, DZ_LPR, dz_console->cflags); + + + mask = 1 << dz_console->line; + tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ + if (!(tmp & mask)) { + tmp |= mask; /* set the TX flag */ + dz_out (dz_console, DZ_TCR, tmp); + } + + + /* TOFIX: force to console line */ + dz_console = &multi[CONSOLE_LINE]; + if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) + dz_console->port = KN01_DZ11_BASE; + else + dz_console->port = KN02_DZ11_BASE; + dz_console->line = CONSOLE_LINE; + + dz_out(dz_console, DZ_CSR, DZ_CLR); + while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) + ; + + /* enable scanning */ + dz_out(dz_console, DZ_CSR, DZ_MSE); + + /* Set up flags... */ + dz_console->cflags = 0; + dz_console->cflags |= DZ_B9600; + dz_console->cflags |= DZ_CS8; + dz_console->cflags |= DZ_PARENB; + dz_out (dz_console, DZ_LPR, dz_console->cflags); + + + mask = 1 << dz_console->line; + tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ + if (!(tmp & mask)) { + tmp |= mask; /* set the TX flag */ + dz_out (dz_console, DZ_TCR, tmp); + } + + + return 0; +} + +static struct console dz_sercons = { + "ttyS", + dz_console_print, + NULL, + dz_console_device, + dz_console_wait_key, + NULL, + dz_console_setup, + CON_CONSDEV | CON_PRINTBUFFER, + CONSOLE_LINE, + 0, + NULL +}; + +__initfunc (long dz_serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&dz_sercons); + + return kmem_start; +} + +#endif /* ifdef CONFIG_SERIAL_CONSOLE */ + diff -u --recursive --new-file v2.2.10/linux/drivers/char/dz.h linux/drivers/char/dz.h --- v2.2.10/linux/drivers/char/dz.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/dz.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,242 @@ +/* + * dz.h: Serial port driver for DECStations equiped + * with the DZ chipset. + * + * Copyright (C) 1998 Olivier A. D. Lebaillif + * + * Email: olivier.lebaillif@ifrsys.com + * + */ +#ifndef DZ_SERIAL_H +#define DZ_SERIAL_H + +/* + * Definitions for the Control and Status Received. + */ +#define DZ_TRDY 0x8000 /* Transmitter empty */ +#define DZ_TIE 0x4000 /* Transmitter Interrupt Enable */ +#define DZ_RDONE 0x0080 /* Receiver data ready */ +#define DZ_RIE 0x0040 /* Receive Interrupt Enable */ +#define DZ_MSE 0x0020 /* Master Scan Enable */ +#define DZ_CLR 0x0010 /* Master reset */ +#define DZ_MAINT 0x0008 /* Loop Back Mode */ + +/* + * Definitions for the Received buffer. + */ +#define DZ_RBUF_MASK 0x00FF /* Data Mask in the Receive Buffer */ +#define DZ_LINE_MASK 0x0300 /* Line Mask in the Receive Buffer */ +#define DZ_DVAL 0x8000 /* Valid Data indicator */ +#define DZ_OERR 0x4000 /* Overrun error indicator */ +#define DZ_FERR 0x2000 /* Frame error indicator */ +#define DZ_PERR 0x1000 /* Parity error indicator */ + +#define LINE(x) (x & DZ_LINE_MASK) >> 8 /* Get the line number from the input buffer */ +#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK) + +/* + * Definitions for the Transmit Register. + */ +#define DZ_LINE_KEYBOARD 0x0001 +#define DZ_LINE_MOUSE 0x0002 +#define DZ_LINE_MODEM 0x0004 +#define DZ_LINE_PRINTER 0x0008 + +#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */ + +/* + * Definitions for the Modem Status Register. + */ +#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */ + +/* + * Definitions for the Transmit Data Register. + */ +#define DZ_BRK0 0x0100 /* Break assertion for line 0 */ +#define DZ_BRK1 0x0200 /* Break assertion for line 1 */ +#define DZ_BRK2 0x0400 /* Break assertion for line 2 */ +#define DZ_BRK3 0x0800 /* Break assertion for line 3 */ + +/* + * Definitions for the Line Parameter Register. + */ +#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */ +#define DZ_MOUSE 0x0001 /* line 1 = mouse */ +#define DZ_MODEM 0x0002 /* line 2 = modem */ +#define DZ_PRINTER 0x0003 /* line 3 = printer */ + +#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */ +#define DZ_CS5 0x0000 /* 5 bits per byte */ +#define DZ_CS6 0x0008 /* 6 bits per byte */ +#define DZ_CS7 0x0010 /* 7 bits per byte */ +#define DZ_CS8 0x0018 /* 8 bits per byte */ + +#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */ + +#define DZ_PARENB 0x0040 /* Parity enable */ +#define DZ_PARODD 0x0080 /* Odd parity instead of even */ + +#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */ +#define DZ_B50 0x0000 +#define DZ_B75 0x0100 +#define DZ_B110 0x0200 +#define DZ_B134 0x0300 +#define DZ_B150 0x0400 +#define DZ_B300 0x0500 +#define DZ_B600 0x0600 +#define DZ_B1200 0x0700 +#define DZ_B1800 0x0800 +#define DZ_B2000 0x0900 +#define DZ_B2400 0x0A00 +#define DZ_B3600 0x0B00 +#define DZ_B4800 0x0C00 +#define DZ_B7200 0x0D00 +#define DZ_B9600 0x0E00 + +#define DZ_CREAD 0x1000 /* Enable receiver */ +#define DZ_RXENAB 0x1000 /* enable receive char */ +/* + * Addresses for the DZ registers + */ +#define DZ_CSR 0x00 /* Control and Status Register */ +#define DZ_RBUF 0x08 /* Receive Buffer */ +#define DZ_LPR 0x08 /* Line Parameters Register */ +#define DZ_TCR 0x10 /* Transmitter Control Register */ +#define DZ_MSR 0x18 /* Modem Status Register */ +#define DZ_TDR 0x18 /* Transmit Data Register */ + + +#define DZ_NB_PORT 4 + +#define DZ_XMIT_SIZE 4096 /* buffer size */ +#define WAKEUP_CHARS DZ_XMIT_SIZE/4 + +#define DZ_EVENT_WRITE_WAKEUP 0 + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define DZ_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define DZ_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define DZ_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define DZ_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define DZ_CLOSING 0x08000000 /* Serial port is closing */ +#define DZ_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define DZ_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +#define DZ_CLOSING_WAIT_INF 0 +#define DZ_CLOSING_WAIT_NONE 65535 + +#define DZ_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ +#define DZ_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define DZ_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ + +struct dz_serial { + unsigned port; /* base address for the port */ + int type; + int flags; + int baud_base; + int blocked_open; + unsigned short close_delay; + unsigned short closing_wait; + unsigned short line; /* port/line number */ + unsigned short cflags; /* line configuration flag */ + unsigned short x_char; /* xon/xoff character */ + unsigned short read_status_mask; /* mask for read condition */ + unsigned short ignore_status_mask; /* mask for ignore condition */ + unsigned long event; /* mask used in BH */ + unsigned char *xmit_buf; /* Transmit buffer */ + int xmit_head; /* Position of the head */ + int xmit_tail; /* Position of the tail */ + int xmit_cnt; /* Count of the chars in the buffer */ + int count; /* indicates how many times it has been opened */ + int magic; + + struct async_icount icount; /* keep track of things ... */ + struct tty_struct *tty; /* tty associated */ + struct tq_struct tqueue; /* Queue for BH */ + struct tq_struct tqueue_hangup; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; + + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + + unsigned char is_console; /* flag indicating a serial console */ + unsigned char is_initialized; +}; + +static struct dz_serial multi[DZ_NB_PORT]; /* Four serial lines in the DZ chip */ +static struct dz_serial *dz_console; +static struct tty_driver serial_driver, callout_driver; + +static struct tty_struct *serial_table[DZ_NB_PORT]; +static struct termios *serial_termios[DZ_NB_PORT]; +static struct termios *serial_termios_locked[DZ_NB_PORT]; + +static int serial_refcount; + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +static struct semaphore tmp_buf_sem = MUTEX; + +static char *dz_name = "DECstation DZ serial driver version "; +static char *dz_version = "1.02"; + +static inline unsigned short dz_in (struct dz_serial *, unsigned); +static inline void dz_out (struct dz_serial *, unsigned, unsigned short); + +static inline void dz_sched_event (struct dz_serial *, int); +static inline void receive_chars (struct dz_serial *); +static inline void transmit_chars (struct dz_serial *); +static inline void check_modem_status (struct dz_serial *); + +static void dz_stop (struct tty_struct *); +static void dz_start (struct tty_struct *); +static void dz_interrupt (int, void *, struct pt_regs *); +static void do_serial_bh (void); +static void do_softint (void *); +static void do_serial_hangup (void *); +static void change_speed (struct dz_serial *); +static void dz_flush_chars (struct tty_struct *); +static void dz_console_print (struct console *, const char *, unsigned int); +static void dz_flush_buffer (struct tty_struct *); +static void dz_throttle (struct tty_struct *); +static void dz_unthrottle (struct tty_struct *); +static void dz_send_xchar (struct tty_struct *, char); +static void shutdown (struct dz_serial *); +static void send_break (struct dz_serial *, int); +static void dz_set_termios (struct tty_struct *, struct termios *); +static void dz_close (struct tty_struct *, struct file *); +static void dz_hangup (struct tty_struct *); +static void show_serial_version (void); + +static int dz_write (struct tty_struct *, int, const unsigned char *, int); +static int dz_write_room (struct tty_struct *); +static int dz_chars_in_buffer (struct tty_struct *); +static int startup (struct dz_serial *); +static int get_serial_info (struct dz_serial *, struct serial_struct *); +static int set_serial_info (struct dz_serial *, struct serial_struct *); +static int get_lsr_info (struct dz_serial *, unsigned int *); +static int dz_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long); +static int block_til_ready (struct tty_struct *, struct file *, struct dz_serial *); +static int dz_open (struct tty_struct *, struct file *); + +#ifdef MODULE +int init_module (void) +void cleanup_module (void) +#endif + +#endif + +#endif /* DZ_SERIAL_H */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.2.10/linux/drivers/char/generic_serial.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/generic_serial.c Mon Aug 9 12:05:09 1999 @@ -0,0 +1,1074 @@ +/* + * generic_serial.c + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Credit for the idea to do it this way might go to Alan Cox. + * + * + * Version 0.1 -- December, 1998. Initial version. + * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc. + * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus. + */ + +#include +#include +#include +#include +#include + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.2.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +/* Some 200 days (on intel) */ +#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL>>1)) + + +#ifndef MODULE + +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + + +/* Should be in a header somewhere. */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ +#endif + +#endif + +#ifndef TWO_ZERO +/* This include is new with 2.2 (and required!) */ +#include +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define waitq_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + +#include "generic_serial.h" + + +#ifndef MODULE +extern void my_hd (unsigned char *ptr, int n); +#endif + +static char * tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +int gs_debug = 0; + + +#ifdef DEBUG +#define gs_dprintk(f, str...) if (gs_debug & f) printk (str) +#else +#define gs_dprintk(f, str...) /* nothing */ +#endif + +#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n") +#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n") + + + +#if NEW_WRITE_LOCKING +#define DECL /* Nothing */ +#define LOCKIT down (& port->port_write_sem); +#define RELEASEIT up (&port->port_write_sem); +#else +#define DECL unsigned long flags; +#define LOCKIT save_flags (flags);cli () +#define RELEASEIT restore_flags (flags) +#endif + + + +void gs_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct gs_port *port = tty->driver_data; + DECL + + /* func_enter (); */ + + /* Take a lock on the serial tranmit buffer! */ + LOCKIT; + + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + /* Sorry, buffer is full, drop character. Update statistics???? -- REW */ + RELEASEIT; + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= SERIAL_XMIT_SIZE - 1; + port->xmit_cnt++; /* Characters in buffer */ + + RELEASEIT; + /* func_exit ();*/ +} + + +#ifdef NEW_WRITE_LOCKING + +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port = tty->driver_data; + int c, total = 0; + int t; + + /* func_enter (); */ + + if (! (port->flags & ASYNC_INITIALIZED)) + return 0; + + /* get exclusive "write" access to this port (problem 3) */ + /* This is not a spinlock because we can have a disk access (page + fault) in copy_from_user */ + down (& port->port_write_sem); + + while (1) { + + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + if (from_user) + copy_from_user (port->xmit_buf + port->xmit_head, buf, c); + else + memcpy (port->xmit_buf + port->xmit_head, buf, c); + + port -> xmit_cnt += c; + port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1); + buf += c; + count -= c; + total += c; + } + up (& port->port_write_sem); + + gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", + (port->flags & GS_TX_INTEN)?"enabled": "disabled"); + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + /* func_exit (); */ + return total; +} +#else +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port; + int c, total = 0; + int t; + unsigned long flags; + + func_enter (); + + /* The standard serial driver returns 0 in this case. + That sounds to me as "No error, I just didn't get to writing any + bytes. Feel free to try again." + The "official" way to write n bytes from buf is: + + for (nwritten = 0;nwritten < n;nwritten += rv) { + rv = write (fd, buf+nwritten, n-nwritten); + if (rv < 0) break; // Error: bail out. // + } + + which will loop endlessly in this case. The manual page for write + agrees with me. In practise almost everybody writes + "write (fd, buf,n);" but some people might have had to deal with + incomplete writes in the past and correctly implemented it by now... + */ + + if (!tty) return -EIO; + + port = tty->driver_data; + if (!port || !port->xmit_buf || !tmp_buf) + return -EIO; + + /* printk ("from_user = %d.\n", from_user); */ + save_flags(flags); + if (from_user) { + /* printk ("Going into the semaphore\n"); */ + down(&tmp_buf_sem); + /* printk ("got out of the semaphore\n"); */ + while (1) { + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + cli(); + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(port->xmit_buf + port->xmit_head, buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + } + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); + return total; +} + +#endif + + + +int gs_write_room(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + int ret; + + /* func_enter (); */ + ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (ret < 0) + ret = 0; + /* func_exit (); */ + return ret; +} + + +int gs_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + func_exit (); + return port->xmit_cnt; +} + + +int gs_real_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + if (!tty) return 0; + port = tty->driver_data; + + func_exit (); + return port->xmit_cnt + port->rd->chars_in_buffer (port); +} + + +static void gs_wait_tx_flushed (void * ptr, int timeout) +{ + struct gs_port *port = ptr; + long end_jiffies; + int jiffies_to_transmit, charsleft; + int to, rcib; + + func_enter(); + + gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port); + if (port) { + gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", + port->xmit_cnt, port->xmit_buf, port->tty); + } + + if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { + gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n"); + func_exit(); + return; /* This is an error which we don't know how to handle. */ + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n"); + + rcib = gs_real_chars_in_buffer(port->tty); + + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 2\n"); + + if(rcib <= 0) { + gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n"); + func_exit(); + return; + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n"); + + /* stop trying: now + twice the time it would normally take + seconds */ + end_jiffies = jiffies; + if (timeout != MAX_SCHEDULE_TIMEOUT) + end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0; + end_jiffies += timeout; + + gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", + jiffies, end_jiffies, end_jiffies-jiffies); + + to = 100; + /* the expression is actually jiffies < end_jiffies, but that won't + work around the wraparound. Tricky eh? */ + while (to-- && + (charsleft = gs_real_chars_in_buffer (port->tty)) && + time_after (end_jiffies, jiffies)) { + /* Units check: + chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! + check! */ + + charsleft += 16; /* Allow 16 chars more to be transmitted ... */ + jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0; + /* ^^^ Round up.... */ + if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1; + + gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies " + "(%d chars).\n", jiffies_to_transmit, charsleft); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(jiffies_to_transmit); + if (signal_pending (current)) + break; + } + + gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); + current->state = TASK_RUNNING; + + func_exit(); +} + + + +void gs_flush_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + + func_enter (); + /* XXX Would the write semaphore do? */ + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + func_exit (); +} + + +void gs_flush_chars(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) { + func_exit (); + return; + } + + /* Beats me -- REW */ + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + func_exit (); +} + + +void gs_stop(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt && + port->xmit_buf && + (port->flags & GS_TX_INTEN) ) { + port->flags &= ~GS_TX_INTEN; + port->rd->disable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_start(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + if (port->xmit_cnt && + port->xmit_buf && + !(port->flags & GS_TX_INTEN) ) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_shutdown_port (struct gs_port *port) +{ + long flags; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + + save_flags (flags); + cli (); + + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = 0; + } + + if (port->tty) + set_bit(TTY_IO_ERROR, &port->tty->flags); + + port->rd->shutdown_port (port); + + port->flags &= ~ASYNC_INITIALIZED; + restore_flags (flags); +} + + +void gs_hangup(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + + tty = port->tty; + if (!tty) return; + + gs_shutdown_port (port); + + /* gs_flush_buffer (tty); */ + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE); + port->tty = NULL; + port->count = 0; + + wake_up_interruptible(&port->open_wait); + func_exit (); +} + + +void gs_do_softint(void *private_) +{ + struct gs_port *port = private_; + struct tty_struct *tty; + + tty = port->tty; + if(!tty) return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + func_exit (); +} + + +int block_til_ready(void *port_, struct file * filp) +{ + struct gs_port *port = port_; + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + int CD; + struct tty_struct *tty; + + func_enter (); + tty = port->tty; + + gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == GS_TYPE_CALLOUT) { + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } + + gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + + gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; + while (1) { + CD = port->rd->get_CD (port); + gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || CD)) + break; + gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", + (int)signal_pending (current), *(long*)(¤t->blocked)); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", + port->blocked_open); + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + + port->flags |= ASYNC_NORMAL_ACTIVE; + func_exit (); + return 0; +} + + +void gs_close(struct tty_struct * tty, struct file * filp) +{ + unsigned long flags; + struct gs_port *port; + + func_enter (); + port = (struct gs_port *) tty->driver_data; + + gs_dprintk (GS_DEBUG_CLOSE, "tty=%p, port=%p port->tty=%p\n", + tty, port, port->tty); + + if(! port) { + func_exit(); + return; + } + if (!port->tty) { + printk (KERN_WARNING "gs: Odd: port->tty is NULL\n"); + port->tty = tty; + } + + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + port->rd->hungup (port); + func_exit (); + return; + } + + if ((tty->count == 1) && (port->count != 1)) { + printk(KERN_ERR "gs: gs_close: bad port count;" + " tty->count is 1, port count is %d\n", port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count); + port->count = 0; + } + if (port->count) { + restore_flags(flags); + func_exit (); + return; + } + port->flags |= ASYNC_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + /* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); */ + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + port->rd->disable_rx_interrupts (port); + + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + gs_wait_tx_flushed (port, port->closing_wait); + + port->flags &= ~GS_ACTIVE; + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING | ASYNC_INITIALIZED); + wake_up_interruptible(&port->close_wait); + + port->rd->close (port); + port->rd->shutdown_port (port); + restore_flags(flags); + func_exit (); +} + + +static unsigned int gs_baudrates[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; + + +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios) +{ + struct gs_port *port = tty->driver_data; + int baudrate, tmp; + struct termios *tiosp; + + func_enter(); + + tiosp = tty->termios; + + + if (gs_debug & GS_DEBUG_TERMIOS) { + gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); + my_hd ((unsigned char *)tiosp, sizeof (struct termios)); + } + +#if 0 + /* This is an optimization that is only allowed for dumb cards */ + /* Smart cards require knowledge of iflags and oflags too: that + might change hardware cooking mode.... */ +#endif + if (old_termios) { + if( (tiosp->c_iflag == old_termios->c_iflag) + && (tiosp->c_oflag == old_termios->c_oflag) + && (tiosp->c_cflag == old_termios->c_cflag) + && (tiosp->c_lflag == old_termios->c_lflag) + && (tiosp->c_line == old_termios->c_line) + && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) { + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n"); + return; + } + } else + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: " + "no optimization\n"); + + if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) { + if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n"); + if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n"); + if(tiosp->c_cflag != old_termios->c_cflag) printk("c_cflag changed\n"); + if(tiosp->c_lflag != old_termios->c_lflag) printk("c_lflag changed\n"); + if(tiosp->c_line != old_termios->c_line) printk("c_line changed\n"); + if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); + } + + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + + baudrate = gs_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (port->baud_base / port->custom_divisor); + } + + /* I recommend using THIS instead of the mess in termios (and + duplicating the above code). Next we should create a clean + interface towards this variable. If your card supports arbitrary + baud rates, (e.g. CD1400 or 16550 based cards) then everything + will be very easy..... */ + port->baud = baudrate; + + /* Two timer ticks seems enough to wakeup something like SLIP driver */ + /* Baudrate/10 is cps. Divide by HZ to get chars per tick. */ + tmp = (baudrate / 10 / HZ) * 2; + + if (tmp < 0) tmp = 0; + if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1; + + port->wakeup_chars = tmp; + + /* We should really wait for the characters to be all sent before + changing the settings. -- CAL */ + gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT); + + port->rd->set_real_termios(port); + + if ((!old_termios || + (old_termios->c_cflag & CRTSCTS)) && + !( tiosp->c_cflag & CRTSCTS)) { + tty->stopped = 0; + gs_start(tty); + } + +#ifdef tytso_patch_94Nov25_1726 + /* This "makes sense", Why is it commented out? */ + + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif + + func_exit(); + return; +} + + + +/* Must be called with interrupts enabled */ +int gs_init_port(struct gs_port *port) +{ + unsigned long flags; + unsigned long page; + + save_flags (flags); + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + + cli (); /* Don't expect this to make a difference. */ + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + restore_flags (flags); + + if (!tmp_buf) { + return -ENOMEM; + } + } + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + if (!port->xmit_buf) { + /* We may sleep in get_free_page() */ + unsigned long tmp; + + tmp = get_free_page(GFP_KERNEL); + + /* Spinlock? */ + cli (); + if (port->xmit_buf) + free_page (tmp); + else + port->xmit_buf = (unsigned char *) tmp; + restore_flags (flags); + + if (!port->xmit_buf) + return -ENOMEM; + } + + cli(); + + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + gs_set_termios(port->tty, NULL); + + port->flags |= ASYNC_INITIALIZED; + port->flags &= ~GS_TX_INTEN; + + restore_flags(flags); + return 0; +} + + +int gs_setserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + copy_from_user(&sio, sp, sizeof(struct serial_struct)); + + if (!capable(CAP_SYS_ADMIN)) { + if ((sio.baud_base != port->baud_base) || + (sio.close_delay != port->close_delay) || + ((sio.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return(-EPERM); + } + + port->flags = (port->flags & ~ASYNC_USR_MASK) | + (sio.flags & ASYNC_USR_MASK); + + port->baud_base = sio.baud_base; + port->close_delay = sio.close_delay; + port->closing_wait = sio.closing_wait; + port->custom_divisor = sio.custom_divisor; + + gs_set_termios (port->tty, NULL); + + return 0; +} + + +/*****************************************************************************/ + +/* + * Generate the serial struct info. + */ + +void gs_getserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + memset(&sio, 0, sizeof(struct serial_struct)); + sio.flags = port->flags; + sio.baud_base = port->baud_base; + sio.close_delay = port->close_delay; + sio.closing_wait = port->closing_wait; + sio.custom_divisor = port->custom_divisor; + sio.hub6 = 0; + + /* If you want you can override these. */ + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = -1; + sio.line = -1; + sio.port = -1; + sio.irq = -1; + + if (port->rd->getserial) + port->rd->getserial (port, &sio); + + copy_to_user(sp, &sio, sizeof(struct serial_struct)); +} + diff -u --recursive --new-file v2.2.10/linux/drivers/char/generic_serial.h linux/drivers/char/generic_serial.h --- v2.2.10/linux/drivers/char/generic_serial.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/generic_serial.h Mon Aug 9 12:05:09 1999 @@ -0,0 +1,101 @@ +/* + * generic_serial.h + * + * Copyright (C) 1998 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Version 0.1 -- December, 1998. + */ + +#ifndef GENERIC_SERIAL_H +#define GENERIC_SERIAL_H + +struct real_driver { + void (*disable_tx_interrupts) (void *); + void (*enable_tx_interrupts) (void *); + void (*disable_rx_interrupts) (void *); + void (*enable_rx_interrupts) (void *); + int (*get_CD) (void *); + void (*shutdown_port) (void*); + void (*set_real_termios) (void*); + int (*chars_in_buffer) (void*); + void (*close) (void*); + void (*hungup) (void*); + void (*getserial) (void*, struct serial_struct *sp); +}; + + + +struct gs_port { + int magic; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + /* struct semaphore port_write_sem; */ + int flags; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + long session; + long pgrp; + int count; + int blocked_open; + struct tty_struct *tty; + int event; + unsigned short closing_wait; + int close_delay; + struct real_driver *rd; + int wakeup_chars; + int baud_base; + int baud; + int custom_divisor; +}; + + +/* Flags */ +/* Warning: serial.h defines some ASYNC_ flags, they say they are "only" + used in serial.c, but they are also used in all other serial drivers. + Make sure they don't clash with these here... */ +#define GS_TX_INTEN 0x00800000 +#define GS_RX_INTEN 0x00400000 +#define GS_ACTIVE 0x00200000 + + + +#define GS_TYPE_NORMAL 1 +#define GS_TYPE_CALLOUT 2 + + +#define GS_DEBUG_FLUSH 0x00000001 +#define GS_DEBUG_BTR 0x00000002 +#define GS_DEBUG_TERMIOS 0x00000004 +#define GS_DEBUG_STUFF 0x00000008 +#define GS_DEBUG_CLOSE 0x00000010 + + +void gs_put_char(struct tty_struct *tty, unsigned char ch); +int gs_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count); +int gs_write_room(struct tty_struct *tty); +int gs_chars_in_buffer(struct tty_struct *tty); +void gs_flush_buffer(struct tty_struct *tty); +void gs_flush_chars(struct tty_struct *tty); +void gs_stop(struct tty_struct *tty); +void gs_start(struct tty_struct *tty); +void gs_hangup(struct tty_struct *tty); +void gs_do_softint(void *private_); +int block_til_ready(void *port, struct file *filp); +void gs_close(struct tty_struct *tty, struct file *filp); +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios); +int gs_init_port(struct gs_port *port); +int gs_setserial(struct gs_port *port, struct serial_struct *sp); +void gs_getserial(struct gs_port *port, struct serial_struct *sp); + +extern int gs_debug; + +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.2.10/linux/drivers/char/isicom.c Fri May 7 11:05:30 1999 +++ linux/drivers/char/isicom.c Mon Aug 9 12:04:39 1999 @@ -14,7 +14,8 @@ * Printk clean up * 9/12/98 alan@redhat.com Rough port to 2.1.x * - * + * 10/6/99 sameer Merged the ISA and PCI drivers to + * a new unified driver. * *********************************************************** * * To use this driver you also need the support package. You @@ -51,8 +52,21 @@ #include #include +#include + #include +static int device_id[] = { 0x2028, + 0x2051, + 0x2052, + 0x2053, + 0x2054, + 0x2055, + 0x2056, + 0x2057, + 0x2058 + }; + static int isicom_refcount = 0; static int prev_card = 3; /* start servicing isi_card[0] */ static struct isi_board * irq_to_board[16] = { NULL, }; @@ -147,7 +161,7 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - unsigned int card, i, j, signature, status; + unsigned int card, i, j, signature, status, portcount = 0; unsigned short word_count, base; bin_frame frame; /* exec_record exec_rec; */ @@ -180,19 +194,38 @@ printk("."); } signature=(inw(base+0x4)) & 0xff; - - if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { + if (isi_card[card].isa) { + + if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { #ifdef ISICOM_DEBUG - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); #endif - printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); - return -EIO; - } - + printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + } + else { + portcount = inw(base+0x2); + if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) { +#ifdef ISICOM_DEBUG + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); +#endif + printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + } switch(signature) { case 0xa5: case 0xbb: - case 0xdd: isi_card[card].port_count = 8; + case 0xdd: + if (isi_card[card].isa) + isi_card[card].port_count = 8; + else { + if (portcount == 4) + isi_card[card].port_count = 4; + else + isi_card[card].port_count = 8; + } isi_card[card].shift_count = 12; break; @@ -310,7 +343,8 @@ outw(0x0, base); outw(0x0, base); InterruptTheCard(base); - + outw(0x0, base+0x4); /* for ISI4608 cards */ + isi_card[card].status |= FIRMWARE_LOADED; return 0; @@ -455,28 +489,7 @@ txcount--; } } -/* - * Replaced the code below with hopefully a faster loop - sameer - */ -/* - while (1) { - wrd = port->xmit_buf[port->xmit_tail++]; - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - if (--txcount > 0) { - wrd |= (port->xmit_buf[port->xmit_tail++] << 8); - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - outw(wrd, base); - if (--txcount <= 0) break; - } - else { - outw(wrd, base); - break; - } - } -*/ InterruptTheCard(base); if (port->xmit_cnt <= 0) port->status &= ~ISI_TXOK; @@ -531,12 +544,34 @@ unsigned char channel; short byte_count; - card = irq_to_board[irq]; + /* + * find the source of interrupt + */ + + for(count = 0; count < BOARD_COUNT; count++) { + card = &isi_card[count]; + if (card->base != 0) { + if (((card->isa == YES) && (card->irq == irq)) || + ((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02))) + break; + } + card = NULL; + } + if (!card || !(card->status & FIRMWARE_LOADED)) { - printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq); +/* printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/ return; } + base = card->base; + if (card->isa == NO) { + /* + * disable any interrupts from the PCI card and lower the + * interrupt line + */ + outw(0x8000, base+0x04); + ClearInterrupt(base); + } inw(base); /* get the dummy word out */ header = inw(base); @@ -548,12 +583,18 @@ if ((channel+1) > card->port_count) { printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", base, channel+1); - ClearInterrupt(base); + if (card->isa) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } port = card->ports + channel; if (!(port->flags & ASYNC_INITIALIZED)) { - ClearInterrupt(base); + if (card->isa) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } @@ -681,7 +722,10 @@ } queue_task(&tty->flip.tqueue, &tq_timer); } - ClearInterrupt(base); + if (card->isa == YES) + ClearInterrupt(base); + else + outw(0x0000, base+0x04); /* enable interrupts */ return; } @@ -1023,12 +1067,11 @@ return -ENODEV; } - /* open on higher 8 dev files on a 8 port card !!! */ - if (card->port_count == 8) - if (line > ((board * 16)+7)) { - printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n"); - return -ENODEV; - } + /* open on a port greater than the port count for the card !!! */ + if (line > ((board * 16) + card->port_count - 1)) { + printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n"); + return -ENODEV; + } port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->device, "isicom_open")) return -ENODEV; @@ -1764,21 +1807,42 @@ static int register_isr(void) { - int count, done=0; + int count, done=0, card; + unsigned char request; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { - if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { - printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", - isi_card[count].irq, count+1); + /* + * verify if the required irq has already been requested for + * another ISI Card, if so we already have it, else request it + */ + request = YES; + for(card = 0; card < count; card++) + if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + request = NO; + if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO)) + break; + /* + * ISA cards cannot share interrupts with other + * PCI or ISA devices hence disable this card. + */ release_region(isi_card[count].base,16); - isi_card[count].base=0; + isi_card[count].base = 0; + break; } - else { - printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", - count+1, isi_card[count].base, isi_card[count].irq); - - irq_to_board[isi_card[count].irq]=&isi_card[count]; - done++; + if (request == YES) { + if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { + printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); + isi_card[count].base=0; + } + else { + printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", + count+1, isi_card[count].base, isi_card[count].irq); + + irq_to_board[isi_card[count].irq]=&isi_card[count]; + done++; + } } } } @@ -1787,14 +1851,24 @@ static void unregister_isr(void) { - int count; - for (count=0; count < BOARD_COUNT; count++ ) + int count, card; + unsigned char freeirq; + for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { - free_irq(isi_card[count].irq, NULL); + freeirq = YES; + for(card = 0; card < count; card++) + if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + freeirq = NO; + break; + } + if (freeirq == YES) { + free_irq(isi_card[count].irq, NULL); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); -#endif + printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); +#endif + } } + } } static int isicom_init(void) @@ -1882,28 +1956,74 @@ int init_module(void) { - int retval, card; - - for(card=0; card < BOARD_COUNT; card++) - { - isi_card[card].base=io[card]; - isi_card[card].irq=irq[card]; - } - - for (card=0 ;card < BOARD_COUNT; card++) { - if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)|| - (isi_card[card].irq==4)||(isi_card[card].irq==5)|| - (isi_card[card].irq==7)||(isi_card[card].irq==10)|| - (isi_card[card].irq==11)||(isi_card[card].irq==12)|| - (isi_card[card].irq==15))) { + struct pci_dev *dev = NULL; + int retval, card, idx, count; + unsigned char pciirq; + unsigned int ioaddr; + + card = 0; + for(idx=0; idx < BOARD_COUNT; idx++) { + if (io[idx]) { + isi_card[idx].base=io[idx]; + isi_card[idx].irq=irq[idx]; + isi_card[idx].isa=YES; + card++; + } + else { + isi_card[idx].base = 0; + isi_card[idx].irq = 0; + } + } + + for (idx=0 ;idx < card; idx++) { + if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)|| + (isi_card[idx].irq==4)||(isi_card[idx].irq==5)|| + (isi_card[idx].irq==7)||(isi_card[idx].irq==10)|| + (isi_card[idx].irq==11)||(isi_card[idx].irq==12)|| + (isi_card[idx].irq==15))) { - if (isi_card[card].base) { + if (isi_card[idx].base) { printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", - isi_card[card].irq, card+1); - isi_card[card].base=0; + isi_card[idx].irq, idx+1); + isi_card[idx].base=0; + card--; } } } + + if (pci_present() && (card < BOARD_COUNT)) { + for (idx=0; idx < DEVID_COUNT; idx++) { + dev = NULL; + for (;;){ + if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) + break; + if (card >= BOARD_COUNT) + break; + + /* found a PCI ISI card! */ + ioaddr = dev->base_address[3]; /* i.e at offset 0x1c in the + * PCI configuration register + * space. + */ + ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + pciirq = dev->irq; + printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); + /* + * allot the first empty slot in the array + */ + for (count=0; count < BOARD_COUNT; count++) { + if (isi_card[count].base == 0) { + isi_card[count].base = ioaddr; + isi_card[count].irq = pciirq; + isi_card[count].isa = NO; + card++; + break; + } + } + } + if (card >= BOARD_COUNT) break; + } + } if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); diff -u --recursive --new-file v2.2.10/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.2.10/linux/drivers/char/keyboard.c Mon Apr 26 13:21:42 1999 +++ linux/drivers/char/keyboard.c Mon Aug 9 12:05:01 1999 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -247,7 +248,7 @@ sysrq_pressed = !up_flag; return; } else if (sysrq_pressed) { - if (!up_flag) + if (!up_flag && sysrq_enabled) handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); return; } @@ -321,15 +322,31 @@ } } +#ifdef CONFIG_FORWARD_KEYBOARD +extern int forward_chars; void put_queue(int ch) { + if (forward_chars == fg_console+1){ + kbd_forward_char (ch); + } else { + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } + } +} +#else +void put_queue(int ch) +{ wake_up(&keypress_wait); if (tty) { tty_insert_flip_char(tty, ch, 0); con_schedule_flip(tty); } } +#endif static void puts_queue(char *cp) { diff -u --recursive --new-file v2.2.10/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.2.10/linux/drivers/char/mem.c Mon May 10 10:18:34 1999 +++ linux/drivers/char/mem.c Mon Aug 9 12:04:57 1999 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -464,11 +465,19 @@ } } +static int open_port(struct inode * inode, struct file * filp) +{ + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +} + + #define mmap_kmem mmap_mem #define zero_lseek null_lseek #define full_lseek null_lseek #define write_zero write_null #define read_full read_zero +#define open_mem open_port /* different capability? */ +#define open_kmem open_mem static struct file_operations mem_fops = { memory_lseek, @@ -478,7 +487,7 @@ NULL, /* mem_poll */ NULL, /* mem_ioctl */ mmap_mem, - NULL, /* no special open code */ + open_mem, NULL, /* flush */ NULL, /* no special release code */ NULL /* fsync */ @@ -492,7 +501,7 @@ NULL, /* kmem_poll */ NULL, /* kmem_ioctl */ mmap_kmem, - NULL, /* no special open code */ + open_kmem, NULL, /* flush */ NULL, /* no special release code */ NULL /* fsync */ @@ -520,7 +529,7 @@ NULL, /* port_poll */ NULL, /* port_ioctl */ NULL, /* port_mmap */ - NULL, /* no special open code */ + open_port, NULL, /* flush */ NULL, /* no special release code */ NULL /* fsync */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.2.10/linux/drivers/char/misc.c Fri Mar 26 13:57:41 1999 +++ linux/drivers/char/misc.c Mon Aug 9 12:04:39 1999 @@ -268,6 +268,12 @@ #ifdef CONFIG_PMAC_PBOOK pmu_device_init(); #endif +#ifdef CONFIG_SGI_NEWPORT_GFX + gfx_register (); +#endif +#ifdef CONFIG_SGI + streamable_init (); +#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff -u --recursive --new-file v2.2.10/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.2.10/linux/drivers/char/pc_keyb.c Mon Apr 26 13:43:01 1999 +++ linux/drivers/char/pc_keyb.c Mon Aug 9 12:04:39 1999 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -34,15 +33,13 @@ #include #include -#include #include #include #include -#include /* Some configuration switches are present in the include file... */ -#include "pc_keyb.h" +#include /* Simple translation table for the SysRq keys */ @@ -57,10 +54,11 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -static void kbd_write(int address, int data); -static unsigned char handle_kbd_event(void); +static void kbd_write_command_w(int data); +static void kbd_write_output_w(int data); spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char handle_kbd_event(void); /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; @@ -84,11 +82,6 @@ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) #define MAX_RETRIES 60 /* some aux operations take long time*/ - -#ifndef AUX_IRQ -# define AUX_IRQ 12 -#endif - #endif /* CONFIG_PSMOUSE */ /* @@ -426,13 +419,13 @@ */ static unsigned char handle_kbd_event(void) { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); + unsigned int work = 10000; while (status & KBD_STAT_OBF) { unsigned char scancode; - scancode = inb(KBD_DATA_REG); - + scancode = kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { handle_mouse_event(scancode); } else { @@ -441,7 +434,14 @@ mark_bh(KEYBOARD_BH); } - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); + + if(!work--) + { + printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", + status); + break; + } } return status; @@ -476,7 +476,7 @@ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ resend = 0; reply_expected = 1; - kbd_write(KBD_DATA_REG, data); + kbd_write_output_w(data); for (;;) { if (acknowledge) return 1; @@ -527,14 +527,14 @@ #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ -static int __init kbd_read_input(void) +static int __init kbd_read_data(void) { int retval = KBD_NO_DATA; unsigned char status; - status = inb(KBD_STATUS_REG); + status = kbd_read_status(); if (status & KBD_STAT_OBF) { - unsigned char data = inb(KBD_DATA_REG); + unsigned char data = kbd_read_input(); retval = data; if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) @@ -548,7 +548,7 @@ int maxread = 100; /* Random number */ do { - if (kbd_read_input() == KBD_NO_DATA) + if (kbd_read_data() == KBD_NO_DATA) break; } while (--maxread); } @@ -558,7 +558,7 @@ long timeout = KBD_INIT_TIMEOUT; do { - int retval = kbd_read_input(); + int retval = kbd_read_data(); if (retval >= 0) return retval; mdelay(1); @@ -566,13 +566,23 @@ return -1; } -static void kbd_write(int address, int data) +static void kbd_write_command_w(int data) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(data); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static void kbd_write_output_w(int data) { unsigned long flags; spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(data, address); + kbd_write_output(data); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -583,9 +593,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MODE); kb_wait(); - outb(cmd, KBD_DATA_REG); + kbd_write_output(cmd); spin_unlock_irqrestore(&kbd_controller_lock, flags); } #endif /* CONFIG_PSMOUSE */ @@ -599,7 +609,7 @@ * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); + kbd_write_command_w(KBD_CCMD_SELF_TEST); if (kbd_wait_for_input() != 0x55) return "Keyboard failed self test"; @@ -608,14 +618,14 @@ * to test the keyboard clock and data lines. The results of the * test are placed in the input buffer. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); + kbd_write_command_w(KBD_CCMD_KBD_TEST); if (kbd_wait_for_input() != 0x00) return "Keyboard interface failed self test"; /* * Enable the keyboard by allowing the keyboard clock to run. */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); /* * Reset keyboard. If the read times out @@ -626,7 +636,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_RESET); + kbd_write_output_w(KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -644,7 +654,7 @@ * Set up to try again if the keyboard asks for RESEND. */ do { - kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); + kbd_write_output_w(KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; @@ -652,37 +662,37 @@ return "Disable keyboard: no ACK"; } while (1); - kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); - kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT + kbd_write_command_w(KBD_CCMD_WRITE_MODE); + kbd_write_output_w(KBD_MODE_KBD_INT | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC); /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); + kbd_write_command_w(KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ - kbd_write(KBD_DATA_REG, 0xF0); + kbd_write_output_w(0xF0); kbd_wait_for_input(); - kbd_write(KBD_DATA_REG, 0x01); + kbd_write_output_w(0x01); kbd_wait_for_input(); } - kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); + kbd_write_output_w(KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Enable keyboard: no ACK"; /* * Finally, set the typematic rate to maximum. */ - kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); + kbd_write_output_w(KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; - kbd_write(KBD_DATA_REG, 0x00); + kbd_write_output_w(0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) return "Set rate: no ACK"; @@ -691,8 +701,7 @@ void __init pckbd_init_hw(void) { - /* Get the keyboard controller registers (incomplete decode) */ - request_region(0x60, 16, "keyboard"); + kbd_request_region(); /* Flush any pending input. */ kbd_clear_input(); @@ -708,7 +717,7 @@ #endif /* Ok, finally allocate the IRQ, and off we go.. */ - request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); + kbd_request_irq(keyboard_interrupt); } #if defined CONFIG_PSMOUSE @@ -732,16 +741,16 @@ * controller has an Auxiliary Port (a.k.a. Mouse Port). */ kb_wait(); - outb(KBD_CCMD_WRITE_AUX_OBUF, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); kb_wait(); - outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */ + kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ do { - unsigned char status = inb(KBD_STATUS_REG); + unsigned char status = kbd_read_status(); if (status & KBD_STAT_OBF) { - (void) inb(KBD_DATA_REG); + (void) kbd_read_input(); if (status & KBD_STAT_MOUSE_OBF) { printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); retval = 1; @@ -764,9 +773,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); spin_unlock_irqrestore(&kbd_controller_lock, flags); } @@ -779,9 +788,9 @@ spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); - outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); kb_wait(); - outb(val, KBD_DATA_REG); + kbd_write_output(val); /* we expect an ACK in response. */ mouse_reply_expected++; kb_wait(); @@ -828,8 +837,8 @@ if (--aux_count) return 0; kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); - free_irq(AUX_IRQ, AUX_DEV); + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + aux_free_irq(AUX_DEV); return 0; } @@ -844,11 +853,11 @@ return 0; } queue->head = queue->tail = 0; /* Flush input queue */ - if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { + if (aux_request_irq(keyboard_interrupt, AUX_DEV)) { aux_count--; return -EBUSY; } - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ @@ -967,14 +976,14 @@ queue->proc_list = NULL; #ifdef INITIALIZE_MOUSE - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ aux_write_ack(AUX_SET_SAMPLE); aux_write_ack(100); /* 100 samples/sec */ aux_write_ack(AUX_SET_RES); aux_write_ack(3); /* 8 counts per mm */ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ #endif /* INITIALIZE_MOUSE */ - kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ return 0; diff -u --recursive --new-file v2.2.10/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h --- v2.2.10/linux/drivers/char/pc_keyb.h Sat Feb 6 12:46:20 1999 +++ linux/drivers/char/pc_keyb.h Wed Dec 31 16:00:00 1969 @@ -1,130 +0,0 @@ -/* - * linux/drivers/char/pc_keyb.h - * - * PC Keyboard And Keyboard Controller - * - * (c) 1997 Martin Mares - */ - -/* - * Configuration Switches - */ - -#undef KBD_REPORT_ERR /* Report keyboard errors */ -#define KBD_REPORT_UNKN /* Report unknown scan codes */ -#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ -#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ -#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ - - - -#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ -#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ -#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ - -/* - * Internal variables of the driver - */ - -extern unsigned char pckbd_read_mask; -extern unsigned char aux_device_present; - -/* - * Keyboard Controller Registers - */ - -#define KBD_STATUS_REG 0x64 /* Status register (R) */ -#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ -#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ - -/* - * Keyboard Controller Commands - */ - -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ - -/* - * Keyboard Commands - */ - -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* - * Keyboard Replies - */ - -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* - * Status Register Bits - */ - -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) - -/* - * Controller Mode Register Bits - */ - -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* - * Mouse Commands - */ - -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define AUX_BUF_SIZE 2048 /* This might be better divisible by - three to make overruns stay in sync - but then the read function would need - a lock etc - ick */ - -struct aux_queue { - unsigned long head; - unsigned long tail; - struct wait_queue *proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; diff -u --recursive --new-file v2.2.10/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.2.10/linux/drivers/char/qpmouse.c Sat Oct 31 10:43:36 1998 +++ linux/drivers/char/qpmouse.c Mon Aug 9 12:04:39 1999 @@ -42,7 +42,7 @@ #include #include -#include "pc_keyb.h" /* mouse enable command.. */ +#include /* mouse enable command.. */ /* diff -u --recursive --new-file v2.2.10/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c --- v2.2.10/linux/drivers/char/radio-cadet.c Mon Jun 7 16:18:17 1999 +++ linux/drivers/char/radio-cadet.c Mon Aug 9 12:04:39 1999 @@ -1,7 +1,7 @@ -/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card +/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card * * by Fred Gleason - * Version 0.3.2 + * Version 0.3.3 * * (Loosely) based on code for the Aztech radio card by * @@ -346,17 +346,13 @@ static long cadet_read(struct video_device *v,char *buf,unsigned long count, int nonblock) { - int i=0,c; + int i=0; unsigned char readbuf[RDS_BUFFER]; if(rdsstat==0) { cadet_lock++; rdsstat=1; outb(0x80,io); /* Select RDS fifo */ - c=3*(inb(io)&0x03); - for(i=0;iflags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) +#define IRQ_T(state) \ + ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) #define SERIAL_INLINE @@ -1003,7 +1004,7 @@ } else handler = rs_interrupt_single; - retval = request_irq(state->irq, handler, IRQ_T(info), + retval = request_irq(state->irq, handler, IRQ_T(state), "serial", NULL); if (retval) { if (capable(CAP_SYS_ADMIN)) { @@ -1168,7 +1169,7 @@ if (IRQ_ports[state->irq]) { free_irq(state->irq, NULL); retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(info), "serial", NULL); + IRQ_T(state), "serial", NULL); if (retval) printk("serial shutdown: request_irq: error %d" @@ -2017,7 +2018,7 @@ else handler = rs_interrupt; - retval = request_irq(state->irq, handler, IRQ_T(info), + retval = request_irq(state->irq, handler, IRQ_T(state), "serial", NULL); if (retval) { printk("Couldn't reallocate serial interrupt " diff -u --recursive --new-file v2.2.10/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.2.10/linux/drivers/char/sx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sx.c Mon Aug 9 12:05:09 1999 @@ -0,0 +1,2684 @@ + +/* sx.c -- driver for the Specialix SX series cards. + * + * This driver will also support the older SI, and XIO cards. + * + * + * (C) 1998 R.E.Wolff@BitWizard.nl + * + * Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous + * version of this driver. Some fragments may have been copied. (none + * yet :-) + * + * Specialix pays for the development and support of this driver. + * Please DO contact support@specialix.co.uk if you require + * support. But please read the documentation (sx.txt) first. + * + * + * + * 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. + * + * Revision history: + * $Log: sx.c,v $ + * Revision 1.26 1999/08/05 15:22:14 wolff + * - Port to 2.3.x + * - Reformatted to Linus' liking. + * + * Revision 1.25 1999/07/30 14:24:08 wolff + * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0). + * + * Revision 1.24 1999/07/28 09:41:52 wolff + * - I noticed the remark about use-count straying in sx.txt. I checked + * sx_open, and found a few places where that could happen. I hope it's + * fixed now. + * + * Revision 1.23 1999/07/28 08:56:06 wolff + * - Fixed crash when sx_firmware run twice. + * - Added sx_slowpoll as a module parameter (I guess nobody really wanted + * to change it from the default... ) + * - Fixed a stupid editing problem I introduced in 1.22. + * - Fixed dropping characters on a termios change. + * + * Revision 1.22 1999/07/26 21:01:43 wolff + * Russell Brown noticed that I had overlooked 4 out of six modem control + * signals in sx_getsignals. Ooops. + * + * Revision 1.21 1999/07/23 09:11:33 wolff + * I forgot to free dynamically allocated memory when the driver is unloaded. + * + * Revision 1.20 1999/07/20 06:25:26 wolff + * The "closing wait" wasn't honoured. Thanks to James Griffiths for + * reporting this. + * + * Revision 1.19 1999/07/11 08:59:59 wolff + * Fixed an oops in close, when an open was pending. Changed the memtest + * a bit. Should also test the board in word-mode, however my card fails the + * memtest then. I still have to figure out what is wrong... + * + * Revision 1.18 1999/06/10 09:38:42 wolff + * Changed the format of the firmware revision from %04x to %x.%02x . + * + * Revision 1.17 1999/06/04 09:44:35 wolff + * fixed problem: reference to pci stuff when config_pci was off... + * Thanks to Jorge Novo for noticing this. + * + * Revision 1.16 1999/06/02 08:30:15 wolff + * added/removed the workaround for the DCD bug in the Firmware. + * A bit more debugging code to locate that... + * + * Revision 1.15 1999/06/01 11:35:30 wolff + * when DCD is left low (floating?), on TA's the firmware first tells us + * that DCD is high, but after a short while suddenly comes to the + * conclusion that it is low. All this would be fine, if it weren't that + * Unix requires us to send a "hangup" signal in that case. This usually + * all happens BEFORE the program has had a chance to ioctl the device + * into clocal mode.. + * + * Revision 1.14 1999/05/25 11:18:59 wolff + * Added PCI-fix. + * Added checks for return code of sx_sendcommand. + * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...) + * + * Revision 1.13 1999/04/29 15:18:01 wolff + * Fixed an "oops" that showed on SuSE 6.0 systems. + * Activate DTR again after stty 0. + * + * Revision 1.12 1999/04/29 07:49:52 wolff + * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming + * the connection would be dropped anyway. That is not always the case, + * and confuses people). + * Told the card to always monitor the modem signals. + * Added support for dynamic gs_debug adjustments. + * Now tells the rest of the system the number of ports. + * + * Revision 1.11 1999/04/24 11:11:30 wolff + * Fixed two stupid typos in the memory test. + * + * Revision 1.10 1999/04/24 10:53:39 wolff + * Added some of Christian's suggestions. + * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the + * card to send the signal to the process.....) + * + * Revision 1.9 1999/04/23 07:26:38 wolff + * Included Christian Lademann's 2.0 compile-warning fixes and interrupt + * assignment redesign. + * Cleanup of some other stuff. + * + * Revision 1.8 1999/04/16 13:05:30 wolff + * fixed a DCD change unnoticed bug. + * + * Revision 1.7 1999/04/14 22:19:51 wolff + * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!) + * + * Revision 1.6 1999/04/13 18:40:20 wolff + * changed misc-minor to 161, as assigned by HPA. + * + * Revision 1.5 1999/04/13 15:12:25 wolff + * Fixed use-count leak when "hangup" occurred. + * Added workaround for a stupid-PCIBIOS bug. + * + * + * Revision 1.4 1999/04/01 22:47:40 wolff + * Fixed < 1M linux-2.0 problem. + * (vremap isn't compatible with ioremap in that case) + * + * Revision 1.3 1999/03/31 13:45:45 wolff + * Firmware loading is now done through a separate IOCTL. + * + * Revision 1.2 1999/03/28 12:22:29 wolff + * rcs cleanup + * + * Revision 1.1 1999/03/28 12:10:34 wolff + * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). + * + * Revision 0.12 1999/03/28 09:20:10 wolff + * Fixed problem in 0.11, continueing cleanup. + * + * Revision 0.11 1999/03/28 08:46:44 wolff + * cleanup. Not good. + * + * Revision 0.10 1999/03/28 08:09:43 wolff + * Fixed loosing characters on close. + * + * Revision 0.9 1999/03/21 22:52:01 wolff + * Ported back to 2.2.... (minor things) + * + * Revision 0.8 1999/03/21 22:40:33 wolff + * Port to 2.0 + * + * Revision 0.7 1999/03/21 19:06:34 wolff + * Fixed hangup processing. + * + * Revision 0.6 1999/02/05 08:45:14 wolff + * fixed real_raw problems. Inclusion into kernel imminent. + * + * Revision 0.5 1998/12/21 23:51:06 wolff + * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it + * shouldn't have. THATs why I want to have transmit interrupts even when + * the buffer is empty. + * + * Revision 0.4 1998/12/17 09:34:46 wolff + * PPP works. ioctl works. Basically works! + * + * Revision 0.3 1998/12/15 13:05:18 wolff + * It works! Wow! Gotta start implementing IOCTL and stuff.... + * + * Revision 0.2 1998/12/01 08:33:53 wolff + * moved over to 2.1.130 + * + * Revision 0.1 1998/11/03 21:23:51 wolff + * Initial revision. Detects SX card. + * + * */ + + +#define RCS_ID "$Id: sx.c,v 1.26 1999/08/05 15:22:14 wolff Exp $" +#define RCS_REV "$Revision: 1.26 $" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */ +#define BYTE u8 +#define WORD u16 + +/* .... but the 3.0.4 version uses _u8 and _u16. */ +#define _u8 u8 +#define _u16 u16 + +#include "sxboards.h" +#include "sxwindow.h" + + +/* I don't think that this driver can handle more than 256 ports on + one machine. You'll have to increase the number of boards in sx.h + if you want more than 4 boards. */ + + +/* ************************************************************** */ +/* * This section can be removed when 2.0 becomes outdated.... * */ +/* ************************************************************** */ + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.3.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +#include + +#define Get_user(a,b) a = get_user(b) +#define Put_user(a,b) 0,put_user(a,b) +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + +#define pci_present pcibios_present +#define pci_read_config_word pcibios_read_config_word +#define pci_read_config_dword pcibios_read_config_dword + +static inline unsigned char get_irq (unsigned char bus, unsigned char fn) +{ + unsigned char t; + pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t); + return t; +} + +static inline void *ioremap(unsigned long base, long length) +{ + if (base < 0x100000) return (void *)base; + return vremap (base, length); +} + +#define my_iounmap(x, b) (((long)x<0x100000)?0:vfree ((void*)x)) + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + +/* Should be in a header somewhere. They are in tty.h on 2.2 */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ + +/* The return type of a "close" routine. */ +#define INT void +#define NO_ERROR /* Nothing */ + +#else + +/* The 2.2.x compatibility section. */ +#include + + +#define Get_user(a,b) get_user(a,b) +#define Put_user(a,b) put_user(a,b) +#define get_irq(pdev) pdev->irq + +#define INT int +#define NO_ERROR 0 + +#define my_iounmap(x,b) (iounmap((char *)(b))) + +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define wait_queue_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + + + +#include "generic_serial.h" +#include "sx.h" + + +/* ************************************************************** */ +/* * End of compatibility section.. * */ +/* ************************************************************** */ + + + +/* Why the hell am I defining these here? */ +#define SX_TYPE_NORMAL 1 +#define SX_TYPE_CALLOUT 2 + +#ifndef SX_NORMAL_MAJOR +/* This allows overriding on the compiler commandline, or in a "major.h" + include or something like that */ +#define SX_NORMAL_MAJOR 32 +#define SX_CALLOUT_MAJOR 33 +#endif + +#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 +#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 +#endif + + + +/* Configurable options: + (Don't be too sure that it'll work if you toggle them) */ + +/* Am I paranoid or not ? ;-) */ +#undef SX_PARANOIA_CHECK + + +/* 20 -> 2000 per second. The card should rate-limit interrupts at 100 + Hz, but it is user configurable. I don't recommend going above 1000 + Hz. The interrupt ratelimit might trigger if the interrupt is + shared with a very active other device. */ +#define IRQ_RATE_LIMIT 20 + +/* Sharing interrupts is possible now. If the other device wants more + than 2000 interrupts per second, we'd gracefully decline further + interrupts. That's not what we want. On the other hand, if the + other device interrupts 2000 times a second, don't use the SX + interrupt. Use polling. */ +#undef IRQ_RATE_LIMIT + + +#if 0 +/* Not implemented */ +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#define SX_REPORT_FIFO +#define SX_REPORT_OVERRUN +#endif + + +/* Function prototypes */ +static void sx_disable_tx_interrupts (void * ptr); +static void sx_enable_tx_interrupts (void * ptr); +static void sx_disable_rx_interrupts (void * ptr); +static void sx_enable_rx_interrupts (void * ptr); +static int sx_get_CD (void * ptr); +static void sx_shutdown_port (void * ptr); +static void sx_set_real_termios (void *ptr); +static void sx_hungup (void *ptr); +static void sx_close (void *ptr); +static int sx_chars_in_buffer (void * ptr); +static int sx_init_board (struct sx_board *board); +static int sx_init_portstructs (int nboards, int nports); +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int sx_fw_open(struct inode *inode, struct file *filp); +static INT sx_fw_release(struct inode *inode, struct file *filp); +static int sx_init_drivers(void); +void my_hd (unsigned char *addr, int len); + + + +static struct tty_driver sx_driver, sx_callout_driver; + +static struct tty_struct * sx_table[SX_NPORTS] = { NULL, }; +static struct termios ** sx_termios; +static struct termios ** sx_termios_locked; + +struct sx_board boards[SX_NBOARDS]; +struct sx_port *sx_ports; +int sx_refcount; +int sx_initialized = 0; +int sx_nports = 0; +int sx_debug = 0; + + +/* You can have the driver poll your card. + - Set sx_poll to 1 to poll every timer tick (10ms on Intel). + This is used when the card cannot use an interrupt for some reason. + + - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If + the driver misses an interrupt (report this if it DOES happen to you!) + everything will continue to work.... + */ +int sx_poll = 1; +int sx_slowpoll = 0; + +/* The card limits the number of interrupts per second. + At 115k2 "100" should be sufficient. + If you're using higher baudrates, you can increase this... + */ + +int sx_maxints = 100; + +/* These are the only open spaces in my computer. Yours may have more + or less.... */ +int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; +int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; + +#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int)) +#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int)) + + +/* Set the mask to all-ones. This alas, only supports 32 interrupts. + Some architectures may need more. */ +int sx_irqmask = -1; + +#ifndef TWO_ZERO +#ifdef MODULE +MODULE_PARM(sx_poll, "i"); +MODULE_PARM(sx_slowpoll, "i"); +MODULE_PARM(sx_maxints, "i"); +MODULE_PARM(sx_debug, "i"); +MODULE_PARM(sx_irqmask, "i"); +#endif +#endif + +static struct real_driver sx_real_driver = { + sx_disable_tx_interrupts, + sx_enable_tx_interrupts, + sx_disable_rx_interrupts, + sx_enable_rx_interrupts, + sx_get_CD, + sx_shutdown_port, + sx_set_real_termios, + sx_chars_in_buffer, + sx_close, + sx_hungup, + NULL +}; + + +/* + This driver can spew a whole lot of debugging output at you. If you + need maximum performance, you should disable the DEBUG define. To + aid in debugging in the field, I'm leaving the compile-time debug + features enabled, and disable them "runtime". That allows me to + instruct people with problems to enable debugging without requiring + them to recompile... +*/ +#define DEBUG + + +#ifdef DEBUG +#define sx_dprintk(f, str...) if (sx_debug & f) printk (str) +#else +#define sx_dprintk(f, str...) /* nothing */ +#endif + + + +#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n") +#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit " __FUNCTION__ "\n") + +#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \ + "(port %d)\n", port->line) + + + + +/* + * Firmware loader driver specific routines + * + */ + +static struct file_operations sx_fw_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + sx_fw_ioctl, + NULL, /* mmap */ + sx_fw_open, +#ifndef TWO_ZERO + NULL, /* flush */ +#endif + sx_fw_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct miscdevice sx_fw_device = { + SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops +}; + + + + + +#ifdef SX_PARANOIA_CHECK + +/* This doesn't work. Who's paranoid around here? Not me! */ + +static inline int sx_paranoia_check(struct sx_port const * port, + kdev_t device, const char *routine) +{ + + static const char *badmagic = + KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n"; + static const char *badinfo = + KERN_ERR "sx: Warning: null sx port for device %s in %s\n"; + + if (!port) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != SX_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } + + return 0; +} +#else +#define sx_paranoia_check(a,b,c) 0 +#endif + +/* The timeouts. First try 30 times as fast as possible. Then give + the card some time to breathe between accesses. (Otherwise the + processor on the card might not be able to access its OWN bus... */ + +#define TIMEOUT_1 30 +#define TIMEOUT_2 1000000 + + +/* This needs redoing for Alpha -- REW -- Done. */ + +inline void write_sx_byte (struct sx_board *board, int offset, u8 byte) +{ + writeb (byte, board->base+offset); +} + +inline u8 read_sx_byte (struct sx_board *board, int offset) +{ + return readb (board->base+offset); +} + + +inline void write_sx_word (struct sx_board *board, int offset, u16 word) +{ + writew (word, board->base+offset); +} + +inline u16 read_sx_word (struct sx_board *board, int offset) +{ + return readw (board->base + offset); +} + + +int sx_busy_wait_eq (struct sx_board *board, + int offset, + int mask, + int correctval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + +int sx_busy_wait_neq (struct sx_board *board, + int offset, + int mask, + int badval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + + +/* 5.6.4 of 6210028 r2.3 */ +int sx_reset (struct sx_board *board) +{ + func_enter (); + + if (IS_SX_BOARD (board)) { + + write_sx_byte (board, SX_CONFIG, 0); + write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */ + + if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) { + printk (KERN_INFO "sx: Card doesn't respond to reset....\n"); + return 0; + } + } else { + /* Gory details of the SI/ISA board */ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET); + write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR); + } + + func_exit (); + return 1; +} + + +/* This doesn't work on machines where "NULL" isn't 0 */ +/* If you have one of those, someone will need to write + the equivalent of this, which will amount to about 3 lines. I don't + want to complicate this right now. -- REW + (See, I do write comments every now and then :-) */ +#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem)) + + +#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem)) +#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem)) +#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem)) + + +#define sx_write_channel_byte(port, elem, val) \ + write_sx_byte (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_byte(port, elem) \ + read_sx_byte (port->board, CHAN_OFFSET (port, elem)) + +#define sx_write_channel_word(port, elem, val) \ + write_sx_word (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_word(port, elem) \ + read_sx_word (port->board, CHAN_OFFSET (port, elem)) + + +#define sx_write_module_byte(board, addr, elem, val) \ + write_sx_byte (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_byte(board, addr, elem) \ + read_sx_byte (board, MODU_OFFSET (board, addr, elem)) + +#define sx_write_module_word(board, addr, elem, val) \ + write_sx_word (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_word(board, addr, elem) \ + read_sx_word (board, MODU_OFFSET (board, addr, elem)) + + +#define sx_write_board_byte(board, elem, val) \ + write_sx_byte (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_byte(board, elem) \ + read_sx_byte (board, BRD_OFFSET (board, elem)) + +#define sx_write_board_word(board, elem, val) \ + write_sx_word (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_word(board, elem) \ + read_sx_word (board, BRD_OFFSET (board, elem)) + + +int sx_start_board (struct sx_board *board) +{ + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN); + } else { + /* Don't bug me about the clear_set. + I haven't the foggiest idea what it's about -- REW*/ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + return 1; +} + +#define SX_IRQ_REG_VAL(board) \ + ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0) + +/* Note. The SX register is write-only. Therefore, we have to enable the + bus too. This is a no-op, if you don't mess with this driver... */ +int sx_start_interrupts (struct sx_board *board) +{ + + /* Don't call this with board->irq == 0 */ + + if (IS_SX_BOARD(board)) { + write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) | + SX_CONF_BUSEN | + SX_CONF_HOSTIRQ); + } else { + switch (board->irq) { + case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break; + case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break; + case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break; + default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n", + board->irq); + return 0; + } + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + + return 1; +} + + +int sx_send_command (struct sx_port *port, + int command, + int mask, + int newstat) +{ + func_enter2 (); + write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command); + func_exit (); + return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat); +} + + +char *mod_type_s (int module_type) +{ + switch (module_type) { + case TA4: return "TA4"; + case TA8: return "TA8"; + case TA4_ASIC: return "TA4_ASIC"; + case TA8_ASIC: return "TA8_ASIC"; + case MTA_CD1400:return "MTA_CD1400"; + case SXDC: return "SXDC"; + default:return "Unknown/invalid"; + } +} + + +char *pan_type_s (int pan_type) +{ + switch (pan_type) { + case MOD_RS232DB25: return "MOD_RS232DB25"; + case MOD_RS232RJ45: return "MOD_RS232RJ45"; + case MOD_RS422DB25: return "MOD_RS422DB25"; + case MOD_PARALLEL: return "MOD_PARALLEL"; + case MOD_2_RS232DB25: return "MOD_2_RS232DB25"; + case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45"; + case MOD_2_RS422DB25: return "MOD_2_RS422DB25"; + case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE"; + case MOD_2_PARALLEL: return "MOD_2_PARALLEL"; + case MOD_BLANK: return "empty"; + default:return "invalid"; + } +} + + +int mod_compat_type (int module_type) +{ + return module_type >> 4; +} + + +static void sx_setsignals (struct sx_port *port, int dtr, int rts) +{ + int t; + func_enter2 (); + + t = sx_read_channel_byte (port, hi_op); + if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR); + if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS); + sx_write_channel_byte (port, hi_op, t); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts); + func_exit (); +} + + + +static int sx_getsignals (struct sx_port *port) +{ + int i_stat,o_stat; + + o_stat = sx_read_channel_byte (port, hi_op); + i_stat = sx_read_channel_byte (port, hi_ip); + + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n", + (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0, + port->c_dcd, sx_get_CD (port), + sx_read_channel_byte (port, hi_ip), + sx_read_channel_byte (port, hi_state)); + + return (((o_stat & OP_DTR)?TIOCM_DTR:0) | + ((o_stat & OP_RTS)?TIOCM_RTS:0) | + ((i_stat & IP_CTS)?TIOCM_CTS:0) | + ((i_stat & IP_DCD)?TIOCM_CAR:0) | + ((i_stat & IP_DSR)?TIOCM_DSR:0) | + ((i_stat & IP_RI)?TIOCM_RNG:0) + ); +} + + +static void sx_set_baud (struct sx_port *port) +{ + int t; + + if (port->board->ta_type == MOD_SXDC) { + switch (port->gs.baud) { + /* Save some typing work... */ +#define e(x) case x:t= BAUD_ ## x ; break + e(50);e(75);e(110);e(150);e(200);e(300);e(600); + e(1200);e(1800);e(2000);e(2400);e(4800);e(7200); + e(9600);e(14400);e(19200);e(28800);e(38400); + e(56000);e(57600);e(64000);e(76800);e(115200); + e(128000);e(150000);e(230400);e(256000);e(460800); + e(921600); + case 134 :t = BAUD_134_5; break; + case 0 :t = -1; + break; + default: + /* Can I return "invalid"? */ + t = BAUD_9600; + printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t > 0) { + /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */ + sx_setsignals (port, 1, -1); + /* XXX This is not TA & MTA compatible */ + sx_write_channel_byte (port, hi_csr, 0xff); + + sx_write_channel_byte (port, hi_txbaud, t); + sx_write_channel_byte (port, hi_rxbaud, t); + } else { + sx_setsignals (port, 0, -1); + } + } else { + switch (port->gs.baud) { +#define e(x) case x:t= CSR_ ## x ; break + e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800); + e(1800);e(9600); + e(19200);e(57600);e(38400); + /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */ + case 110: + if (port->board->ta_type == MOD_TA) { + t = CSR_110; + break; + } else { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } + case 115200: + if (port->board->ta_type == MOD_TA) { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } else { + t = CSR_110; + break; + } + case 0 :t = -1; + break; + default: + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t >= 0) { + sx_setsignals (port, 1, -1); + sx_write_channel_byte (port, hi_csr, t * 0x11); + } else { + sx_setsignals (port, 0, -1); + } + } +} + + +/* Simon Allen's version of this routine was 225 lines long. 85 is a lot + better. -- REW */ + +static void sx_set_real_termios (void *ptr) +{ + struct sx_port *port = ptr; + + func_enter2(); + + /* What is this doing here? -- REW + Ha! figured it out. It is to allow you to get DTR active again + if you've dropped it with stty 0. Moved to set_baud, where it + belongs (next to the drop dtr if baud == 0) -- REW */ + /* sx_setsignals (port, 1, -1); */ + + sx_set_baud (port); + +#define CFLAG port->gs.tty->termios->c_cflag + sx_write_channel_byte (port, hi_mr1, + (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) | + (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) | + (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) | + (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) | + (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) | + (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) | + (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) ); + + sx_write_channel_byte (port, hi_mr2, + (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) | + (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP)); + + switch (CFLAG & CSIZE) { + case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break; + case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break; + case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break; + case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break; + default: + printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE); + break; + } + + sx_write_channel_byte (port, hi_prtcl, + (I_IXON (port->gs.tty)?SP_TXEN:0) | + (I_IXOFF (port->gs.tty)?SP_RXEN:0) | + (I_IXANY (port->gs.tty)?SP_TANY:0) | + SP_DCEN); + + sx_write_channel_byte (port, hi_break, + I_OTHER(port->gs.tty) ? 0: + (I_IGNBRK(port->gs.tty)?BR_IGN:0 | + I_BRKINT(port->gs.tty)?BR_INT:0)); + + sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty)); + + if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) { + if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n"); + } + } else { + sx_dprintk (SX_DEBUG_TERMIOS, + "sx: Not sending reconfigure: port isn't open (%02x).\n", + sx_read_channel_byte (port, hi_hstat)); + } + + + /* Tell line discipline whether we will do input cooking */ + if(I_OTHER(port->gs.tty)) { + clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } else { + set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", + port->gs.tty->termios->c_iflag, + I_OTHER(port->gs.tty)); + + +/* Tell line discipline whether we will do output cooking. + * If OPOST is set and no other output flags are set then we can do output + * processing. Even if only *one* other flag in the O_OTHER group is set + * we do cooking in software. + */ + if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) { + set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } else { + clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", + port->gs.tty->termios->c_oflag, + O_OTHER(port->gs.tty)); + /* port->c_dcd = sx_get_CD (port); */ + func_exit (); +} + + + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +/* Note: + Other drivers use the macro "MIN" to calculate how much to copy. + This has the disadvantage that it will evaluate parts twice. That's + expensive when it's IO (and the compiler cannot optimize those away!). + Moreover, I'm not sure that you're race-free. + + I assign a value, and then only allow the value to decrease. This + is always safe. This makes the code a few lines longer, and you + know I'm dead against that, but I think it is required in this + case. */ + + +void sx_transmit_chars (struct sx_port *port) +{ + int c; + int tx_ip; + int txroom; + + func_enter2 (); + sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n", + port, port->gs.xmit_cnt); + + if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) { + return; + } + + while (1) { + c = port->gs.xmit_cnt; + + sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c); + tx_ip = sx_read_channel_byte (port, hi_txipos); + + /* Took me 5 minutes to deduce this formula. + Luckily it is literally in the manual in section 6.5.4.3.5 */ + txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff; + + /* Don't copy more bytes than there is room for in the buffer */ + if (c > txroom) + c = txroom; + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom ); + + /* Don't copy past the end of the hardware transmit buffer */ + if (c > 0x100 - tx_ip) + c = 0x100 - tx_ip; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip ); + + /* Don't copy pas the end of the source buffer */ + if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) + c = SERIAL_XMIT_SIZE - port->gs.xmit_tail; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", + c, SERIAL_XMIT_SIZE- port->gs.xmit_tail); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + + memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip, + port->gs.xmit_buf + port->gs.xmit_tail, c); + + /* Update the pointer in the card */ + sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff); + + /* Update the kernel buffer end */ + port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1); + + /* This one last. (this is essential) + It would allow others to start putting more data into the buffer! */ + port->gs.xmit_cnt -= c; + } + + if (port->gs.xmit_cnt == 0) { + sx_disable_tx_interrupts (port); + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + port->gs.wakeup_chars); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); + func_exit (); +} + + +/* Note the symmetry between receiving chars and transmitting them! + Note: The kernel should have implemented both a receive buffer and + a transmit buffer. */ + +/* Inlined: Called only once. Remove the inline when you add another call */ +inline void sx_receive_chars (struct sx_port *port) +{ + int c; + int rx_op; + struct tty_struct *tty; + int copied=0; + + /* func_enter2 (); */ + tty = port->gs.tty; + while (1) { + rx_op = sx_read_channel_byte (port, hi_rxopos); + c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff; + + sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + c > TTY_FLIPBUF_SIZE) + c = TTY_FLIPBUF_SIZE - tty->flip.count; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* Don't copy past the end of the hardware receive buffer */ + if (rx_op + c > 0x100) c = 0x100 - rx_op; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, + read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op), + CHAN_OFFSET(port, hi_rxbuf)); + memcpy_fromio (tty->flip.char_buf_ptr, + port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c); + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c); + + /* Update the kernel buffer end */ + tty->flip.count += c; + tty->flip.char_buf_ptr += c; + tty->flip.flag_buf_ptr += c; + + /* This one last. ( Not essential.) + It allows the card to start putting more data into the buffer! + Update the pointer in the card */ + sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff); + + copied += c; + } + if (copied) { + struct timeval tv; + + do_gettimeofday (&tv); + sx_dprintk (SX_DEBUG_RECEIVE, + "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n", + port->line, copied, + (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw); + + /* Tell the rest of the system the news. Great news. New characters! */ + tty_flip_buffer_push (tty); + /* tty_schedule_flip (tty); */ + } + + /* func_exit (); */ +} + +/* Inlined: it is called only once. Remove the inline if you add another + call */ +inline void sx_check_modem_signals (struct sx_port *port) +{ + int hi_state; + int c_dcd; + + hi_state = sx_read_channel_byte (port, hi_state); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n", + port->c_dcd, sx_get_CD (port)); + + if (hi_state & ST_BREAK) { + hi_state &= ~ST_BREAK; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n"); + + sx_write_channel_byte (port, hi_state, hi_state); + if (port->gs.flags & ASYNC_SAK) { + do_SAK (port->gs.tty); + } + } + if (hi_state & ST_DCD) { + hi_state &= ~ST_DCD; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n"); + sx_write_channel_byte (port, hi_state, hi_state); + c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd); + if (c_dcd != port->c_dcd) { + port->c_dcd = c_dcd; + if (sx_get_CD (port)) { + /* DCD went UP */ + if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || + ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) && + (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) { + /* Are we blocking in open?*/ + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n"); + wake_up_interruptible(&port->gs.open_wait); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n"); + } + } else { + /* DCD went down! */ + if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && + (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n"); + tty_hangup (port->gs.tty); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n"); + } + } + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n"); + } + } +} + + +/* This is what an interrupt routine should look like. + * Small, elegant, clear. + */ + +static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs) +{ + struct sx_board *board = ptr; + struct sx_port *port; + int i; + + /* func_enter (); */ + sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); + + /* AAargh! The order in which to do these things is essential and + not trivial. + + - Rate limit goes before "recursive". Otherwise a series of + recursive calls will hang the machine in the interrupt routine. + + - hardware twiddling goes before "recursive". Otherwise when we + poll the card, and a recursive interrupt happens, we wont + ack the card, so it might keep on interrupting us. (especially + level sensitive interrupt systems like PCI). + + - Rate limit goes before hardware twiddling. Otherwise we won't + catch a card that has gone bonkers. + + - The "initialized" test goes after the hardware twiddling. Otherwise + the card will stick us in the interrupt routine again. + + - The initialized test goes before recursive. + */ + + + +#ifdef IRQ_RATE_LIMIT + /* Aaargh! I'm ashamed. This costs more lines-of-code than the + actual interrupt routine!. (Well, used to when I wrote that comment) */ + { + static int lastjif; + static int nintr=0; + + if (lastjif == jiffies) { + if (++nintr > IRQ_RATE_LIMIT) { + free_irq (board->irq, board); + printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n", + board->irq); + } + } else { + lastjif = jiffies; + nintr = 0; + } + } +#endif + + + if (board->irq == irq) { + /* Tell the card we've noticed the interrupt. */ + + sx_write_board_word (board, cc_int_pending, 0); + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_RESET_IRQ, 1); + } else { + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + } + + if (!sx_initialized) return; + if (!(board->flags & SX_BOARD_INITIALIZED)) return; + + if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) { + printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq); + return; + } + + for (i=0;inports;i++) { + port = &board->ports[i]; + if (port->gs.flags & GS_ACTIVE) { + if (sx_read_channel_byte (port, hi_state)) { + sx_dprintk (SX_DEBUG_INTERRUPTS, + "Port %d: modem signal change?... \n", i); + sx_check_modem_signals (port); + } + if (port->gs.xmit_cnt) { + sx_transmit_chars (port); + } + if (!(port->gs.flags & SX_RX_THROTTLE)) { + sx_receive_chars (port); + } + } + } + + clear_bit (SX_BOARD_INTR_LOCK, &board->locks); + + sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); + /* func_exit (); */ +} + + +static void sx_pollfunc (unsigned long data) +{ + struct sx_board *board = (struct sx_board *) data; + + func_enter (); + + sx_interrupt (0, board, NULL); + + board->timer.expires = jiffies + sx_poll; + add_timer (&board->timer); + func_exit (); +} + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the generic_serial driver * + * ********************************************************************** */ + +/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */ +/* Hmm. Ok I figured it out. You don't. */ + +static void sx_disable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_enable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + int data_in_buffer; + func_enter2(); + + /* First transmit the characters that we're supposed to */ + sx_transmit_chars (port); + + /* The sx card will never interrupt us if we don't fill the buffer + past 25%. So we keep considering interrupts off if that's the case. */ + data_in_buffer = (sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff; + + /* XXX Must be "HIGH_WATER" for SI card according to doc. */ + if (data_in_buffer < LOW_WATER) + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_disable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + +static void sx_enable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + + +/* Jeez. Isn't this simple? */ +static int sx_get_CD (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0); +} + + +/* Jeez. Isn't this simple? */ +static int sx_chars_in_buffer (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff); +} + + +static void sx_shutdown_port (void * ptr) +{ + struct sx_port *port = ptr; + + func_enter(); + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + sx_setsignals (port, 0, 0); + } + + func_exit(); +} + + + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the rest of the system * + * ********************************************************************** */ + + +static int sx_fw_open(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_INC_USE_COUNT; + func_exit (); + return 0; +} + + +static INT sx_fw_release(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); + return NO_ERROR; +} + + +static int sx_open (struct tty_struct * tty, struct file * filp) +{ + struct sx_port *port; + int retval, line; + + func_enter(); + + if (!sx_initialized) { + return -EIO; + } + + line = MINOR(tty->device); + sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", + current->pid, line, tty, current->tty, sx_nports); + + if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports)) + return -ENODEV; + + port = & sx_ports[line]; + port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a + 1 -> 0 transition. */ + + + sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd); + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + + sx_dprintk (SX_DEBUG_OPEN, "starting port\n"); + + /* + * Start up serial port + */ + retval = gs_init_port(&port->gs); + sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n"); + if (retval) { + port->gs.count--; + return retval; + } + + port->gs.flags |= GS_ACTIVE; + sx_setsignals (port, 1,1); + + sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", + port->gs.count); + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n"); + +#if 0 + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port, sizeof (*port)); +#else + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port->board->base + port->ch_base, + sizeof (*port)); +#endif + + if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n"); + MOD_DEC_USE_COUNT; + port->gs.count--; + return -EIO; + } + + retval = block_til_ready(port, filp); + sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", + retval, port->gs.count); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + /* tty->low_latency = 1; */ + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + sx_set_real_termios (port); + } + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + port->c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); + func_exit(); + return 0; + +} + + +/* I haven't the foggiest why the decrement use count has to happen + here. The whole linux serial drivers stuff needs to be redesigned. + My guess is that this is a hack to minimize the impact of a bug + elsewhere. Thinking about it some more. (try it sometime) Try + running minicom on a serial port that is driven by a modularized + driver. Have the modem hangup. Then remove the driver module. Then + exit minicom. I expect an "oops". -- REW */ +static void sx_hungup (void *ptr) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); +} + + +static void sx_close (void *ptr) +{ + struct sx_port *port = ptr; + /* Give the port 5 seconds to close down. */ + int to = 5 * HZ; + + func_enter (); + sx_send_command (port, HS_CLOSE, 0, 0); + + while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (1); + if (signal_pending (current)) + break; + } + current->state = TASK_RUNNING; + if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { + if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { + printk (KERN_ERR + "sx: sent the force_close command, but card didn't react\n"); + } else + sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); + } + + sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", + 5 * HZ - to - 1, port->gs.count); + + MOD_DEC_USE_COUNT; + func_exit (); +} + + + +/* This is relatively thorough. But then again it is only 20 lines. */ +#define MARCHUP for (i=min;i=min;i--) +#define W0 write_sx_byte (board, i, 0x55) +#define W1 write_sx_byte (board, i, 0xaa) +#define R0 if (read_sx_byte (board, i) != 0x55) return 1 +#define R1 if (read_sx_byte (board, i) != 0xaa) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest (struct sx_board *board, int min, int max) +{ + int i; + + /* This is a marchb. Theoretically, marchb catches much more than + simpler tests. In practise, the longer test just catches more + intermittent errors. -- REW + (For the theory behind memory testing see: + Testing Semiconductor Memories by A.J. van de Goor.) */ + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +#undef MARCHUP +#undef MARCHDOWN +#undef W0 +#undef W1 +#undef R0 +#undef R1 + +#define MARCHUP for (i=min;i=min;i-=2) +#define W0 write_sx_word (board, i, 0x55aa) +#define W1 write_sx_word (board, i, 0xaa55) +#define R0 if (read_sx_word (board, i) != 0x55aa) return 1 +#define R1 if (read_sx_word (board, i) != 0xaa55) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest_w (struct sx_board *board, int min, int max) +{ + int i; + + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + int *descr = (int *)arg, i; + static struct sx_board *board = NULL; + int nbytes, offset, data; + char *tmp; + + func_enter(); + +#if 0 + /* Removed superuser check: Sysops can use the permissions on the device + file to restrict access. Recommendation: Root only. (root.root 600) */ + if (!suser ()) { + return -EPERM; + } +#endif + + sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg); + + if (!board) board = &boards[0]; + if (board->flags & SX_BOARD_PRESENT) { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n", + board->flags); + } else { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:", + board->flags); + for (i=0;i< SX_NBOARDS;i++) + sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags); + sx_dprintk (SX_DEBUG_FIRMWARE, "\n"); + return -EIO; + } + + switch (cmd) { + case SXIO_SET_BOARD: + sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg); + if (arg > SX_NBOARDS) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n"); + if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n"); + board = &boards[arg]; + break; + case SXIO_GET_TYPE: + rc = IS_SX_BOARD (board)? SX_TYPE_SX:SX_TYPE_SI; + sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); + break; + case SXIO_DO_RAMTEST: + if (sx_initialized) /* Already initialized: better not ramtest the board. */ + return -EPERM; + if (IS_SX_BOARD (board)) { + rc = do_memtest (board, 0, 0x7000); + if (!rc) rc = do_memtest (board, 0, 0x7000); + /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/ + } else { + rc = do_memtest (board, 0, 0x7ff8); + /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */ + } + sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc); + break; + case SXIO_DOWNLOAD: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + if (!sx_reset (board)) + return -EIO; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER); + if (!tmp) return -ENOMEM; + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + while (nbytes && data) { + for (i=0;inbytes)?nbytes-i:SX_CHUNK_SIZE); + memcpy_toio ((char *) (board->base + offset + i), tmp, + (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE); + } + + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + } + kfree (tmp); + sx_nports += sx_init_board (board); + rc = sx_nports; + break; + case SXIO_INIT: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + /* This is not allowed until all boards are initialized... */ + for (i=0;i= 0) + sx_initialized++; + break; + case SXIO_SETDEBUG: + sx_debug = arg; + break; + case SXIO_GETDEBUG: + rc = sx_debug; + break; + case SXIO_SETGSDEBUG: + gs_debug = arg; + break; + case SXIO_GETGSDEBUG: + rc = gs_debug; + break; + default: + printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd); + break; + } + func_exit (); + return rc; +} + + +static int sx_ioctl (struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int rc; + struct sx_port *port = tty->driver_data; + int ival; + + /* func_enter2(); */ + + rc = 0; + switch (cmd) { + case TIOCGSOFTCAR: + rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + Get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + gs_getserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = sx_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + + default: + rc = -ENOIOCTLCMD; + break; + } + + /* func_exit(); */ + return rc; +} + + +/* The throttle/unthrottle scheme for the Specialix card is different + * from other drivers and deserves some explanation. + * The Specialix hardware takes care of XON/XOFF + * and CTS/RTS flow control itself. This means that all we have to + * do when signalled by the upper tty layer to throttle/unthrottle is + * to make a note of it here. When we come to read characters from the + * rx buffers on the card (sx_receive_chars()) we look to see if the + * upper layer can accept more (as noted here in sx_rx_throt[]). + * If it can't we simply don't remove chars from the cards buffer. + * When the tty layer can accept chars, we again note that here and when + * sx_receive_chars() is called it will remove them from the cards buffer. + * The card will notice that a ports buffer has drained below some low + * water mark and will unflow control the line itself, using whatever + * flow control scheme is in use for that port. -- Simon Allen + */ + +static void sx_throttle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* If the port is using any type of input flow + * control then throttle the port. + */ + if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) { + port->gs.flags |= SX_RX_THROTTLE; + } + func_exit(); +} + + +static void sx_unthrottle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* Always unthrottle even if flow control is not enabled on + * this port in case we disabled flow control while the port + * was throttled + */ + port->gs.flags &= ~SX_RX_THROTTLE; + func_exit(); + return; +} + + +/* ********************************************************************** * + * Here are the initialization routines. * + * ********************************************************************** */ + + + + +static int sx_init_board (struct sx_board *board) +{ + int addr; + int chans; + int type; + + func_enter(); + + /* This is preceded by downloading the download code. */ + + board->flags |= SX_BOARD_INITIALIZED; + + /* This resets the processor again, to make sure it didn't do any + foolish things while we were downloading the image */ + if (!sx_reset (board)) + return 0; + + sx_start_board (board); + + if (!sx_busy_wait_neq (board, 0, 0xff, 0)) { + printk (KERN_ERR "sx: Ooops. Board won't initialize.\n"); + return 0; + } + + /* Ok. So now the processor on the card is running. It gathered + some info for us... */ + sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10); + sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30); + + sx_dprintk (SX_DEBUG_INIT, + "init_status: %x, %dk memory, firmware V%x.%02x,\n", + read_sx_byte (board, 0), read_sx_byte(board, 1), + read_sx_byte (board, 5), read_sx_byte(board, 4)); + + if (read_sx_byte (board, 0) == 0xff) { + printk (KERN_INFO "sx: No modules found. Sorry.\n"); + board->nports = 0; + return 0; + } + + chans = 0; + + if (IS_SX_BOARD(board)) { + sx_write_board_word (board, cc_int_count, sx_maxints); + } else { + if (sx_maxints) + sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints); + } + + /* grab the first module type... */ + /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */ + board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip)); + + /* XXX byteorder */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + type = sx_read_module_byte (board, addr, mc_chip); + sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n", + addr, read_sx_byte (board, addr + 2)); + + chans += sx_read_module_byte (board, addr, mc_type); + + sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n", + mod_type_s (type), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4)); + + sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n", + sx_read_module_byte (board, addr, mc_rev1), + sx_read_module_byte (board, addr, mc_rev2), + sx_read_module_byte (board, addr, mc_mtaasic_rev)); + + /* The following combinations are illegal: It should theoretically + work, but timing problems make the bus HANG. */ + + if (mod_compat_type (type) != board->ta_type) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't mix TA/MTA/SXDC on the same hostadapter.\n"); + chans=0; + break; + } + if (IS_SI_BOARD(board) && (mod_compat_type(type) == 4)) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't use SXDCs on an SI/XIO adapter.\n"); + chans=0; + break; + } +#if 0 /* Problem fixed: firmware 3.05 */ + if (IS_SX_BOARD(board) && (type == TA8)) { + /* There are some issues with the firmware and the DCD/RTS + lines. It might work if you tie them together or something. + It might also work if you get a newer sx_firmware. Therefore + this is just a warning. */ + printk (KERN_WARNING "sx: The SX host doesn't work too well " + "with the TA8 adapters.\nSpecialix is working on it.\n"); + } +#endif + } + + if (chans) { + /* board->flags |= SX_BOARD_PRESENT; */ + if(board->irq > 0) { + /* fixed irq, probably PCI */ + if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */ + if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) { + printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq); + board->irq = 0; + } + } else + board->irq = 0; + } else if(board->irq < 0 && sx_irqmask) { + /* auto-allocate irq */ + int irqnr; + int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK); + for(irqnr = 15; irqnr > 0; irqnr--) + if(irqmask & (1 << irqnr)) + if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) + break; + if(! irqnr) + printk(KERN_ERR "sx: Cannot allocate IRQ.\n"); + board->irq = irqnr; + } else + board->irq = 0; + + if (board->irq) { + /* Found a valid interrupt, start up interrupts! */ + sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq); + sx_start_interrupts (board); + board->poll = sx_slowpoll; + board->flags |= SX_IRQ_ALLOCATED; + } else { + /* no irq: setup board for polled operation */ + board->poll = sx_poll; + sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll); + } + + /* The timer should be initialized anyway: That way we can safely + del_timer it when the module is unloaded. */ + init_timer (&board->timer); + + if (board->poll) { + board->timer.data = (unsigned long) board; + board->timer.function = sx_pollfunc; + board->timer.expires = jiffies + board->poll; + add_timer (&board->timer); + } + } else { + board->irq = 0; + } + + board->nports = chans; + sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports); + + func_exit(); + return chans; +} + + +void printheader(void) +{ + static int header_printed = 0; + + if (!header_printed) { + printk (KERN_INFO "Specialix SX driver " + "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n"); + printk (KERN_INFO "sx: version %s\n", RCS_ID); + header_printed = 1; + } +} + + +int probe_sx (struct sx_board *board) +{ + struct vpd_prom vpdp; + char *p; + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", + board->base + SX_VPD_ROM); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SX_VPD_ROM), 0x40); + + p = (char *) &vpdp; + for (i=0;i< sizeof (struct vpd_prom);i++) + *p++ = read_sx_byte (board, SX_VPD_ROM + i*2); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)&vpdp, 0x20); + + sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n"); + + if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) { + sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n", + vpdp.identifier); + return 0; + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base); + printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", + vpdp.hwrev, vpdp.hwass, vpdp.uniqid); + printk ( "Manufactured: %d/%d\n", + 1970 + vpdp.myear, vpdp.mweek); + + + if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) && + (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) { + /* This might be a bit harsh. This was the primary reason the + SX/ISA card didn't work at first... */ + printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n"); + return (0); + } + + if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) { + if (board->base & 0x8000) { + printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base); + printk (KERN_WARNING "sx: Read sx.txt for more info.\n"); + } + } + + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + + +/* Specialix probes for this card at 32k increments from 640k to 16M. + I consider machines with less than 16M unlikely nowadays, so I'm + not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA + card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves + 0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */ + +int probe_si (struct sx_board *board) +{ + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", + board->base + SI2_ISA_ID_BASE); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8); + + for (i=0;i<8;i++) { + if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) { + return 0; + } + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base); + /* Compared to the SX boards, it is a complete guess as to what + this card is up to... */ + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + +static int sx_init_drivers(void) +{ + int error; + + func_enter(); + + memset(&sx_driver, 0, sizeof(sx_driver)); + sx_driver.magic = TTY_DRIVER_MAGIC; + sx_driver.driver_name = "specialix_sx"; + sx_driver.name = "ttyX"; + sx_driver.major = SX_NORMAL_MAJOR; + sx_driver.num = sx_nports; + sx_driver.type = TTY_DRIVER_TYPE_SERIAL; + sx_driver.subtype = SX_TYPE_NORMAL; + sx_driver.init_termios = tty_std_termios; + sx_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + sx_driver.flags = TTY_DRIVER_REAL_RAW; + sx_driver.refcount = &sx_refcount; + sx_driver.table = sx_table; + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + sx_driver.open = sx_open; + sx_driver.close = gs_close; + sx_driver.write = gs_write; + sx_driver.put_char = gs_put_char; + sx_driver.flush_chars = gs_flush_chars; + sx_driver.write_room = gs_write_room; + sx_driver.chars_in_buffer = gs_chars_in_buffer; + sx_driver.flush_buffer = gs_flush_buffer; + sx_driver.ioctl = sx_ioctl; + sx_driver.throttle = sx_throttle; + sx_driver.unthrottle = sx_unthrottle; + sx_driver.set_termios = gs_set_termios; + sx_driver.stop = gs_stop; + sx_driver.start = gs_start; + sx_driver.hangup = gs_hangup; + + sx_callout_driver = sx_driver; + sx_callout_driver.name = "cux"; + sx_callout_driver.major = SX_CALLOUT_MAJOR; + sx_callout_driver.subtype = SX_TYPE_CALLOUT; + + if ((error = tty_register_driver(&sx_driver))) { + printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&sx_callout_driver))) { + tty_unregister_driver(&sx_driver); + printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n", + error); + return 1; + } + + func_exit(); + return 0; +} + + +void * ckmalloc (int size) +{ + void *p; + + p = kmalloc(size, GFP_KERNEL); + if (p) + memset(p, 0, size); + return p; +} + + +static int sx_init_portstructs (int nboards, int nports) +{ + struct sx_board *board; + struct sx_port *port; + int i, j; + int addr, chans; + int portno; + + func_enter(); + + /* Many drivers statically allocate the maximum number of ports + There is no reason not to allocate them dynamically. Is there? -- REW */ + sx_ports = ckmalloc(nports * sizeof (struct sx_port)); + if (!sx_ports) + return -ENOMEM; + + sx_termios = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios) { + kfree (sx_ports); + return -ENOMEM; + } + + sx_termios_locked = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios_locked) { + kfree (sx_ports); + kfree (sx_termios); + return -ENOMEM; + } + + /* Adjust the values in the "driver" */ + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + port = sx_ports; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->ports = port; + for (j=0; j < boards[i].nports;j++) { + sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j); + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SX_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->board = board; + port->gs.rd = &sx_real_driver; +#ifdef NEW_WRITE_LOCKING + port->gs.port_write_sem = MUTEX; +#endif + port++; + } + } + + port = sx_ports; + portno = 0; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->port_base = portno; + /* Possibly the configuration was rejected. */ + sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports); + if (board->nports <= 0) continue; + /* XXX byteorder ?? */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + chans = sx_read_module_byte (board, addr, mc_type); + sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans); + sx_dprintk (SX_DEBUG_PROBE, "Port at"); + for (j=0;jch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer); + else + port->ch_base = addr + 0x100 + 0x300*j; + + sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base); + port->line = portno++; + port++; + } + sx_dprintk (SX_DEBUG_PROBE, "\n"); + } + /* This has to be done earlier. */ + /* board->flags |= SX_BOARD_INITIALIZED; */ + } + + func_exit(); + return 0; +} + + +static void sx_release_drivers(void) +{ + func_enter(); + tty_unregister_driver(&sx_driver); + tty_unregister_driver(&sx_callout_driver); + func_exit(); +} + +#ifdef TWO_ZERO +#define PDEV unsigned char pci_bus, unsigned pci_fun +#define pdev pci_bus, pci_fun +#else +#define PDEV struct pci_dev *pdev +#endif + + +#ifdef CONFIG_PCI + /******************************************************** + * Setting bit 17 in the CNTRL register of the PLX 9050 * + * chip forces a retry on writes while a read is pending.* + * This is to prevent the card locking up on Intel Xeon * + * multiprocessor systems with the NX chipset. -- NV * + ********************************************************/ + +/* Newer cards are produced with this bit set from the configuration + EEprom. As the bit is read/write for the CPU, we can fix it here, + if we detect that it isn't set correctly. -- REW */ + +void fix_sx_pci (PDEV, struct sx_board *board) +{ + unsigned int hwbase; + unsigned long rebase; + int t; + +#define CNTRL_REG_OFFSET 0x14 + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase); + hwbase &= PCI_BASE_ADDRESS_MEM_MASK; + rebase = (ulong) ioremap(hwbase, 0x80); + t = readb (rebase + CNTRL_REG_OFFSET*4 + 2); + if (t != 0x06) { + printk (KERN_DEBUG "sx: performing cntrl reg fix: %02x -> 06\n", t); + writeb (0x06, rebase + CNTRL_REG_OFFSET*4+2); + } + my_iounmap (hwbase, rebase); + +} +#endif + + +#ifdef MODULE +#define sx_init init_module +#endif + +int sx_init(void) +{ + int i; + int found = 0; + struct sx_board *board; + +#ifdef CONFIG_PCI +#ifndef TWO_ZERO + struct pci_dev *pdev = NULL; +#else + unsigned char pci_bus, pci_fun; + /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */ +#endif + unsigned int tint; + unsigned short tshort; +#endif + + func_enter(); + sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug); + if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) { + printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. " + "Assuming -1.\n"); + printk ("(%p)\n", &sx_debug); + sx_debug=-1; + } + +#ifdef CONFIG_PCI + if (pci_present ()) { +#ifndef TWO_ZERO + while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, + pdev))) { +#else + for (i=0;i< SX_NBOARDS;i++) { + if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i, + &pci_bus, &pci_fun)) break; +#endif + /* Specialix has a whole bunch of cards with + 0x2000 as the device ID. They say its because + the standard requires it. Stupid standard. */ + /* It seems that reading a word doesn't work reliably on 2.0. + Also, reading a non-aligned dword doesn't work. So we read the + whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID) + ourselves */ + /* I don't know why the define doesn't work, constant 0x2c does --REW */ + pci_read_config_dword (pdev, 0x2c, &tint); + tshort = (tint >> 16) & 0xffff; + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint); + /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */ + if (tshort != 0x0200) { + sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n", + tshort); + continue; + } + board = &boards[found]; + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->irq = get_irq (pdev); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_PCI_BOARD; + + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n", + tint, boards[found].base, board->irq); + + if (probe_sx (board)) { + found++; + fix_sx_pci (pdev, board); + } else + my_iounmap (board->hw_base, board->base); + } + } +#endif + + for (i=0;ihw_base = sx_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_ISA_BOARD; + board->irq = sx_irqmask?-1:0; + + if (probe_sx (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + for (i=0;ihw_base = si_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SI_ISA_BOARD; + board->irq = sx_irqmask ?-1:0; + + if (probe_si (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + if (found) { + printk (KERN_INFO "sx: total of %d boards detected.\n", found); + + if (misc_register(&sx_fw_device) < 0) { + printk(KERN_ERR "SX: Unable to register firmware loader driver.\n"); + return -EIO; + } + } + + func_exit(); + return found?0:-EIO; +} + + + +void cleanup_module(void) +{ + int i; + struct sx_board *board; + + func_enter(); + for (i = 0; i < SX_NBOARDS; i++) { + board = &boards[i]; + if (board->flags & SX_BOARD_INITIALIZED) { + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base); + /* The board should stop messing with us. + (actually I mean the interrupt) */ + sx_reset (board); + if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED)) + free_irq (board->irq, board); + + /* It is safe/allowed to del_timer a non-active timer */ + del_timer (& board->timer); + my_iounmap (board->hw_base, board->base); + } + } + if (misc_deregister(&sx_fw_device) < 0) { + printk (KERN_INFO "sx: couldn't deregister firmware loader device\n"); + } + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized); + if (sx_initialized) + sx_release_drivers (); + + kfree (sx_ports); + kfree (sx_termios); + kfree (sx_termios_locked); + func_exit(); +} + + +#ifdef DEBUG +void my_hd (unsigned char *addr, int len) +{ + int i, j, ch; + + for (i=0;i 0x7f)?'.':ch)); + } + printk ("\n"); + } +} +#endif + +#ifdef MODULE +#undef func_enter +#undef func_exit + +#include "generic_serial.c" +#endif + + +/* + * Anybody who knows why this doesn't work for me, please tell me -- REW. + * Snatched from scsi.c (fixed one spelling error): + * Overrides for Emacs so that we follow Linus' tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/sx.h linux/drivers/char/sx.h --- v2.2.10/linux/drivers/char/sx.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sx.h Mon Aug 9 12:05:09 1999 @@ -0,0 +1,180 @@ + +/* + * sx.h + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * SX serial driver. + * -- Supports SI, XIO and SX host cards. + * -- Supports TAs, MTAs and SXDCs. + * + * Version 1.3 -- March, 1999. + * + */ + +#define SX_NBOARDS 4 +#define SX_PORTSPERBOARD 32 +#define SX_NPORTS (SX_NBOARDS * SX_PORTSPERBOARD) + +#ifdef __KERNEL__ + +#define SX_MAGIC 0x12345678 + +struct sx_port { + struct gs_port gs; + /* + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + */ + struct wait_queue *shutdown_wait; + int ch_base; + int c_dcd; + struct sx_board *board; + int line; + int locks; +}; + +struct sx_board { + int magic; + unsigned int base; + unsigned int hw_base; + int port_base; /* Number of the first port */ + struct sx_port *ports; + int nports; + int flags; + int irq; + int poll; + int ta_type; + struct timer_list timer; + int locks; +}; + +struct vpd_prom { + unsigned short id; + char hwrev; + char hwass; + int uniqid; + char myear; + char mweek; + char hw_feature[5]; + char oem_id; + char identifier[16]; +}; + +#ifndef MOD_RS232DB25MALE +#define MOD_RS232DB25MALE 0x0a +#endif + + +#define SX_BOARD_PRESENT 0x00000001 +#define SX_ISA_BOARD 0x00000002 +#define SX_PCI_BOARD 0x00000004 +#define SI_ISA_BOARD 0x00000008 +#define SX_BOARD_INITIALIZED 0x00000010 +#define SX_IRQ_ALLOCATED 0x00000020 + +#define SX_BOARD_TYPE (SX_ISA_BOARD|SX_PCI_BOARD|SI_ISA_BOARD) + +#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_ISA_BOARD)) +#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD) + + +#define SERIAL_TYPE_NORMAL 1 + +/* The SI processor clock is required to calculate the cc_int_count register + value for the SI cards. */ +#define SI_PROCESSOR_CLOCK 25000000 + + +/* port flags */ +/* Make sure these don't clash with gs flags or async flags */ +#define SX_RX_THROTTLE 0x0000001 + + + +#define SX_PORT_TRANSMIT_LOCK 0 +#define SX_BOARD_INTR_LOCK 0 + + + +/* Debug flags. Add these together to get more debug info. */ + +#define SX_DEBUG_OPEN 0x00000001 +#define SX_DEBUG_SETTING 0x00000002 +#define SX_DEBUG_FLOW 0x00000004 +#define SX_DEBUG_MODEMSIGNALS 0x00000008 +#define SX_DEBUG_TERMIOS 0x00000010 +#define SX_DEBUG_TRANSMIT 0x00000020 +#define SX_DEBUG_RECEIVE 0x00000040 +#define SX_DEBUG_INTERRUPTS 0x00000080 +#define SX_DEBUG_PROBE 0x00000100 +#define SX_DEBUG_INIT 0x00000200 +#define SX_DEBUG_CLEANUP 0x00000400 +#define SX_DEBUG_CLOSE 0x00000800 +#define SX_DEBUG_FIRMWARE 0x00001000 +#define SX_DEBUG_MEMTEST 0x00002000 + +#define SX_DEBUG_ALL 0xffffffff + + +#define O_OTHER(tty) \ + ((O_OLCUC(tty)) ||\ + (O_ONLCR(tty)) ||\ + (O_OCRNL(tty)) ||\ + (O_ONOCR(tty)) ||\ + (O_ONLRET(tty)) ||\ + (O_OFILL(tty)) ||\ + (O_OFDEL(tty)) ||\ + (O_NLDLY(tty)) ||\ + (O_CRDLY(tty)) ||\ + (O_TABDLY(tty)) ||\ + (O_BSDLY(tty)) ||\ + (O_VTDLY(tty)) ||\ + (O_FFDLY(tty))) + +/* Same for input. */ +#define I_OTHER(tty) \ + ((I_INLCR(tty)) ||\ + (I_IGNCR(tty)) ||\ + (I_ICRNL(tty)) ||\ + (I_IUCLC(tty)) ||\ + (L_ISIG(tty))) + +#define MOD_TA ( TA>>4) +#define MOD_MTA (MTA_CD1400>>4) +#define MOD_SXDC ( SXDC>>4) + + +/* We copy the download code over to the card in chunks of ... bytes */ +#define SX_CHUNK_SIZE 128 + +#endif /* __KERNEL__ */ + + + +/* Specialix document 6210046-11 page 3 */ +#define SPX(X) (('S'<<24) | ('P' << 16) | (X)) + +/* Specialix-Linux specific IOCTLS. */ +#define SPXL(X) (SPX(('L' << 8) | (X))) + + +#define SXIO_SET_BOARD SPXL(0x01) +#define SXIO_GET_TYPE SPXL(0x02) +#define SXIO_DOWNLOAD SPXL(0x03) +#define SXIO_INIT SPXL(0x04) +#define SXIO_SETDEBUG SPXL(0x05) +#define SXIO_GETDEBUG SPXL(0x06) +#define SXIO_DO_RAMTEST SPXL(0x07) +#define SXIO_SETGSDEBUG SPXL(0x08) +#define SXIO_GETGSDEBUG SPXL(0x09) + + +#ifndef SXCTL_MISC_MINOR +/* Allow others to gather this into "major.h" or something like that */ +#define SXCTL_MISC_MINOR 167 +#endif + +#define SX_TYPE_SX 0x01 +#define SX_TYPE_SI 0x02 + diff -u --recursive --new-file v2.2.10/linux/drivers/char/sxboards.h linux/drivers/char/sxboards.h --- v2.2.10/linux/drivers/char/sxboards.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sxboards.h Mon Aug 9 12:05:09 1999 @@ -0,0 +1,181 @@ +/************************************************************************/ +/* */ +/* Title : SX/SI/XIO Board Hardware Definitions */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO board hardware */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. + +*/ + +#ifndef _sxboards_h /* If SXBOARDS.H not already defined */ +#define _sxboards_h 1 + +/***************************************************************************** +******************************* ****************************** +******************************* Board Types ****************************** +******************************* ****************************** +*****************************************************************************/ + +/* BUS types... */ +#define BUS_ISA 0 +#define BUS_MCA 1 +#define BUS_EISA 2 +#define BUS_PCI 3 + +/* Board phases... */ +#define SI1_Z280 1 +#define SI2_Z280 2 +#define SI3_T225 3 + +/* Board types... */ +#define CARD_TYPE(bus,phase) (bus<<4|phase) +#define CARD_BUS(type) ((type>>4)&0xF) +#define CARD_PHASE(type) (type&0xF) + +#define TYPE_SI2_ISA CARD_TYPE(BUS_ISA,SI2_Z280) +#define TYPE_SI2_EISA CARD_TYPE(BUS_EISA,SI2_Z280) +#define TYPE_SI2_PCI CARD_TYPE(BUS_PCI,SI2_Z280) + +#define TYPE_SX_ISA CARD_TYPE(BUS_ISA,SI3_T225) +#define TYPE_SX_PCI CARD_TYPE(BUS_PCI,SI3_T225) + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 2 Z280 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* ISA board details... */ +#define SI2_ISA_WINDOW_LEN 0x8000 /* 32 Kbyte shared memory window */ +#define SI2_ISA_MEMORY_LEN 0x7FF8 /* Usable memory */ +#define SI2_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SI2_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SI2_ISA_ADDR_STEP SI2_ISA_WINDOW_LEN/* ISA board address step */ +#define SI2_ISA_IRQ_MASK 0x9800 /* IRQs 15,12,11 */ + +/* ISA board, register definitions... */ +#define SI2_ISA_ID_BASE 0x7FF8 /* READ: Board ID string */ +#define SI2_ISA_RESET SI2_ISA_ID_BASE /* WRITE: Host Reset */ +#define SI2_ISA_IRQ11 (SI2_ISA_ID_BASE+1) /* WRITE: Set IRQ11 */ +#define SI2_ISA_IRQ12 (SI2_ISA_ID_BASE+2) /* WRITE: Set IRQ12 */ +#define SI2_ISA_IRQ15 (SI2_ISA_ID_BASE+3) /* WRITE: Set IRQ15 */ +#define SI2_ISA_IRQSET (SI2_ISA_ID_BASE+4) /* WRITE: Set Host Interrupt */ +#define SI2_ISA_INTCLEAR (SI2_ISA_ID_BASE+5) /* WRITE: Enable Host Interrupt */ + +#define SI2_ISA_IRQ11_SET 0x10 +#define SI2_ISA_IRQ11_CLEAR 0x00 +#define SI2_ISA_IRQ12_SET 0x10 +#define SI2_ISA_IRQ12_CLEAR 0x00 +#define SI2_ISA_IRQ15_SET 0x10 +#define SI2_ISA_IRQ15_CLEAR 0x00 +#define SI2_ISA_INTCLEAR_SET 0x10 +#define SI2_ISA_INTCLEAR_CLEAR 0x00 +#define SI2_ISA_IRQSET_CLEAR 0x10 +#define SI2_ISA_IRQSET_SET 0x00 +#define SI2_ISA_RESET_SET 0x00 +#define SI2_ISA_RESET_CLEAR 0x10 + +/* PCI board details... */ +#define SI2_PCI_WINDOW_LEN 0x100000 /* 1 Mbyte memory window */ + +/* PCI board register definitions... */ +#define SI2_PCI_SET_IRQ 0x40001 /* Set Host Interrupt */ +#define SI2_PCI_RESET 0xC0001 /* Host Reset */ + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 3 T225 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* General board details... */ +#define SX_WINDOW_LEN 64*1024 /* 64 Kbyte memory window */ + +/* ISA board details... */ +#define SX_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SX_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SX_ISA_ADDR_STEP SX_WINDOW_LEN /* ISA board address step */ +#define SX_ISA_IRQ_MASK 0x9E00 /* IRQs 15,12,11,10,9 */ + +/* Hardware register definitions... */ +#define SX_EVENT_STATUS 0x7800 /* READ: T225 Event Status */ +#define SX_EVENT_STROBE 0x7800 /* WRITE: T225 Event Strobe */ +#define SX_EVENT_ENABLE 0x7880 /* WRITE: T225 Event Enable */ +#define SX_VPD_ROM 0x7C00 /* READ: Vital Product Data ROM */ +#define SX_CONFIG 0x7C00 /* WRITE: Host Configuration Register */ +#define SX_IRQ_STATUS 0x7C80 /* READ: Host Interrupt Status */ +#define SX_SET_IRQ 0x7C80 /* WRITE: Set Host Interrupt */ +#define SX_RESET_STATUS 0x7D00 /* READ: Host Reset Status */ +#define SX_RESET 0x7D00 /* WRITE: Host Reset */ +#define SX_RESET_IRQ 0x7D80 /* WRITE: Reset Host Interrupt */ + +/* SX_VPD_ROM definitions... */ +#define SX_VPD_SLX_ID1 0x00 +#define SX_VPD_SLX_ID2 0x01 +#define SX_VPD_HW_REV 0x02 +#define SX_VPD_HW_ASSEM 0x03 +#define SX_VPD_UNIQUEID4 0x04 +#define SX_VPD_UNIQUEID3 0x05 +#define SX_VPD_UNIQUEID2 0x06 +#define SX_VPD_UNIQUEID1 0x07 +#define SX_VPD_MANU_YEAR 0x08 +#define SX_VPD_MANU_WEEK 0x09 +#define SX_VPD_IDENT 0x10 +#define SX_VPD_IDENT_STRING "JET HOST BY KEV#" + +/* SX unique identifiers... */ +#define SX_UNIQUEID_MASK 0xF0 +#define SX_ISA_UNIQUEID1 0x20 +#define SX_PCI_UNIQUEID1 0x50 + +/* SX_CONFIG definitions... */ +#define SX_CONF_BUSEN 0x02 /* Enable T225 memory and I/O */ +#define SX_CONF_HOSTIRQ 0x04 /* Enable board to host interrupt */ + +/* SX bootstrap... */ +#define SX_BOOTSTRAP "\x28\x20\x21\x02\x60\x0a" +#define SX_BOOTSTRAP_SIZE 6 +#define SX_BOOTSTRAP_ADDR (0x8000-SX_BOOTSTRAP_SIZE) + +/***************************************************************************** +********************************** ********************************** +********************************** EISA ********************************** +********************************** ********************************** +*****************************************************************************/ + +#define SI2_EISA_OFF 0x42 +#define SI2_EISA_VAL 0x01 + +/***************************************************************************** +*********************************** ********************************** +*********************************** PCI ********************************** +*********************************** ********************************** +*****************************************************************************/ + +/* General definitions... */ + +#define SPX_VENDOR_ID 0x11CB /* Assigned by the PCI SIG */ +#define SPX_DEVICE_ID 0x4000 /* SI/XIO boards */ +#define SPX_PLXDEVICE_ID 0x2000 /* SX boards */ + +#define SPX_SUB_VENDOR_ID SPX_VENDOR_ID /* Same as vendor id */ +#define SI2_SUB_SYS_ID 0x400 /* Phase 2 (Z280) board */ +#define SX_SUB_SYS_ID 0x200 /* Phase 3 (t225) board */ + +#endif /*_sxboards_h */ + +/* End of SXBOARDS.H */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/sxwindow.h linux/drivers/char/sxwindow.h --- v2.2.10/linux/drivers/char/sxwindow.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sxwindow.h Mon Aug 9 12:05:09 1999 @@ -0,0 +1,393 @@ +/************************************************************************/ +/* */ +/* Title : SX Shared Memory Window Structure */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO cards shared */ +/* memory window structure: */ +/* SXCARD */ +/* SXMODULE */ +/* SXCHANNEL */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. (based on STRUCT.H) + +*/ + +#ifndef _sxwindow_h /* If SXWINDOW.H not already defined */ +#define _sxwindow_h 1 + +/***************************************************************************** +*************************** *************************** +*************************** Common Definitions *************************** +*************************** *************************** +*****************************************************************************/ + +typedef struct _SXCARD *PSXCARD; /* SXCARD structure pointer */ +typedef struct _SXMODULE *PMOD; /* SXMODULE structure pointer */ +typedef struct _SXCHANNEL *PCHAN; /* SXCHANNEL structure pointer */ + +/***************************************************************************** +********************************* ********************************* +********************************* SXCARD ********************************* +********************************* ********************************* +*****************************************************************************/ + +typedef struct _SXCARD +{ + BYTE cc_init_status; /* 0x00 Initialisation status */ + BYTE cc_mem_size; /* 0x01 Size of memory on card */ + WORD cc_int_count; /* 0x02 Interrupt count */ + WORD cc_revision; /* 0x04 Download code revision */ + BYTE cc_isr_count; /* 0x06 Count when ISR is run */ + BYTE cc_main_count; /* 0x07 Count when main loop is run */ + WORD cc_int_pending; /* 0x08 Interrupt pending */ + WORD cc_poll_count; /* 0x0A Count when poll is run */ + BYTE cc_int_set_count; /* 0x0C Count when host interrupt is set */ + BYTE cc_rfu[0x80 - 0x0D]; /* 0x0D Pad structure to 128 bytes (0x80) */ + +} SXCARD; + +/* SXCARD.cc_init_status definitions... */ +#define ADAPTERS_FOUND (BYTE)0x01 +#define NO_ADAPTERS_FOUND (BYTE)0xFF + +/* SXCARD.cc_mem_size definitions... */ +#define SX_MEMORY_SIZE (BYTE)0x40 + +/* SXCARD.cc_int_count definitions... */ +#define INT_COUNT_DEFAULT 100 /* Hz */ + +/***************************************************************************** +******************************** ******************************** +******************************** SXMODULE ******************************** +******************************** ******************************** +*****************************************************************************/ + +#define TOP_POINTER(a) ((a)|0x8000) /* Sets top bit of word */ +#define UNTOP_POINTER(a) ((a)&~0x8000) /* Clears top bit of word */ + +typedef struct _SXMODULE +{ + WORD mc_next; /* 0x00 Next module "pointer" (ORed with 0x8000) */ + BYTE mc_type; /* 0x02 Type of TA in terms of number of channels */ + BYTE mc_mod_no; /* 0x03 Module number on SI bus cable (0 closest to card) */ + BYTE mc_dtr; /* 0x04 Private DTR copy (TA only) */ + BYTE mc_rfu1; /* 0x05 Reserved */ + WORD mc_uart; /* 0x06 UART base address for this module */ + BYTE mc_chip; /* 0x08 Chip type / number of ports */ + BYTE mc_current_uart; /* 0x09 Current uart selected for this module */ +#ifdef DOWNLOAD + PCHAN mc_chan_pointer[8]; /* 0x0A Pointer to each channel structure */ +#else + WORD mc_chan_pointer[8]; /* 0x0A Define as WORD if not compiling into download */ +#endif + WORD mc_rfu2; /* 0x1A Reserved */ + BYTE mc_opens1; /* 0x1C Number of open ports on first four ports on MTA/SXDC */ + BYTE mc_opens2; /* 0x1D Number of open ports on second four ports on MTA/SXDC */ + BYTE mc_mods; /* 0x1E Types of connector module attached to MTA/SXDC */ + BYTE mc_rev1; /* 0x1F Revision of first CD1400 on MTA/SXDC */ + BYTE mc_rev2; /* 0x20 Revision of second CD1400 on MTA/SXDC */ + BYTE mc_mtaasic_rev; /* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */ + BYTE mc_rfu3[0x100 - 0x22]; /* 0x22 Pad structure to 256 bytes (0x100) */ + +} SXMODULE; + +/* SXMODULE.mc_type definitions... */ +#define FOUR_PORTS (BYTE)4 +#define EIGHT_PORTS (BYTE)8 + +/* SXMODULE.mc_chip definitions... */ +#define CHIP_MASK 0xF0 +#define TA (BYTE)0 +#define TA4 (TA | FOUR_PORTS) +#define TA8 (TA | EIGHT_PORTS) +#define TA4_ASIC (BYTE)0x0A +#define TA8_ASIC (BYTE)0x0B +#define MTA_CD1400 (BYTE)0x28 +#define SXDC (BYTE)0x48 + +/* SXMODULE.mc_mods definitions... */ +#define MOD_RS232DB25 0x00 /* RS232 DB25 (socket/plug) */ +#define MOD_RS232RJ45 0x01 /* RS232 RJ45 (shielded/opto-isolated) */ +#define MOD_RESERVED_2 0x02 /* Reserved (RS485) */ +#define MOD_RS422DB25 0x03 /* RS422 DB25 Socket */ +#define MOD_RESERVED_4 0x04 /* Reserved */ +#define MOD_PARALLEL 0x05 /* Parallel */ +#define MOD_RESERVED_6 0x06 /* Reserved (RS423) */ +#define MOD_RESERVED_7 0x07 /* Reserved */ +#define MOD_2_RS232DB25 0x08 /* Rev 2.0 RS232 DB25 (socket/plug) */ +#define MOD_2_RS232RJ45 0x09 /* Rev 2.0 RS232 RJ45 */ +#define MOD_RESERVED_A 0x0A /* Rev 2.0 Reserved */ +#define MOD_2_RS422DB25 0x0B /* Rev 2.0 RS422 DB25 */ +#define MOD_RESERVED_C 0x0C /* Rev 2.0 Reserved */ +#define MOD_2_PARALLEL 0x0D /* Rev 2.0 Parallel */ +#define MOD_RESERVED_E 0x0E /* Rev 2.0 Reserved */ +#define MOD_BLANK 0x0F /* Blank Panel */ + +/***************************************************************************** +******************************** ******************************* +******************************** SXCHANNEL ******************************* +******************************** ******************************* +*****************************************************************************/ + +#define TX_BUFF_OFFSET 0x60 /* Transmit buffer offset in channel structure */ +#define BUFF_POINTER(a) (((a)+TX_BUFF_OFFSET)|0x8000) +#define UNBUFF_POINTER(a) (jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET) +#define BUFFER_SIZE 256 +#define HIGH_WATER ((BUFFER_SIZE / 4) * 3) +#define LOW_WATER (BUFFER_SIZE / 4) + +typedef struct _SXCHANNEL +{ + WORD next_item; /* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */ + WORD addr_uart; /* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */ + WORD module; /* 0x04 Offset from window base of parent SXMODULE structure */ + BYTE type; /* 0x06 Chip type / number of ports (copy of mc_chip) */ + BYTE chan_number; /* 0x07 Channel number on the TA/MTA/SXDC */ + WORD xc_status; /* 0x08 Flow control and I/O status */ + BYTE hi_rxipos; /* 0x0A Receive buffer input index */ + BYTE hi_rxopos; /* 0x0B Receive buffer output index */ + BYTE hi_txopos; /* 0x0C Transmit buffer output index */ + BYTE hi_txipos; /* 0x0D Transmit buffer input index */ + BYTE hi_hstat; /* 0x0E Command register */ + BYTE dtr_bit; /* 0x0F INTERNAL DTR control byte (TA only) */ + BYTE txon; /* 0x10 INTERNAL copy of hi_txon */ + BYTE txoff; /* 0x11 INTERNAL copy of hi_txoff */ + BYTE rxon; /* 0x12 INTERNAL copy of hi_rxon */ + BYTE rxoff; /* 0x13 INTERNAL copy of hi_rxoff */ + BYTE hi_mr1; /* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/ + BYTE hi_mr2; /* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/ + BYTE hi_csr; /* 0x16 Clock Select Register (baud rate) */ + BYTE hi_op; /* 0x17 Modem Output Signal */ + BYTE hi_ip; /* 0x18 Modem Input Signal */ + BYTE hi_state; /* 0x19 Channel status */ + BYTE hi_prtcl; /* 0x1A Channel protocol (flow control) */ + BYTE hi_txon; /* 0x1B Transmit XON character */ + BYTE hi_txoff; /* 0x1C Transmit XOFF character */ + BYTE hi_rxon; /* 0x1D Receive XON character */ + BYTE hi_rxoff; /* 0x1E Receive XOFF character */ + BYTE close_prev; /* 0x1F INTERNAL channel previously closed flag */ + BYTE hi_break; /* 0x20 Break and error control */ + BYTE break_state; /* 0x21 INTERNAL copy of hi_break */ + BYTE hi_mask; /* 0x22 Mask for received data */ + BYTE mask; /* 0x23 INTERNAL copy of hi_mask */ + BYTE mod_type; /* 0x24 MTA/SXDC hardware module type */ + BYTE ccr_state; /* 0x25 INTERNAL MTA/SXDC state of CCR register */ + BYTE ip_mask; /* 0x26 Input handshake mask */ + BYTE hi_parallel; /* 0x27 Parallel port flag */ + BYTE par_error; /* 0x28 Error code for parallel loopback test */ + BYTE any_sent; /* 0x29 INTERNAL data sent flag */ + BYTE asic_txfifo_size; /* 0x2A INTERNAL SXDC transmit FIFO size */ + BYTE rfu1[2]; /* 0x2B Reserved */ + BYTE csr; /* 0x2D INTERNAL copy of hi_csr */ +#ifdef DOWNLOAD + PCHAN nextp; /* 0x2E Offset from window base of next channel structure */ +#else + WORD nextp; /* 0x2E Define as WORD if not compiling into download */ +#endif + BYTE prtcl; /* 0x30 INTERNAL copy of hi_prtcl */ + BYTE mr1; /* 0x31 INTERNAL copy of hi_mr1 */ + BYTE mr2; /* 0x32 INTERNAL copy of hi_mr2 */ + BYTE hi_txbaud; /* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */ + BYTE hi_rxbaud; /* 0x34 Extended receive baud rate (SXDC only if((hi_csr&0xF0)==0xF0) */ + BYTE txbreak_state; /* 0x35 INTERNAL MTA/SXDC transmit break state */ + BYTE txbaud; /* 0x36 INTERNAL copy of hi_txbaud */ + BYTE rxbaud; /* 0x37 INTERNAL copy of hi_rxbaud */ + WORD err_framing; /* 0x38 Count of receive framing errors */ + WORD err_parity; /* 0x3A Count of receive parity errors */ + WORD err_overrun; /* 0x3C Count of receive overrun errors */ + WORD err_overflow; /* 0x3E Count of receive buffer overflow errors */ + BYTE rfu2[TX_BUFF_OFFSET - 0x40]; /* 0x40 Reserved until hi_txbuf */ + BYTE hi_txbuf[BUFFER_SIZE]; /* 0x060 Transmit buffer */ + BYTE hi_rxbuf[BUFFER_SIZE]; /* 0x160 Receive buffer */ + BYTE rfu3[0x300 - 0x260]; /* 0x260 Reserved until 768 bytes (0x300) */ + +} SXCHANNEL; + +/* SXCHANNEL.addr_uart definitions... */ +#define FASTPATH 0x1000 /* Set to indicate fast rx/tx processing (TA only) */ + +/* SXCHANNEL.xc_status definitions... */ +#define X_TANY 0x0001 /* XON is any character (TA only) */ +#define X_TION 0x0001 /* Tx interrupts on (MTA only) */ +#define X_TXEN 0x0002 /* Tx XON/XOFF enabled (TA only) */ +#define X_RTSEN 0x0002 /* RTS FLOW enabled (MTA only) */ +#define X_TXRC 0x0004 /* XOFF received (TA only) */ +#define X_RTSLOW 0x0004 /* RTS dropped (MTA only) */ +#define X_RXEN 0x0008 /* Rx XON/XOFF enabled */ +#define X_ANYXO 0x0010 /* XOFF pending/sent or RTS dropped */ +#define X_RXSE 0x0020 /* Rx XOFF sent */ +#define X_NPEND 0x0040 /* Rx XON pending or XOFF pending */ +#define X_FPEND 0x0080 /* Rx XOFF pending */ +#define C_CRSE 0x0100 /* Carriage return sent (TA only) */ +#define C_TEMR 0x0100 /* Tx empty requested (MTA only) */ +#define C_TEMA 0x0200 /* Tx empty acked (MTA only) */ +#define C_ANYP 0x0200 /* Any protocol bar tx XON/XOFF (TA only) */ +#define C_EN 0x0400 /* Cooking enabled (on MTA means port is also || */ +#define C_HIGH 0x0800 /* Buffer previously hit high water */ +#define C_CTSEN 0x1000 /* CTS automatic flow-control enabled */ +#define C_DCDEN 0x2000 /* DCD/DTR checking enabled */ +#define C_BREAK 0x4000 /* Break detected */ +#define C_RTSEN 0x8000 /* RTS automatic flow control enabled (MTA only) */ +#define C_PARITY 0x8000 /* Parity checking enabled (TA only) */ + +/* SXCHANNEL.hi_hstat definitions... */ +#define HS_IDLE_OPEN 0x00 /* Channel open state */ +#define HS_LOPEN 0x02 /* Local open command (no modem monitoring) */ +#define HS_MOPEN 0x04 /* Modem open command (wait for DCD signal) */ +#define HS_IDLE_MPEND 0x06 /* Waiting for DCD signal state */ +#define HS_CONFIG 0x08 /* Configuration command */ +#define HS_CLOSE 0x0A /* Close command */ +#define HS_START 0x0C /* Start transmit break command */ +#define HS_STOP 0x0E /* Stop transmit break command */ +#define HS_IDLE_CLOSED 0x10 /* Closed channel state */ +#define HS_IDLE_BREAK 0x12 /* Transmit break state */ +#define HS_FORCE_CLOSED 0x14 /* Force close command */ +#define HS_RESUME 0x16 /* Clear pending XOFF command */ +#define HS_WFLUSH 0x18 /* Flush transmit buffer command */ +#define HS_RFLUSH 0x1A /* Flush receive buffer command */ +#define HS_SUSPEND 0x1C /* Suspend output command (like XOFF received) */ +#define PARALLEL 0x1E /* Parallel port loopback test command (Diagnostics Only) */ +#define ENABLE_RX_INTS 0x20 /* Enable receive interrupts command (Diagnostics Only) */ +#define ENABLE_TX_INTS 0x22 /* Enable transmit interrupts command (Diagnostics Only) */ +#define ENABLE_MDM_INTS 0x24 /* Enable modem interrupts command (Diagnostics Only) */ +#define DISABLE_INTS 0x26 /* Disable interrupts command (Diagnostics Only) */ + +/* SXCHANNEL.hi_mr1 definitions... */ +#define MR1_BITS 0x03 /* Data bits mask */ +#define MR1_5_BITS 0x00 /* 5 data bits */ +#define MR1_6_BITS 0x01 /* 6 data bits */ +#define MR1_7_BITS 0x02 /* 7 data bits */ +#define MR1_8_BITS 0x03 /* 8 data bits */ +#define MR1_PARITY 0x1C /* Parity mask */ +#define MR1_ODD 0x04 /* Odd parity */ +#define MR1_EVEN 0x00 /* Even parity */ +#define MR1_WITH 0x00 /* Parity enabled */ +#define MR1_FORCE 0x08 /* Force parity */ +#define MR1_NONE 0x10 /* No parity */ +#define MR1_NOPARITY MR1_NONE /* No parity */ +#define MR1_ODDPARITY (MR1_WITH|MR1_ODD) /* Odd parity */ +#define MR1_EVENPARITY (MR1_WITH|MR1_EVEN) /* Even parity */ +#define MR1_MARKPARITY (MR1_FORCE|MR1_ODD) /* Mark parity */ +#define MR1_SPACEPARITY (MR1_FORCE|MR1_EVEN) /* Space parity */ +#define MR1_RTS_RXFLOW 0x80 /* RTS receive flow control */ + +/* SXCHANNEL.hi_mr2 definitions... */ +#define MR2_STOP 0x0F /* Stop bits mask */ +#define MR2_1_STOP 0x07 /* 1 stop bit */ +#define MR2_2_STOP 0x0F /* 2 stop bits */ +#define MR2_CTS_TXFLOW 0x10 /* CTS transmit flow control */ +#define MR2_RTS_TOGGLE 0x20 /* RTS toggle on transmit */ +#define MR2_NORMAL 0x00 /* Normal mode */ +#define MR2_AUTO 0x40 /* Auto-echo mode (TA only) */ +#define MR2_LOCAL 0x80 /* Local echo mode */ +#define MR2_REMOTE 0xC0 /* Remote echo mode (TA only) */ + +/* SXCHANNEL.hi_csr definitions... */ +#define CSR_75 0x0 /* 75 baud */ +#define CSR_110 0x1 /* 110 baud (TA), 115200 (MTA/SXDC) */ +#define CSR_38400 0x2 /* 38400 baud */ +#define CSR_150 0x3 /* 150 baud */ +#define CSR_300 0x4 /* 300 baud */ +#define CSR_600 0x5 /* 600 baud */ +#define CSR_1200 0x6 /* 1200 baud */ +#define CSR_2000 0x7 /* 2000 baud */ +#define CSR_2400 0x8 /* 2400 baud */ +#define CSR_4800 0x9 /* 4800 baud */ +#define CSR_1800 0xA /* 1800 baud */ +#define CSR_9600 0xB /* 9600 baud */ +#define CSR_19200 0xC /* 19200 baud */ +#define CSR_57600 0xD /* 57600 baud */ +#define CSR_EXTBAUD 0xF /* Extended baud rate (hi_txbaud/hi_rxbaud) */ + +/* SXCHANNEL.hi_op definitions... */ +#define OP_RTS 0x01 /* RTS modem output signal */ +#define OP_DTR 0x02 /* DTR modem output signal */ + +/* SXCHANNEL.hi_ip definitions... */ +#define IP_CTS 0x02 /* CTS modem input signal */ +#define IP_DCD 0x04 /* DCD modem input signal */ +#define IP_DSR 0x20 /* DTR modem input signal */ +#define IP_RI 0x40 /* RI modem input signal */ + +/* SXCHANNEL.hi_state definitions... */ +#define ST_BREAK 0x01 /* Break received (clear with config) */ +#define ST_DCD 0x02 /* DCD signal changed state */ + +/* SXCHANNEL.hi_prtcl definitions... */ +#define SP_TANY 0x01 /* Transmit XON/XANY (if SP_TXEN enabled) */ +#define SP_TXEN 0x02 /* Transmit XON/XOFF flow control */ +#define SP_CEN 0x04 /* Cooking enabled */ +#define SP_RXEN 0x08 /* Rx XON/XOFF enabled */ +#define SP_DCEN 0x20 /* DCD / DTR check */ +#define SP_DTR_RXFLOW 0x40 /* DTR receive flow control */ +#define SP_PAEN 0x80 /* Parity checking enabled */ + +/* SXCHANNEL.hi_break definitions... */ +#define BR_IGN 0x01 /* Ignore any received breaks */ +#define BR_INT 0x02 /* Interrupt on received break */ +#define BR_PARMRK 0x04 /* Enable parmrk parity error processing */ +#define BR_PARIGN 0x08 /* Ignore chars with parity errors */ +#define BR_ERRINT 0x80 /* Treat parity/framing/overrun errors as exceptions */ + +/* SXCHANNEL.par_error definitions.. */ +#define DIAG_IRQ_RX 0x01 /* Indicate serial receive interrupt (diags only) */ +#define DIAG_IRQ_TX 0x02 /* Indicate serial transmit interrupt (diags only) */ +#define DIAG_IRQ_MD 0x04 /* Indicate serial modem interrupt (diags only) */ + +/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */ +#define BAUD_75 0x00 /* 75 baud */ +#define BAUD_115200 0x01 /* 115200 baud */ +#define BAUD_38400 0x02 /* 38400 baud */ +#define BAUD_150 0x03 /* 150 baud */ +#define BAUD_300 0x04 /* 300 baud */ +#define BAUD_600 0x05 /* 600 baud */ +#define BAUD_1200 0x06 /* 1200 baud */ +#define BAUD_2000 0x07 /* 2000 baud */ +#define BAUD_2400 0x08 /* 2400 baud */ +#define BAUD_4800 0x09 /* 4800 baud */ +#define BAUD_1800 0x0A /* 1800 baud */ +#define BAUD_9600 0x0B /* 9600 baud */ +#define BAUD_19200 0x0C /* 19200 baud */ +#define BAUD_57600 0x0D /* 57600 baud */ +#define BAUD_230400 0x0E /* 230400 baud */ +#define BAUD_460800 0x0F /* 460800 baud */ +#define BAUD_921600 0x10 /* 921600 baud */ +#define BAUD_50 0x11 /* 50 baud */ +#define BAUD_110 0x12 /* 110 baud */ +#define BAUD_134_5 0x13 /* 134.5 baud */ +#define BAUD_200 0x14 /* 200 baud */ +#define BAUD_7200 0x15 /* 7200 baud */ +#define BAUD_56000 0x16 /* 56000 baud */ +#define BAUD_64000 0x17 /* 64000 baud */ +#define BAUD_76800 0x18 /* 76800 baud */ +#define BAUD_128000 0x19 /* 128000 baud */ +#define BAUD_150000 0x1A /* 150000 baud */ +#define BAUD_14400 0x1B /* 14400 baud */ +#define BAUD_256000 0x1C /* 256000 baud */ +#define BAUD_28800 0x1D /* 28800 baud */ + +/* SXCHANNEL.txbreak_state definiions... */ +#define TXBREAK_OFF 0 /* Not sending break */ +#define TXBREAK_START 1 /* Begin sending break */ +#define TXBREAK_START1 2 /* Begin sending break, part 1 */ +#define TXBREAK_ON 3 /* Sending break */ +#define TXBREAK_STOP 4 /* Stop sending break */ +#define TXBREAK_STOP1 5 /* Stop sending break, part 1 */ + +#endif /* _sxwindow_h */ + +/* End of SXWINDOW.H */ + diff -u --recursive --new-file v2.2.10/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.2.10/linux/drivers/char/sysrq.c Wed Nov 25 17:25:17 1998 +++ linux/drivers/char/sysrq.c Mon Aug 9 12:05:01 1999 @@ -28,6 +28,10 @@ #include #endif +#ifdef CONFIG_MAGIC_SYSRQ +int sysrq_enabled = 1; +#endif + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; diff -u --recursive --new-file v2.2.10/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.2.10/linux/drivers/char/tty_io.c Mon Mar 22 10:06:21 1999 +++ linux/drivers/char/tty_io.c Mon Aug 9 12:05:09 1999 @@ -2166,6 +2166,9 @@ #ifdef CONFIG_SPECIALIX specialix_init(); #endif +#ifdef CONFIG_SX + sx_init(); +#endif #ifdef CONFIG_8xx rs_8xx_init(); #endif /* CONFIG_8xx */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.2.10/linux/drivers/char/videodev.c Wed Jun 2 11:29:28 1999 +++ linux/drivers/char/videodev.c Mon Aug 9 12:04:39 1999 @@ -63,6 +63,9 @@ #ifdef CONFIG_RADIO_RTRACK extern int rtrack_init(struct video_init *); #endif +#ifdef CONFIG_RADIO_RTRACK2 +extern int rtrack2_init(struct video_init *); +#endif #ifdef CONFIG_RADIO_SF16FMI extern int fmi_init(struct video_init *); #endif @@ -81,6 +84,9 @@ #ifdef CONFIG_VIDEO_PMS extern int init_pms_cards(struct video_init *); #endif +#ifdef CONFIG_VIDEO_ZORAN +extern int init_zoran_cards(struct video_init *); +#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -108,6 +114,9 @@ #ifdef CONFIG_RADIO_RTRACK {"RTrack", rtrack_init}, #endif +#ifdef CONFIG_RADIO_RTRACK2 + {"RTrack2", rtrack2_init}, +#endif #ifdef CONFIG_RADIO_SF16FMI {"SF16FMI", fmi_init}, #endif @@ -123,6 +132,9 @@ #ifdef CONFIG_RADIO_TYPHOON {"radio-typhoon", typhoon_init}, #endif +#ifdef CONFIG_VIDEO_ZORAN + {"zoran", init_zoran_cards}, +#endif {"end", NULL} }; diff -u --recursive --new-file v2.2.10/linux/drivers/char/vino.c linux/drivers/char/vino.c --- v2.2.10/linux/drivers/char/vino.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/vino.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,276 @@ +/* $Id: vino.c,v 1.4 1999/02/09 23:59:36 ulfc Exp $ + * drivers/char/vino.c + * + * (incomplete) Driver for the Vino Video input system found in SGI Indys. + * + * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) + * + * This isn't complete yet, please don't expect any video until I've written + * some more code. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vino.h" + +struct vino_device { + struct video_device vdev; + + unsigned long chan; +#define VINO_CHAN_A 0 +#define VINO_CHAN_B 1 + + unsigned long flags; +#define VINO_DMA_ACTIVE (1<<0) +}; + +/* We can actually receive TV and IndyCam input at the same time. Believe it or + * not.. + */ +static struct vino_device vino[2]; + +/* Those registers have to be accessed by either *one* 64 bit write or *one* 64 + * bit read. We need some asm to fix this. We can't use mips3 as standard + * because we just save 32 bits at context switch. + */ + +static __inline__ unsigned long long vino_reg_read(unsigned long addr) +{ + unsigned long long ret __attribute__ ((aligned (64))); + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "sd\t$1,(%1)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&ret) + :"$1"); + restore_flags(flags); + + return ret; +} + +static __inline__ void vino_reg_write(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + /* we might lose the upper parts of the registers which are not saved + * if there comes an interrupt in our way, play safe */ + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "sd\t$1,(%1)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (&value), + "r" (virt_addr) + :"$1"); + restore_flags(flags); +} + +static __inline__ void vino_reg_and(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "ld\t$2,(%1)\n\t" + "and\t$1,$1,$2\n\t" + "sd\t$1,(%0)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&value) + :"$1","$2"); + restore_flags(flags); +} + +static __inline__ void vino_reg_or(unsigned long long value, + unsigned long addr) +{ + unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE); + unsigned long flags; + + save_and_cli(flags); + __asm__ __volatile__( + ".set\tmips3\n\t" + ".set\tnoat\n\t" + "ld\t$1,(%0)\n\t" + "ld\t$2,(%1)\n\t" + "or\t$1,$1,$2\n\t" + "sd\t$1,(%0)\n\t" + ".set\tat\n\t" + ".set\tmips0" + : + :"r" (virt_addr), + "r" (&value) + :"$1","$2"); + restore_flags(flags); +} + +static int vino_dma_setup(void) +{ + return 0; +} + +static void vino_dma_stop(void) +{ + +} + +static int vino_init(void) +{ + unsigned long ret; + unsigned short rev, id; + unsigned long long foo; + unsigned long *bar; + + bar = (unsigned long *) &foo; + + ret = vino_reg_read(VINO_REVID); + + rev = (ret & VINO_REVID_REV_MASK); + id = (ret & VINO_REVID_ID_MASK) >> 4; + + printk("Vino: ID:%02hx Rev:%02hx\n", id, rev); + + foo = vino_reg_read(VINO_A_DESC_DATA0); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA1); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA2); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_A_DESC_DATA3); + printk("0x%lx", bar[0]); + printk("%lx\n", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA0); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA1); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA2); + printk("0x%lx", bar[0]); + printk("%lx ", bar[1]); + foo = vino_reg_read(VINO_B_DESC_DATA3); + printk("0x%lx", bar[0]); + printk("%lx\n", bar[1]); + + return 0; +} + +static void vino_dma_go(struct vino_device *v) +{ + +} + +/* Reset the vino back to default state */ + +static void vino_setup(struct vino_device *v) +{ + +} + +static int vino_open(struct video_device *dev, int flags) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static void vino_close(struct video_device *dev) +{ + MOD_DEC_USE_COUNT; +} + +static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + return 0; +} + +static int vino_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + return 0; +} + +static struct video_device vino_dev = { + "Vino IndyCam/TV", + VID_TYPE_CAPTURE, + VID_HARDWARE_VINO, + vino_open, + vino_close, + NULL, /* vino_read */ + NULL, /* vino_write */ + NULL, /* vino_poll */ + vino_ioctl, + vino_mmap, + NULL, /* vino_init */ + NULL, + 0, + 0 +}; + +__initfunc(int init_vino(struct video_device *dev)) +{ + int err; + + err = vino_init(); + if (err) + return err; + +#if 0 + if (video_register_device(&vinodev, VFL_TYPE_GRABBER) == -1) { + return -ENODEV; + } +#endif + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + int err; + + err = vino_init(); + if (err) + return err; + + return 0; +} + +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/char/vino.h linux/drivers/char/vino.h --- v2.2.10/linux/drivers/char/vino.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/vino.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,118 @@ +/* $Id: vino.h,v 1.2 1999/02/09 23:03:53 ulfc Exp $ + * drivers/sgi/vino.h + * + * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se) + */ + +#define VINO_BASE 0x0008000 + +#define VINO_REVID 0x0000 +#define VINO_CTRL 0x0008 +#define VINO_INTSTAT 0x0010 /* Interrupt status */ +#define VINO_I2C_CTRL 0x0018 +#define VINO_I2C_DATA 0x0020 +#define VINO_A_ALPHA 0x0028 /* Channel A ... */ +#define VINO_A_CLIPS 0x0030 /* Clipping start */ +#define VINO_A_CLIPE 0x0038 /* Clipping end */ +#define VINO_A_FRAMERT 0x0040 /* Framerate */ +#define VINO_A_FLDCNT 0x0048 /* Field counter */ +#define VINO_A_LNSZ 0x0050 +#define VINO_A_LNCNT 0x0058 +#define VINO_A_PGIX 0x0060 /* Page index */ +#define VINO_A_DESC_PTR 0x0068 /* Ptr to next four descriptors */ +#define VINO_A_DESC_TLB_PTR 0x0070 /* Ptr to start of descriptor table */ +#define VINO_A_DESC_DATA0 0x0078 /* Descriptor data 0 */ +#define VINO_A_DESC_DATA1 0x0080 /* ... */ +#define VINO_A_DESC_DATA2 0x0088 +#define VINO_A_DESC_DATA3 0x0090 +#define VINO_A_FIFO_THRESHOLD 0x0098 /* FIFO threshold */ +#define VINO_A_FIFO_RP 0x00a0 +#define VINO_A_FIFO_WP 0x00a8 +#define VINO_B_ALPHA 0x00b0 /* Channel B ... */ +#define VINO_B_CLIPS 0x00b8 +#define VINO_B_CLIPE 0x00c0 +#define VINO_B_FRAMERT 0x00c8 +#define VINO_B_FLDCNT 0x00d0 +#define VINO_B_LNSZ 0x00d8 +#define VINO_B_LNCNT 0x00e0 +#define VINO_B_PGIX 0x00e8 +#define VINO_B_DESC_PTR 0x00f0 +#define VINO_B_DESC_TLB_PTR 0x00f8 +#define VINO_B_DESC_DATA0 0x0100 +#define VINO_B_DESC_DATA1 0x0108 +#define VINO_B_DESC_DATA2 0x0110 +#define VINO_B_DESC_DATA3 0x0118 +#define VINO_B_FIFO_THRESHOLD 0x0120 +#define VINO_B_FIFO_RP 0x0128 +#define VINO_B_FIFO_WP 0x0130 + +/* Bits in the VINO_REVID register */ + +#define VINO_REVID_REV_MASK 0x000f /* bits 0:3 */ +#define VINO_REVID_ID_MASK 0x00f0 /* bits 4:7 */ + +/* Bits in the VINO_CTRL register */ + +#define VINO_CTRL_LITTLE_ENDIAN (1<<0) +#define VINO_CTRL_A_FIELD_TRANS_INT (1<<1) /* Field transferred int */ +#define VINO_CTRL_A_FIFO_OF_INT (1<<2) /* FIFO overflow int */ +#define VINO_CTRL_A_END_DESC_TBL_INT (1<<3) /* End of desc table int */ +#define VINO_CTRL_B_FIELD_TRANS_INT (1<<4) /* Field transferred int */ +#define VINO_CTRL_B_FIFO_OF_INT (1<<5) /* FIFO overflow int */ +#define VINO_CTRL_B_END_DESC_TLB_INT (1<<6) /* End of desc table int */ +#define VINO_CTRL_A_DMA_ENBL (1<<7) +#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8) +#define VINO_CTRL_A_SYNC_ENBL (1<<9) +#define VINO_CTRL_A_SELECT (1<<10) /* 1=D1 0=Philips */ +#define VINO_CTRL_A_RGB (1<<11) /* 1=RGB 0=YUV */ +#define VINO_CTRL_A_LUMA_ONLY (1<<12) +#define VINO_CTRL_A_DEC_ENBL (1<<13) /* Decimation */ +#define VINO_CTRL_A_DEC_SCALE_MASK 0x1c000 /* bits 14:17 */ +#define VINO_CTRL_A_DEC_HOR_ONLY (1<<17) /* Horizontal only */ +#define VINO_CTRL_A_DITHER (1<<18) /* 24 -> 8 bit dither */ +#define VINO_CTRL_B_DMA_ENBL (1<<19) +#define VINO_CTRL_B_INTERLEAVE_ENBL (1<<20) +#define VINO_CTRL_B_SYNC_ENBL (1<<21) +#define VINO_CTRL_B_SELECT (1<<22) /* 1=D1 0=Philips */ +#define VINO_CTRL_B_RGB (1<<22) /* 1=RGB 0=YUV */ +#define VINO_CTRL_B_LUMA_ONLY (1<<23) +#define VINO_CTRL_B_DEC_ENBL (1<<24) /* Decimation */ +#define VINO_CTRL_B_DEC_SCALE_MASK 0x1c000000 /* bits 25:28 */ +#define VINO_CTRL_B_DEC_HOR_ONLY (1<<29) /* Decimation horizontal only */ +#define VINO_CTRL_B_DITHER (1<<30) /* ChanB 24 -> 8 bit dither */ + +/* Bits in the Interrupt and Status register */ + +#define VINO_INTSTAT_A_FIELD_TRANS (1<<0) /* Field transferred int */ +#define VINO_INTSTAT_A_FIFO_OF (1<<1) /* FIFO overflow int */ +#define VINO_INTSTAT_A_END_DESC_TBL (1<<2) /* End of desc table int */ +#define VINO_INTSTAT_B_FIELD_TRANS (1<<3) /* Field transferred int */ +#define VINO_INTSTAT_B_FIFO_OF (1<<4) /* FIFO overflow int */ +#define VINO_INTSTAT_B_END_DESC_TBL (1<<5) /* End of desc table int */ + +/* Bits in the Clipping Start register */ + +#define VINO_CLIPS_START 0x3ff /* bits 0:9 */ +#define VINO_CLIPS_ODD_MASK 0x7fc00 /* bits 10:18 */ +#define VINO_CLIPS_EVEN_MASK 0xff80000 /* bits 19:27 */ + +/* Bits in the Clipping End register */ + +#define VINO_CLIPE_END 0x3ff /* bits 0:9 */ +#define VINO_CLIPE_ODD_MASK 0x7fc00 /* bits 10:18 */ +#define VINO_CLIPE_EVEN_MASK 0xff80000 /* bits 19:27 */ + +/* Bits in the Frame Rate register */ + +#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */ +#define VINO_FRAMERT_RT_MASK 0x1ffe /* bits 1:12 */ + +/* Bits in the VINO_I2C_CTRL */ + +#define VINO_CTRL_I2C_IDLE (1<<0) /* write: 0=force idle + * read: 0=idle 1=not idle */ +#define VINO_CTRL_I2C_DIR (1<<1) /* 0=read 1=write */ +#define VINO_CTRL_I2C_MORE_BYTES (1<<2) /* 0=last byte 1=more bytes */ +#define VINO_CTRL_I2C_TRANS_BUSY (1<<4) /* 0=trans done 1=trans busy */ +#define VINO_CTRL_I2C_ACK (1<<5) /* 0=ack received 1=ack not */ +#define VINO_CTRL_I2C_BUS_ERROR (1<<7) /* 0=no bus err 1=bus err */ diff -u --recursive --new-file v2.2.10/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.2.10/linux/drivers/char/vt.c Wed Feb 3 22:57:41 1999 +++ linux/drivers/char/vt.c Mon Aug 9 12:04:39 1999 @@ -88,7 +88,8 @@ * comments - KDMKTONE doesn't put the process to sleep. */ -#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__) +#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ + || (defined(__mips__) && !defined(CONFIG_SGI)) static void kd_nosound(unsigned long ignored) diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.2.10/linux/drivers/isdn/Config.in Mon Mar 15 16:11:29 1999 +++ linux/drivers/isdn/Config.in Mon Aug 9 12:04:39 1999 @@ -9,6 +9,7 @@ fi fi bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO +bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION if [ "$CONFIG_X25" != "n" ]; then bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25 fi @@ -19,37 +20,53 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO if [ "$CONFIG_HISAX_EURO" != "n" ]; then - bool 'Support for german tarifinfo' CONFIG_DE_AOC - bool 'Support for australian Microlink service (not for std. EURO)' CONFIG_HISAX_ML + bool 'Support for german chargeinfo' CONFIG_DE_AOC + bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE + bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC fi bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6 bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0 bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3 - bool 'HiSax Support for Teles 16.3c' CONFIG_HISAX_TELES3C + bool 'HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI + bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1 + bool 'HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI + bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2 bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT - bool 'HiSax Support for Sedlbauer speed card/win/star' CONFIG_HISAX_SEDLBAUER + bool 'HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS + bool 'HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY + bool 'HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF + bool 'HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR + bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T + bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO + bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then - bool 'HiSax Support for SPARC Am7930' CONFIG_HISAX_AMD7930 - bool 'HiSax Support for SPARC DBRI' CONFIG_HISAX_DBRI - fi + bool 'HiSax Support for HFC PCI-Bus cards (EXPERIMENTAL)' CONFIG_HISAX_HFC_PCI +# bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU + if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then + bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930 + fi fi fi if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN fi -dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN +dep_tristate 'Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN +dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then + bool 'AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA + bool 'AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI + bool 'AVM T1/T1B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA + bool 'AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON fi diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.2.10/linux/drivers/isdn/Makefile Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/Makefile Mon Aug 9 12:04:39 1999 @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 +ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert L_OBJS := LX_OBJS := @@ -33,6 +33,7 @@ OX_OBJS += isdn_common.o ifdef CONFIG_ISDN_PPP O_OBJS += isdn_ppp.o + M_OBJS += isdn_bsdcomp.o endif ifdef CONFIG_ISDN_X25 O_OBJS += isdn_x25iface.o @@ -44,6 +45,12 @@ endif endif +ifeq ($(CONFIG_ISDN_DIVERSION),y) + ifeq ($(CONFIG_MODULES),y) + MOD_SUB_DIRS += divert + endif +endif + ifeq ($(CONFIG_ISDN_DRV_HISAX),y) L_OBJS += hisax/hisax.o SUB_DIRS += hisax @@ -111,6 +118,16 @@ else ifeq ($(CONFIG_ISDN_DRV_ACT2000),m) MOD_SUB_DIRS += act2000 + endif +endif + +ifeq ($(CONFIG_ISDN_DRV_EICON),y) + L_OBJS += eicon/eicon.o + SUB_DIRS += eicon + MOD_SUB_DIRS += eicon +else + ifeq ($(CONFIG_ISDN_DRV_EICON),m) + MOD_SUB_DIRS += eicon endif endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h --- v2.2.10/linux/drivers/isdn/act2000/act2000.h Mon May 10 13:00:10 1999 +++ linux/drivers/isdn/act2000/act2000.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: act2000.h,v 1.5 1997/10/09 22:22:59 fritz Exp $ +/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000.h,v $ + * Revision 1.7 1999/04/12 13:13:54 fritz + * Made cards pointer static to avoid name-clash. + * + * Revision 1.6 1998/11/05 22:12:38 fritz + * Changed mail-address. + * * Revision 1.5 1997/10/09 22:22:59 fritz * New HL<->LL interface: * New BSENT callback with nr. of bytes included. @@ -212,8 +218,6 @@ isdn_if interface; /* Interface to upper layer */ char regname[35]; /* Name used for request_region */ } act2000_card; - -extern act2000_card *actcards; extern __inline__ void act2000_schedule_tx(act2000_card *card) { diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/act2000_isa.c linux/drivers/isdn/act2000/act2000_isa.c --- v2.2.10/linux/drivers/isdn/act2000/act2000_isa.c Thu Nov 5 09:58:43 1998 +++ linux/drivers/isdn/act2000/act2000_isa.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $ +/* $Id: act2000_isa.c,v 1.8 1999/01/05 18:29:25 he Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000_isa.c,v $ + * Revision 1.8 1999/01/05 18:29:25 he + * merged remaining schedule_timeout() changes from 2.1.127 + * + * Revision 1.7 1998/11/05 22:12:41 fritz + * Changed mail-address. + * + * Revision 1.6 1998/06/17 19:51:09 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * * Revision 1.5 1998/02/12 23:06:47 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/act2000_isa.h linux/drivers/isdn/act2000/act2000_isa.h --- v2.2.10/linux/drivers/isdn/act2000/act2000_isa.h Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/act2000/act2000_isa.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: act2000_isa.h,v 1.1 1997/09/23 18:00:07 fritz Exp $ +/* $Id: act2000_isa.h,v 1.2 1998/11/05 22:12:43 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version). * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: act2000_isa.h,v $ + * Revision 1.2 1998/11/05 22:12:43 fritz + * Changed mail-address. + * * Revision 1.1 1997/09/23 18:00:07 fritz * New driver for IBM Active 2000. * diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/capi.c linux/drivers/isdn/act2000/capi.c --- v2.2.10/linux/drivers/isdn/act2000/capi.c Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/act2000/capi.c Mon Aug 9 12:04:39 1999 @@ -1,9 +1,9 @@ -/* $Id: capi.c,v 1.7 1998/02/23 23:35:41 fritz Exp $ +/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * CAPI encoder/decoder * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: capi.c,v $ + * Revision 1.8 1998/11/05 22:12:46 fritz + * Changed mail-address. + * * Revision 1.7 1998/02/23 23:35:41 fritz * Eliminated some compiler warnings. * diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/capi.h linux/drivers/isdn/act2000/capi.h --- v2.2.10/linux/drivers/isdn/act2000/capi.h Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/act2000/capi.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: capi.h,v 1.4 1997/10/01 09:21:04 fritz Exp $ +/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: capi.h,v $ + * Revision 1.5 1998/11/05 22:12:48 fritz + * Changed mail-address. + * * Revision 1.4 1997/10/01 09:21:04 fritz * Removed old compatibility stuff for 2.0.X kernels. * From now on, this code is for 2.1.X ONLY! diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c --- v2.2.10/linux/drivers/isdn/act2000/module.c Mon May 10 13:00:10 1999 +++ linux/drivers/isdn/act2000/module.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: module.c,v 1.7 1998/02/12 23:06:52 keil Exp $ +/* $Id: module.c,v 1.9 1999/04/12 13:13:56 fritz Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * - * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de) * Thanks to Friedemann Baitinger and IBM Germany * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: module.c,v $ + * Revision 1.9 1999/04/12 13:13:56 fritz + * Made cards pointer static to avoid name-clash. + * + * Revision 1.8 1998/11/05 22:12:51 fritz + * Changed mail-address. + * * Revision 1.7 1998/02/12 23:06:52 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -57,7 +63,7 @@ }; #define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short)) -act2000_card *actcards = (act2000_card *) NULL; +static act2000_card *cards = (act2000_card *) NULL; /* Parameters to be set by insmod */ static int act_bus = 0; @@ -589,7 +595,7 @@ static inline act2000_card * act2000_findcard(int driverid) { - act2000_card *p = actcards; + act2000_card *p = cards; while (p) { if (p->myid == driverid) @@ -714,8 +720,8 @@ card->bus = bus; card->port = port; card->irq = irq; - card->next = actcards; - actcards = card; + card->next = cards; + cards = card; } /* @@ -805,9 +811,9 @@ bus); } } - if (!actcards) + if (!cards) return 1; - p = actcards; + p = cards; while (p) { initialized = 0; if (!p->interface.statcallb) { @@ -870,9 +876,9 @@ kfree(p); p = q->next; } else { - actcards = p->next; + cards = p->next; kfree(p); - p = actcards; + p = cards; } failed++; } @@ -890,9 +896,9 @@ act2000_init(void) { printk(KERN_INFO "%s\n", DRIVERNAME); - if (!actcards) + if (!cards) act2000_addcard(act_bus, act_port, act_irq, act_id); - if (!actcards) + if (!cards) printk(KERN_INFO "act2000: No cards defined yet\n"); /* No symbols to export, hide all symbols */ EXPORT_NO_SYMBOLS; @@ -903,14 +909,14 @@ void cleanup_module(void) { - act2000_card *card = actcards; + act2000_card *card = cards; act2000_card *last; while (card) { unregister_card(card); del_timer(&card->ptimer); card = card->next; } - card = actcards; + card = cards; while (card) { last = card; card = card->next; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/Makefile linux/drivers/isdn/avmb1/Makefile --- v2.2.10/linux/drivers/isdn/avmb1/Makefile Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/avmb1/Makefile Mon Aug 9 12:04:39 1999 @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.4 1997/03/30 17:10:40 calle Exp $ +# $Id: Makefile,v 1.5 1999/07/01 15:26:20 calle Exp $ # # Makefile for the CAPI and AVM-B1 device drivers. # @@ -11,6 +11,22 @@ # parent makes.. # # $Log: Makefile,v $ +# Revision 1.5 1999/07/01 15:26:20 calle +# complete new version (I love it): +# + new hardware independed "capi_driver" interface that will make it easy to: +# - support other controllers with CAPI-2.0 (i.e. USB Controller) +# - write a CAPI-2.0 for the passive cards +# - support serial link CAPI-2.0 boxes. +# + wrote "capi_driver" for all supported cards. +# + "capi_driver" (supported cards) now have to be configured with +# make menuconfig, in the past all supported cards where included +# at once. +# + new and better informations in /proc/capi/ +# + new ioctl to switch trace of capi messages per controller +# using "avmcapictrl trace [contr] on|off|...." +# + complete testcircle with all supported cards and also the +# PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. +# # Revision 1.4 1997/03/30 17:10:40 calle # added support for AVM-B1-PCI card. # @@ -56,20 +72,38 @@ ifeq ($(CONFIG_ISDN_DRV_AVMB1),y) O_TARGET += avmb1.o - O_OBJS += capi.o b1lli.o - OX_OBJS += capiutil.o b1capi.o capidrv.o - ifdef CONFIG_PCI - OX_OBJS += b1pci.o + OX_OBJS += kcapi.o + O_OBJS += capi.o kernelcapi.o + ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA + O_OBJS += b1isa.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI + O_OBJS += b1pci.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA + O_OBJS += t1isa.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + OX_OBJS += b1pcmcia.o endif + OX_OBJS += capiutil.o capidrv.o b1.o else ifeq ($(CONFIG_ISDN_DRV_AVMB1),m) O_TARGET += kernelcapi.o - O_OBJS += b1lli.o - OX_OBJS += b1capi.o + OX_OBJS += kcapi.o M_OBJS += capi.o kernelcapi.o - MX_OBJS += capiutil.o capidrv.o - ifdef CONFIG_PCI - MX_OBJS += b1pci.o + ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA + M_OBJS += b1isa.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI + M_OBJS += b1pci.o + endif + ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA + M_OBJS += t1isa.o + endif + MX_OBJS += capiutil.o capidrv.o b1.o + ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + MX_OBJS += b1pcmcia.o endif endif endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h --- v2.2.10/linux/drivers/isdn/avmb1/avmcard.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/avmcard.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,535 @@ +/* + * $Id: avmcard.h,v 1.2 1999/07/05 15:09:45 calle Exp $ + * + * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: avmcard.h,v $ + * Revision 1.2 1999/07/05 15:09:45 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:22 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + */ + +#ifndef _AVMCARD_H_ +#define _AVMCARD_H_ + +#define AVMB1_PORTLEN 0x1f +#define AVM_MAXVERSION 8 +#define AVM_NAPPS 30 +#define AVM_NCCI_PER_CHANNEL 4 + +/* + * Versions + */ + +#define VER_DRIVER 0 +#define VER_CARDTYPE 1 +#define VER_HWID 2 +#define VER_SERIAL 3 +#define VER_OPTION 4 +#define VER_PROTO 5 +#define VER_PROFILE 6 +#define VER_CAPI 7 + +enum avmcardtype { + avm_b1isa, + avm_b1pci, + avm_b1pcmcia, + avm_m1, + avm_m2, + avm_t1isa, + avm_t1pci +}; + +typedef struct avmcard { + char name[32]; + unsigned int port; + unsigned irq; + enum avmcardtype cardtype; + int cardnr; /* for t1isa */ + + int versionlen; + char versionbuf[1024]; + char *version[AVM_MAXVERSION]; + + char cardname[32]; + + char infobuf[128]; /* for function procinfo */ + char msgbuf[128]; /* capimsg msg part */ + char databuf[2048]; /* capimsg data part */ + + int interrupt; + + struct capi_ctr *ctrl; +} avmcard; + +extern int b1_irq_table[16]; + +/* + * LLI Messages to the ISDN-ControllerISDN Controller + */ + +#define SEND_POLL 0x72 /* + * after load <- RECEIVE_POLL + */ +#define SEND_INIT 0x11 /* + * first message <- RECEIVE_INIT + * int32 NumApplications int32 + * NumNCCIs int32 BoardNumber + */ +#define SEND_REGISTER 0x12 /* + * register an application int32 + * ApplIDId int32 NumMessages + * int32 NumB3Connections int32 + * NumB3Blocks int32 B3Size + * + * AnzB3Connection != 0 && + * AnzB3Blocks >= 1 && B3Size >= 1 + */ +#define SEND_RELEASE 0x14 /* + * deregister an application int32 + * ApplID + */ +#define SEND_MESSAGE 0x15 /* + * send capi-message int32 length + * capi-data ... + */ +#define SEND_DATA_B3_REQ 0x13 /* + * send capi-data-message int32 + * MsgLength capi-data ... int32 + * B3Length data .... + */ + +#define SEND_CONFIG 0x21 /* + */ + +#define SEND_POLLACK 0x73 /* T1 Watchdog */ + +/* + * LLI Messages from the ISDN-ControllerISDN Controller + */ + +#define RECEIVE_POLL 0x32 /* + * <- after SEND_POLL + */ +#define RECEIVE_INIT 0x27 /* + * <- after SEND_INIT int32 length + * byte total length b1struct board + * driver revision b1struct card + * type b1struct reserved b1struct + * serial number b1struct driver + * capability b1struct d-channel + * protocol b1struct CAPI-2.0 + * profile b1struct capi version + */ +#define RECEIVE_MESSAGE 0x21 /* + * <- after SEND_MESSAGE int32 + * AppllID int32 Length capi-data + * .... + */ +#define RECEIVE_DATA_B3_IND 0x22 /* + * received data int32 AppllID + * int32 Length capi-data ... + * int32 B3Length data ... + */ +#define RECEIVE_START 0x23 /* + * Handshake + */ +#define RECEIVE_STOP 0x24 /* + * Handshake + */ +#define RECEIVE_NEW_NCCI 0x25 /* + * int32 AppllID int32 NCCI int32 + * WindowSize + */ +#define RECEIVE_FREE_NCCI 0x26 /* + * int32 AppllID int32 NCCI + */ +#define RECEIVE_RELEASE 0x26 /* + * int32 AppllID int32 0xffffffff + */ +#define RECEIVE_TASK_READY 0x31 /* + * int32 tasknr + * int32 Length Taskname ... + */ +#define RECEIVE_DEBUGMSG 0x71 /* + * int32 Length message + * + */ + +#define WRITE_REGISTER 0x00 +#define READ_REGISTER 0x01 + +/* + * port offsets + */ + +#define B1_READ 0x00 +#define B1_WRITE 0x01 +#define B1_INSTAT 0x02 +#define B1_OUTSTAT 0x03 +#define B1_RESET 0x10 +#define B1_ANALYSE 0x04 + + +#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l) +#define B1_STAT1(cardtype) (0x80E00000l) + +/* ---------------------------------------------------------------- */ + +static inline unsigned char b1outp(unsigned int base, + unsigned short offset, + unsigned char value) +{ + outb(value, base + offset); + return inb(base + B1_ANALYSE); +} + + +static inline int b1_rx_full(unsigned int base) +{ + return inb(base + B1_INSTAT) & 0x1; +} + +static inline unsigned char b1_get_byte(unsigned int base) +{ + unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ + while (!b1_rx_full(base) && time_before(jiffies, stop)); + if (b1_rx_full(base)) + return inb(base + B1_READ); + printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base); + return 0; +} + +static inline unsigned int b1_get_word(unsigned int base) +{ + unsigned int val = 0; + val |= b1_get_byte(base); + val |= (b1_get_byte(base) << 8); + val |= (b1_get_byte(base) << 16); + val |= (b1_get_byte(base) << 24); + return val; +} + +static inline int b1_tx_empty(unsigned int base) +{ + return inb(base + B1_OUTSTAT) & 0x1; +} + +static inline void b1_put_byte(unsigned int base, unsigned char val) +{ + while (!b1_tx_empty(base)); + b1outp(base, B1_WRITE, val); +} + +static inline int b1_save_put_byte(unsigned int base, unsigned char val) +{ + unsigned long stop = jiffies + 2 * HZ; + while (!b1_tx_empty(base) && time_before(jiffies,stop)); + if (!b1_tx_empty(base)) return -1; + b1outp(base, B1_WRITE, val); + return 0; +} + +static inline void b1_put_word(unsigned int base, unsigned int val) +{ + b1_put_byte(base, val & 0xff); + b1_put_byte(base, (val >> 8) & 0xff); + b1_put_byte(base, (val >> 16) & 0xff); + b1_put_byte(base, (val >> 24) & 0xff); +} + +static inline unsigned int b1_get_slice(unsigned int base, + unsigned char *dp) +{ + unsigned int len, i; + + len = i = b1_get_word(base); + while (i-- > 0) *dp++ = b1_get_byte(base); + return len; +} + +static inline void b1_put_slice(unsigned int base, + unsigned char *dp, unsigned int len) +{ + unsigned i = len; + b1_put_word(base, i); + while (i-- > 0) + b1_put_byte(base, *dp++); +} + +static void b1_wr_reg(unsigned int base, + unsigned int reg, + unsigned int value) +{ + b1_put_byte(base, WRITE_REGISTER); + b1_put_word(base, reg); + b1_put_word(base, value); +} + +static inline unsigned int b1_rd_reg(unsigned int base, + unsigned int reg) +{ + b1_put_byte(base, READ_REGISTER); + b1_put_word(base, reg); + return b1_get_word(base); + +} + +static inline void b1_reset(unsigned int base) +{ + b1outp(base, B1_RESET, 0); + udelay(55 * 2 * 1000); /* 2 TIC's */ + + b1outp(base, B1_RESET, 1); + udelay(55 * 2 * 1000); /* 2 TIC's */ + + b1outp(base, B1_RESET, 0); + udelay(55 * 2 * 1000); /* 2 TIC's */ +} + +static inline unsigned char b1_disable_irq(unsigned int base) +{ + return b1outp(base, B1_INSTAT, 0x00); +} + +/* ---------------------------------------------------------------- */ + +static inline void b1_set_test_bit(unsigned int base, + enum avmcardtype cardtype, + int onoff) +{ + b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20); +} + +static inline int b1_get_test_bit(unsigned int base, + enum avmcardtype cardtype) +{ + return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0; +} + +/* ---------------------------------------------------------------- */ + +#define T1_FASTLINK 0x00 +#define T1_SLOWLINK 0x08 + +#define T1_READ B1_READ +#define T1_WRITE B1_WRITE +#define T1_INSTAT B1_INSTAT +#define T1_OUTSTAT B1_OUTSTAT +#define T1_IRQENABLE 0x05 +#define T1_FIFOSTAT 0x06 +#define T1_RESETLINK 0x10 +#define T1_ANALYSE 0x11 +#define T1_IRQMASTER 0x12 +#define T1_IDENT 0x17 +#define T1_RESETBOARD 0x1f + +#define T1F_IREADY 0x01 +#define T1F_IHALF 0x02 +#define T1F_IFULL 0x04 +#define T1F_IEMPTY 0x08 +#define T1F_IFLAGS 0xF0 + +#define T1F_OREADY 0x10 +#define T1F_OHALF 0x20 +#define T1F_OEMPTY 0x40 +#define T1F_OFULL 0x80 +#define T1F_OFLAGS 0xF0 + +/* there are HEMA cards with 1k and 4k FIFO out */ +#define FIFO_OUTBSIZE 256 +#define FIFO_INPBSIZE 512 + +#define HEMA_VERSION_ID 0 +#define HEMA_PAL_ID 0 + +static inline void t1outp(unsigned int base, + unsigned short offset, + unsigned char value) +{ + outb(value, base + offset); +} + +static inline unsigned char t1inp(unsigned int base, + unsigned short offset) +{ + return inb(base + offset); +} + +static inline int t1_isfastlink(unsigned int base) +{ + return (inb(base + T1_IDENT) & ~0x82) == 1; +} + +static inline unsigned char t1_fifostatus(unsigned int base) +{ + return inb(base + T1_FIFOSTAT); +} + +static inline unsigned int t1_get_slice(unsigned int base, + unsigned char *dp) +{ + unsigned int len, i; +#ifdef FASTLINK_DEBUG + unsigned wcnt = 0, bcnt = 0; +#endif + + len = i = b1_get_word(base); + if (t1_isfastlink(base)) { + int status; + while (i > 0) { + status = t1_fifostatus(base) & (T1F_IREADY|T1F_IHALF); + if (i >= FIFO_INPBSIZE) status |= T1F_IFULL; + + switch (status) { + case T1F_IREADY|T1F_IHALF|T1F_IFULL: + insb(base+B1_READ, dp, FIFO_INPBSIZE); + dp += FIFO_INPBSIZE; + i -= FIFO_INPBSIZE; +#ifdef FASTLINK_DEBUG + wcnt += FIFO_INPBSIZE; +#endif + break; + case T1F_IREADY|T1F_IHALF: + insb(base+B1_READ,dp, i); +#ifdef FASTLINK_DEBUG + wcnt += i; +#endif + dp += i; + i = 0; + if (i == 0) + break; + /* fall through */ + default: + *dp++ = b1_get_byte(base); + i--; +#ifdef FASTLINK_DEBUG + bcnt++; +#endif + break; + } + } +#ifdef FASTLINK_DEBUG + if (wcnt) + printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n", + base, len, wcnt, bcnt); +#endif + } else { + while (i-- > 0) + *dp++ = b1_get_byte(base); + } + return len; +} + +static inline void t1_put_slice(unsigned int base, + unsigned char *dp, unsigned int len) +{ + unsigned i = len; + b1_put_word(base, i); + if (t1_isfastlink(base)) { + int status; + while (i > 0) { + status = t1_fifostatus(base) & (T1F_OREADY|T1F_OHALF); + if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY; + switch (status) { + case T1F_OREADY|T1F_OHALF|T1F_OEMPTY: + outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE); + dp += FIFO_OUTBSIZE; + i -= FIFO_OUTBSIZE; + break; + case T1F_OREADY|T1F_OHALF: + outsb(base+B1_WRITE, dp, i); + dp += i; + i = 0; + break; + default: + b1_put_byte(base, *dp++); + i--; + break; + } + } + } else { + while (i-- > 0) + b1_put_byte(base, *dp++); + } +} + +static inline void t1_disable_irq(unsigned int base) +{ + t1outp(base, T1_IRQMASTER, 0x00); +} + +static inline void t1_reset(unsigned int base) +{ + /* reset T1 Controller */ + b1_reset(base); + /* disable irq on HEMA */ + t1outp(base, B1_INSTAT, 0x00); + t1outp(base, B1_OUTSTAT, 0x00); + t1outp(base, T1_IRQMASTER, 0x00); + /* reset HEMA board configuration */ + t1outp(base, T1_RESETBOARD, 0xf); +} + +static inline void b1_setinterrupt(unsigned int base, unsigned irq, + enum avmcardtype cardtype) +{ + switch (cardtype) { + case avm_t1isa: + t1outp(base, B1_INSTAT, 0x00); + t1outp(base, B1_INSTAT, 0x02); + t1outp(base, T1_IRQMASTER, 0x08); + break; + case avm_b1isa: + b1outp(base, B1_INSTAT, 0x00); + b1outp(base, B1_RESET, b1_irq_table[irq]); + b1outp(base, B1_INSTAT, 0x02); + break; + default: + case avm_m1: + case avm_m2: + case avm_b1pci: + b1outp(base, B1_INSTAT, 0x00); + b1outp(base, B1_RESET, 0xf0); + b1outp(base, B1_INSTAT, 0x02); + break; + } +} + +int b1_detect(unsigned int base, enum avmcardtype cardtype); +int b1_load_t4file(unsigned int base, capiloaddatapart * t4file); +int b1_load_config(unsigned int base, capiloaddatapart * config); +int b1_loaded(unsigned int base); +int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); +void b1_reset_ctr(struct capi_ctr *ctrl); +void b1_register_appl(struct capi_ctr *ctrl, __u16 appl, + capi_register_params *rp); +void b1_release_appl(struct capi_ctr *ctrl, __u16 appl); +void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); +void b1_parse_version(avmcard *card); +void b1_handle_interrupt(avmcard * card); + +int b1ctl_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl); + + +#endif /* _AVMCARD_H_ */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.2.10/linux/drivers/isdn/avmb1/b1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,679 @@ +/* + * $Id: b1.c,v 1.4 1999/07/09 15:05:38 keil Exp $ + * + * Common module for AVM B1 cards. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1.c,v $ + * Revision 1.4 1999/07/09 15:05:38 keil + * compat.h is now isdn_compat.h + * + * Revision 1.3 1999/07/06 07:41:59 calle + * - changes in /proc interface + * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. + * + * Revision 1.2 1999/07/05 15:09:47 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:23 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capilli.h" +#include "avmcard.h" +#include "capicmd.h" +#include "capiutil.h" + +static char *revision = "$Revision: 1.4 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth "); + +/* ------------------------------------------------------------- */ + +int b1_irq_table[16] = +{0, + 0, + 0, + 192, /* irq 3 */ + 32, /* irq 4 */ + 160, /* irq 5 */ + 96, /* irq 6 */ + 224, /* irq 7 */ + 0, + 64, /* irq 9 */ + 80, /* irq 10 */ + 208, /* irq 11 */ + 48, /* irq 12 */ + 0, + 0, + 112, /* irq 15 */ +}; + +/* ------------------------------------------------------------- */ + +int b1_detect(unsigned int base, enum avmcardtype cardtype) +{ + int onoff, i; + + /* + * Statusregister 0000 00xx + */ + if ((inb(base + B1_INSTAT) & 0xfc) + || (inb(base + B1_OUTSTAT) & 0xfc)) + return 1; + /* + * Statusregister 0000 001x + */ + b1outp(base, B1_INSTAT, 0x2); /* enable irq */ + /* b1outp(base, B1_OUTSTAT, 0x2); */ + if ((inb(base + B1_INSTAT) & 0xfe) != 0x2 + /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */) + return 2; + /* + * Statusregister 0000 000x + */ + b1outp(base, B1_INSTAT, 0x0); /* disable irq */ + b1outp(base, B1_OUTSTAT, 0x0); + if ((inb(base + B1_INSTAT) & 0xfe) + || (inb(base + B1_OUTSTAT) & 0xfe)) + return 3; + + for (onoff = !0, i= 0; i < 10 ; i++) { + b1_set_test_bit(base, cardtype, onoff); + if (b1_get_test_bit(base, cardtype) != onoff) + return 4; + onoff = !onoff; + } + + if (cardtype == avm_m1) + return 0; + + if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01) + return 5; + + return 0; +} + +int b1_load_t4file(unsigned int base, capiloaddatapart * t4file) +{ + unsigned char buf[256]; + unsigned char *dp; + int i, left, retval; + + dp = t4file->data; + left = t4file->len; + while (left > sizeof(buf)) { + if (t4file->user) { + retval = copy_from_user(buf, dp, sizeof(buf)); + if (retval) + return -EFAULT; + } else { + memcpy(buf, dp, sizeof(buf)); + } + for (i = 0; i < sizeof(buf); i++) + if (b1_save_put_byte(base, buf[i]) < 0) { + printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n"); + return -EIO; + } + left -= sizeof(buf); + dp += sizeof(buf); + } + if (left) { + if (t4file->user) { + retval = copy_from_user(buf, dp, left); + if (retval) + return -EFAULT; + } else { + memcpy(buf, dp, left); + } + for (i = 0; i < left; i++) + if (b1_save_put_byte(base, buf[i]) < 0) { + printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n"); + return -EIO; + } + } + return 0; +} + +int b1_load_config(unsigned int base, capiloaddatapart * config) +{ + unsigned char buf[256]; + unsigned char *dp; + int i, j, left, retval; + + dp = config->data; + left = config->len; + if (left) { + b1_put_byte(base, SEND_CONFIG); + b1_put_word(base, 1); + b1_put_byte(base, SEND_CONFIG); + b1_put_word(base, left); + } + while (left > sizeof(buf)) { + if (config->user) { + retval = copy_from_user(buf, dp, sizeof(buf)); + if (retval) + return -EFAULT; + } else { + memcpy(buf, dp, sizeof(buf)); + } + for (i = 0; i < sizeof(buf); ) { + b1_put_byte(base, SEND_CONFIG); + for (j=0; j < 4; j++) { + b1_put_byte(base, buf[i++]); + } + } + left -= sizeof(buf); + dp += sizeof(buf); + } + if (left) { + if (config->user) { + retval = copy_from_user(buf, dp, left); + if (retval) + return -EFAULT; + } else { + memcpy(buf, dp, left); + } + for (i = 0; i < left; ) { + b1_put_byte(base, SEND_CONFIG); + for (j=0; j < 4; j++) { + if (i < left) + b1_put_byte(base, buf[i++]); + else + b1_put_byte(base, 0); + } + } + } + return 0; +} + +int b1_loaded(unsigned int base) +{ + unsigned long stop; + unsigned char ans; + unsigned long tout = 2; + + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_tx_empty(base)) + break; + } + if (!b1_tx_empty(base)) { + printk(KERN_ERR "b1_loaded: tx err, corrupted t4 file ?\n"); + return 0; + } + b1_put_byte(base, SEND_POLL); + for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { + if (b1_rx_full(base)) { + if ((ans = b1_get_byte(base)) == RECEIVE_POLL) { + return 1; + } + printk(KERN_ERR "b1_loaded: got 0x%x, firmware not running\n", ans); + return 0; + } + } + printk(KERN_ERR "b1_loaded: firmware not running\n"); + return 0; +} + +/* ------------------------------------------------------------- */ + +int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + int retval; + + b1_reset(port); + + if ((retval = b1_load_t4file(port, &data->firmware))) { + b1_reset(port); + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + return retval; + } + + b1_disable_irq(port); + + if (data->configuration.len > 0 && data->configuration.data) { + if ((retval = b1_load_config(port, &data->configuration))) { + b1_reset(port); + printk(KERN_ERR "%s: failed to load config!!\n", + card->name); + return retval; + } + } + + if (!b1_loaded(port)) { + printk(KERN_ERR "%s: failed to load t4file.\n", card->name); + return -EIO; + } + + save_flags(flags); + cli(); + b1_setinterrupt(port, card->irq, card->cardtype); + b1_put_byte(port, SEND_INIT); + b1_put_word(port, AVM_NAPPS); + b1_put_word(port, AVM_NCCI_PER_CHANNEL*2); + b1_put_word(port, ctrl->cnr - 1); + restore_flags(flags); + + return 0; +} + +void b1_reset_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + b1_reset(port); + b1_reset(port); + + memset(card->version, 0, sizeof(card->version)); + ctrl->reseted(ctrl); +} + +void b1_register_appl(struct capi_ctr *ctrl, + __u16 appl, + capi_register_params *rp) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + int nconn, want = rp->level3cnt; + + if (want > 0) nconn = want; + else nconn = ctrl->profile.nbchannel * -want; + if (nconn == 0) nconn = ctrl->profile.nbchannel; + + save_flags(flags); + cli(); + b1_put_byte(port, SEND_REGISTER); + b1_put_word(port, appl); + b1_put_word(port, 1024 * (nconn+1)); + b1_put_word(port, nconn); + b1_put_word(port, rp->datablkcnt); + b1_put_word(port, rp->datablklen); + restore_flags(flags); + + ctrl->appl_registered(ctrl, appl); +} + +void b1_release_appl(struct capi_ctr *ctrl, __u16 appl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + + save_flags(flags); + cli(); + b1_put_byte(port, SEND_RELEASE); + b1_put_word(port, appl); + restore_flags(flags); +} + +void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + __u16 len = CAPIMSG_LEN(skb->data); + __u8 cmd = CAPIMSG_COMMAND(skb->data); + __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + save_flags(flags); + cli(); + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + b1_put_byte(port, SEND_DATA_B3_REQ); + b1_put_slice(port, skb->data, len); + b1_put_slice(port, skb->data + len, dlen); + } else { + b1_put_byte(port, SEND_MESSAGE); + b1_put_slice(port, skb->data, len); + } + restore_flags(flags); + dev_kfree_skb(skb); +} + +/* ------------------------------------------------------------- */ + +void b1_parse_version(avmcard *card) +{ + struct capi_ctr *ctrl = card->ctrl; + capi_profile *profp; + __u8 *dversion; + __u8 flag; + int i, j; + + for (j = 0; j < AVM_MAXVERSION; j++) + card->version[j] = "\0\0" + 1; + for (i = 0, j = 0; + j < AVM_MAXVERSION && i < card->versionlen; + j++, i += card->versionbuf[i] + 1) + card->version[j] = &card->versionbuf[i + 1]; + + strncpy(ctrl->serial, card->version[VER_SERIAL], CAPI_SERIAL_LEN); + memcpy(&ctrl->profile, card->version[VER_PROFILE],sizeof(capi_profile)); + strncpy(ctrl->manu, "AVM GmbH", CAPI_MANUFACTURER_LEN); + dversion = card->version[VER_DRIVER]; + ctrl->version.majorversion = 2; + ctrl->version.minorversion = 0; + ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4); + ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf); + ctrl->version.minormanuversion = (dversion[3] - '0') << 4; + ctrl->version.minormanuversion |= + (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf); + + profp = &ctrl->profile; + + flag = ((__u8 *)(profp->manu))[1]; + switch (flag) { + case 0: strcpy(card->cardname, "B1"); break; + case 3: strcpy(card->cardname,"PCMCIA B"); break; + case 4: strcpy(card->cardname,"PCMCIA M1"); break; + case 5: strcpy(card->cardname,"PCMCIA M2"); break; + case 6: strcpy(card->cardname,"B1 V3.0"); break; + case 7: strcpy(card->cardname,"B1 PCI"); break; + default: sprintf(card->cardname, "AVM?%u", (unsigned int)flag); break; + } + printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n", + card->name, ctrl->cnr, card->cardname); + + flag = ((__u8 *)(profp->manu))[3]; + if (flag) + printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n", + ctrl->cnr, + (flag & 0x01) ? " DSS1" : "", + (flag & 0x02) ? " CT1" : "", + (flag & 0x04) ? " VN3" : "", + (flag & 0x08) ? " NI1" : "", + (flag & 0x10) ? " AUSTEL" : "", + (flag & 0x20) ? " ESS" : "", + (flag & 0x40) ? " 1TR6" : "" + ); + + flag = ((__u8 *)(profp->manu))[5]; + if (flag) + printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n", + card->name, + ctrl->cnr, + (flag & 0x01) ? " point to point" : "", + (flag & 0x02) ? " point to multipoint" : "", + (flag & 0x08) ? " leased line without D-channel" : "", + (flag & 0x04) ? " leased line with D-channel" : "" + ); +} + +/* ------------------------------------------------------------- */ + +void b1_handle_interrupt(avmcard * card) +{ + struct capi_ctr *ctrl = card->ctrl; + unsigned char b1cmd; + struct sk_buff *skb; + + unsigned ApplId; + unsigned MsgLen; + unsigned DataB3Len; + unsigned NCCI; + unsigned WindowSize; + + if (!b1_rx_full(card->port)) + return; + + b1cmd = b1_get_byte(card->port); + + switch (b1cmd) { + + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = b1_get_slice(card->port, card->msgbuf); + DataB3Len = b1_get_slice(card->port, card->databuf); + + if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + CAPIMSG_SETDATA(skb->data, skb->data + MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = b1_get_slice(card->port, card->msgbuf); + if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "%s: incoming packet dropped\n", + card->name); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = b1_get_word(card->port); + NCCI = b1_get_word(card->port); + WindowSize = b1_get_word(card->port); + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = b1_get_word(card->port); + NCCI = b1_get_word(card->port); + + if (NCCI != 0xffffffff) + ctrl->free_ncci(ctrl, ApplId, NCCI); + else ctrl->appl_released(ctrl, ApplId); + break; + + case RECEIVE_START: + /* b1_put_byte(card->port, SEND_POLLACK); */ + ctrl->resume_output(ctrl); + break; + + case RECEIVE_STOP: + ctrl->suspend_output(ctrl); + break; + + case RECEIVE_INIT: + + card->versionlen = b1_get_slice(card->port, card->versionbuf); + b1_parse_version(card); + printk(KERN_INFO "%s: %s-card (%s) now active\n", + card->name, + card->version[VER_CARDTYPE], + card->version[VER_DRIVER]); + ctrl->ready(ctrl); + break; + + case RECEIVE_TASK_READY: + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = b1_get_slice(card->port, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: task %d \"%s\" ready.\n", + card->name, ApplId, card->msgbuf); + break; + + case RECEIVE_DEBUGMSG: + MsgLen = b1_get_slice(card->port, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); + break; + + case 0xff: + printk(KERN_ERR "%s: card removed ?\n", card->name); + return; + default: + printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } +} + +/* ------------------------------------------------------------- */ +int b1ctl_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + __u8 flag; + int len = 0; + char *s; + + len += sprintf(page+len, "%-16s %s\n", "name", card->name); + len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port); + len += sprintf(page+len, "%-16s %d\n", "irq", card->irq); + switch (card->cardtype) { + case avm_b1isa: s = "B1 ISA"; break; + case avm_b1pci: s = "B1 PCI"; break; + case avm_b1pcmcia: s = "B1 PCMCIA"; break; + case avm_m1: s = "M1"; break; + case avm_m2: s = "M2"; break; + case avm_t1isa: s = "T1 ISA (HEMA)"; break; + case avm_t1pci: s = "T1 PCI"; break; + default: s = "???"; break; + } + len += sprintf(page+len, "%-16s %s\n", "type", s); + if (card->cardtype == avm_t1isa) + len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr); + if ((s = card->version[VER_DRIVER]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_driver", s); + if ((s = card->version[VER_CARDTYPE]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s); + if ((s = card->version[VER_SERIAL]) != 0) + len += sprintf(page+len, "%-16s %s\n", "ver_serial", s); + + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[3]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n", + "protocol", + (flag & 0x01) ? " DSS1" : "", + (flag & 0x02) ? " CT1" : "", + (flag & 0x04) ? " VN3" : "", + (flag & 0x08) ? " NI1" : "", + (flag & 0x10) ? " AUSTEL" : "", + (flag & 0x20) ? " ESS" : "", + (flag & 0x40) ? " 1TR6" : "" + ); + } + if (card->cardtype != avm_m1) { + flag = ((__u8 *)(ctrl->profile.manu))[5]; + if (flag) + len += sprintf(page+len, "%-16s%s%s%s%s\n", + "linetype", + (flag & 0x01) ? " point to point" : "", + (flag & 0x02) ? " point to multipoint" : "", + (flag & 0x08) ? " leased line without D-channel" : "", + (flag & 0x04) ? " leased line with D-channel" : "" + ); + } + len += sprintf(page+len, "%-16s %s\n", "cardname", card->cardname); + + if (len < off) + return 0; + *eof = 1; + *start = page - off; + return ((count < len-off) ? count : len-off); + if (len < off) + return 0; + *eof = 1; + *start = page - off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +EXPORT_SYMBOL(b1_irq_table); + +EXPORT_SYMBOL(b1_detect); +EXPORT_SYMBOL(b1_load_t4file); +EXPORT_SYMBOL(b1_load_config); +EXPORT_SYMBOL(b1_loaded); +EXPORT_SYMBOL(b1_load_firmware); +EXPORT_SYMBOL(b1_reset_ctr); +EXPORT_SYMBOL(b1_register_appl); +EXPORT_SYMBOL(b1_release_appl); +EXPORT_SYMBOL(b1_send_message); + +EXPORT_SYMBOL(b1_parse_version); +EXPORT_SYMBOL(b1_handle_interrupt); + +EXPORT_SYMBOL(b1ctl_read_proc); + +#ifdef MODULE +#define b1_init init_module +void cleanup_module(void); +#endif + +int b1_init(void) +{ + char *p; + char rev[10]; + + if ((p = strchr(revision, ':'))) { + strncpy(rev, p + 1, sizeof(rev)); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + + printk(KERN_INFO "b1: revision %s\n", rev); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1capi.c linux/drivers/isdn/avmb1/b1capi.c --- v2.2.10/linux/drivers/isdn/avmb1/b1capi.c Thu Nov 5 09:58:43 1998 +++ linux/drivers/isdn/avmb1/b1capi.c Wed Dec 31 16:00:00 1969 @@ -1,1141 +0,0 @@ -/* - * $Id: b1capi.c,v 1.10 1998/02/13 07:09:10 calle Exp $ - * - * CAPI 2.0 Module for AVM B1-card. - * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: b1capi.c,v $ - * Revision 1.10 1998/02/13 07:09:10 calle - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.9 1998/01/31 11:14:39 calle - * merged changes to 2.0 tree, prepare 2.1.82 to work. - * - * Revision 1.8 1997/12/10 20:00:46 calle - * get changes from 2.0 version - * - * Revision 1.4.2.5 1997/12/07 19:59:54 calle - * more changes for M1/T1/B1 + config - * - * Revision 1.4.2.4 1997/11/26 16:57:20 calle - * more changes for B1/M1/T1. - * - * Revision 1.7 1997/10/19 14:45:40 calle - * fixed capi_get_version. - * - * Revision 1.6 1997/10/01 09:21:09 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.5 1997/07/12 08:22:26 calle - * Correct bug in CARD_NR macro, so now more than one card will work. - * Allow card reset, even if card is in running state. - * - * - * Revision 1.4 1997/05/27 15:17:45 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * Revision 1.3 1997/05/18 09:24:09 calle - * added verbose disconnect reason reporting to avmb1. - * some fixes in capi20 interface. - * changed info messages for B1-PCI - * - * Revision 1.2 1997/03/05 21:20:41 fritz - * Removed include of config.h (mkdep stated this is unneded). - * - * Revision 1.1 1997/03/04 21:50:27 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "compat.h" -#include "capicmd.h" -#include "capiutil.h" - -static char *revision = "$Revision: 1.10 $"; - -/* ------------------------------------------------------------- */ - -int showcapimsgs = 0; /* used in lli.c */ -int loaddebug = 0; - -MODULE_AUTHOR("Carsten Paeth "); -MODULE_PARM(showcapimsgs, "0-3i"); -MODULE_PARM(loaddebug, "0-1i"); - -/* ------------------------------------------------------------- */ - -struct msgidqueue { - struct msgidqueue *next; - __u16 msgid; -}; - -typedef struct avmb1_ncci { - struct avmb1_ncci *next; - __u16 applid; - __u32 ncci; - __u32 winsize; - struct msgidqueue *msgidqueue; - struct msgidqueue *msgidlast; - struct msgidqueue *msgidfree; - struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW]; -} avmb1_ncci; - -typedef struct avmb1_appl { - __u16 applid; - capi_register_params rparam; - int releasing; - __u32 param; - void (*signal) (__u16 applid, __u32 param); - struct sk_buff_head recv_queue; - struct avmb1_ncci *nccilist; -} avmb1_appl; - -/* ------------------------------------------------------------- */ - -static struct capi_version driver_version = {2, 0, 1, 1<<4}; -static char driver_serial[CAPI_SERIAL_LEN] = "4711"; -static char capi_manufakturer[64] = "AVM Berlin"; - -#define APPL(a) (&applications[(a)-1]) -#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a) -#define APPL_IS_FREE(a) (APPL(a)->applid == 0) -#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0); -#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0); - -#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) - -#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR) -#define CARD(c) (&cards[(c)-1]) -#define CARDNR(cp) (((cp)-cards)+1) - -static avmb1_appl applications[CAPI_MAXAPPL]; -static avmb1_card cards[CAPI_MAXCONTR]; -static int ncards = 0; -static struct sk_buff_head recv_queue; -static struct capi_interface_user *capi_users = 0; -static long notify_up_set = 0; -static long notify_down_set = 0; - -static struct tq_struct tq_state_notify; -static struct tq_struct tq_recv_notify; - -/* -------- util functions ------------------------------------ */ - -static char *cardtype2str(int cardtype) -{ - switch (cardtype) { - default: - case AVM_CARDTYPE_B1: return "B1"; - case AVM_CARDTYPE_M1: return "M1"; - case AVM_CARDTYPE_M2: return "M2"; - case AVM_CARDTYPE_T1: return "T1"; - } -} - -static inline int capi_cmd_valid(__u8 cmd) -{ - switch (cmd) { - case CAPI_ALERT: - case CAPI_CONNECT: - case CAPI_CONNECT_ACTIVE: - case CAPI_CONNECT_B3_ACTIVE: - case CAPI_CONNECT_B3: - case CAPI_CONNECT_B3_T90_ACTIVE: - case CAPI_DATA_B3: - case CAPI_DISCONNECT_B3: - case CAPI_DISCONNECT: - case CAPI_FACILITY: - case CAPI_INFO: - case CAPI_LISTEN: - case CAPI_MANUFACTURER: - case CAPI_RESET_B3: - case CAPI_SELECT_B_PROTOCOL: - return 1; - } - return 0; -} - -static inline int capi_subcmd_valid(__u8 subcmd) -{ - switch (subcmd) { - case CAPI_REQ: - case CAPI_CONF: - case CAPI_IND: - case CAPI_RESP: - return 1; - } - return 0; -} - -/* -------- NCCI Handling ------------------------------------- */ - -static inline void mq_init(avmb1_ncci * np) -{ - int i; - np->msgidqueue = 0; - np->msgidlast = 0; - memset(np->msgidpool, 0, sizeof(np->msgidpool)); - np->msgidfree = &np->msgidpool[0]; - for (i = 1; i < np->winsize; i++) { - np->msgidpool[i].next = np->msgidfree; - np->msgidfree = &np->msgidpool[i]; - } -} - -static inline int mq_enqueue(avmb1_ncci * np, __u16 msgid) -{ - struct msgidqueue *mq; - if ((mq = np->msgidfree) == 0) - return 0; - np->msgidfree = mq->next; - mq->msgid = msgid; - mq->next = 0; - if (np->msgidlast) - np->msgidlast->next = mq; - np->msgidlast = mq; - if (!np->msgidqueue) - np->msgidqueue = mq; - return 1; -} - -static inline int mq_dequeue(avmb1_ncci * np, __u16 msgid) -{ - struct msgidqueue **pp; - for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { - if ((*pp)->msgid == msgid) { - struct msgidqueue *mq = *pp; - *pp = mq->next; - if (mq == np->msgidlast) - np->msgidlast = 0; - mq->next = np->msgidfree; - np->msgidfree = mq; - return 1; - } - } - return 0; -} - -void avmb1_handle_new_ncci(avmb1_card * card, - __u16 appl, __u32 ncci, __u32 winsize) -{ - avmb1_ncci *np; - if (!VALID_APPLID(appl)) { - printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl); - return; - } - if ((np = (avmb1_ncci *) kmalloc(sizeof(avmb1_ncci), GFP_ATOMIC)) == 0) { - printk(KERN_ERR "avmb1_handle_new_ncci: alloc failed ncci 0x%x\n", ncci); - return; - } - if (winsize > CAPI_MAXDATAWINDOW) { - printk(KERN_ERR "avmb1_handle_new_ncci: winsize %d too big, set to %d\n", - winsize, CAPI_MAXDATAWINDOW); - winsize = CAPI_MAXDATAWINDOW; - } - np->applid = appl; - np->ncci = ncci; - np->winsize = winsize; - mq_init(np); - np->next = APPL(appl)->nccilist; - APPL(appl)->nccilist = np; - printk(KERN_INFO "b1capi: appl %d ncci 0x%x up\n", appl, ncci); - -} - -void avmb1_handle_free_ncci(avmb1_card * card, - __u16 appl, __u32 ncci) -{ - if (!VALID_APPLID(appl)) { - printk(KERN_ERR "avmb1_handle_free_ncci: illegal appl %d\n", appl); - return; - } - if (ncci != 0xffffffff) { - avmb1_ncci **pp; - for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) { - if ((*pp)->ncci == ncci) { - avmb1_ncci *np = *pp; - *pp = np->next; - kfree(np); - printk(KERN_INFO "b1capi: appl %d ncci 0x%x down\n", appl, ncci); - return; - } - } - printk(KERN_ERR "avmb1_handle_free_ncci: ncci 0x%x not found\n", ncci); - } else { - avmb1_ncci **pp, **nextpp; - for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { - if (NCCI2CTRL((*pp)->ncci) == card->cnr) { - avmb1_ncci *np = *pp; - *pp = np->next; - printk(KERN_INFO "b1capi: appl %d ncci 0x%x down!\n", appl, np->ncci); - kfree(np); - nextpp = pp; - } else { - nextpp = &(*pp)->next; - } - } - APPL(appl)->releasing--; - if (APPL(appl)->releasing == 0) { - APPL(appl)->signal = 0; - APPL_MARK_FREE(appl); - printk(KERN_INFO "b1capi: appl %d down\n", appl); - } - } -} - -static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci) -{ - avmb1_ncci *np; - for (np = app->nccilist; np; np = np->next) { - if (np->ncci == ncci) - return np; - } - return 0; -} - - - -/* -------- Receiver ------------------------------------------ */ - - -static void recv_handler(void *dummy) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(&recv_queue)) != 0) { - __u16 appl = CAPIMSG_APPID(skb->data); - struct avmb1_ncci *np; - if (!VALID_APPLID(appl)) { - printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n", - appl, capi_message2str(skb->data)); - kfree_skb(skb); - continue; - } - if (APPL(appl)->signal == 0) { - printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n", - appl); - kfree_skb(skb); - continue; - } - if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 - && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF - && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0 - && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) { - printk(KERN_ERR "b1capi: msgid %hu ncci 0x%x not on queue\n", - CAPIMSG_MSGID(skb->data), np->ncci); - } - skb_queue_tail(&APPL(appl)->recv_queue, skb); - (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param); - } -} - - -void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb) -{ - if (card->cardstate != CARD_RUNNING) { - printk(KERN_INFO "b1capi: controller %d not active, got: %s", - card->cnr, capi_message2str(skb->data)); - goto error; - return; - } - skb_queue_tail(&recv_queue, skb); - queue_task(&tq_recv_notify, &tq_immediate); - mark_bh(IMMEDIATE_BH); - return; - - error: - kfree_skb(skb); -} - -void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs) -{ - avmb1_card *card; - - card = (avmb1_card *) devptr; - - if (!card) { - printk(KERN_WARNING "avmb1_interrupt: wrong device\n"); - return; - } - if (card->interrupt) { - printk(KERN_ERR "avmb1_interrupt: reentering interrupt hander\n"); - return; - } - - card->interrupt = 1; - - B1_handle_interrupt(card); - - card->interrupt = 0; -} - -/* -------- Notifier ------------------------------------------ */ - -static void notify_up(__u16 contr) -{ - struct capi_interface_user *p; - - printk(KERN_NOTICE "b1capi: notify up contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (p->callback) - (*p->callback) (KCI_CONTRUP, contr, - (capi_profile *) - CARD(contr)->version[VER_PROFILE]); - } -} - -static void notify_down(__u16 contr) -{ - struct capi_interface_user *p; - printk(KERN_NOTICE "b1capi: notify down contr %d\n", contr); - for (p = capi_users; p; p = p->next) { - if (p->callback) - (*p->callback) (KCI_CONTRDOWN, contr, 0); - } -} - -static void notify_handler(void *dummy) -{ - __u16 contr; - - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_up_set)) - notify_up(contr); - for (contr=1; VALID_CARD(contr); contr++) - if (test_and_clear_bit(contr, ¬ify_down_set)) - notify_down(contr); -} - -/* -------- card ready callback ------------------------------- */ - -void avmb1_card_ready(avmb1_card * card) -{ - struct capi_profile *profp = - (struct capi_profile *)card->version[VER_PROFILE]; - char *dversion = card->version[VER_DRIVER]; - __u16 appl; - char *cardname, cname[20]; - __u32 flag; - - card->cversion.majorversion = 2; - card->cversion.minorversion = 0; - card->cversion.majormanuversion = (((dversion[0] - '0') & 0xf) << 4); - card->cversion.majormanuversion |= ((dversion[2] - '0') & 0xf); - card->cversion.minormanuversion = (dversion[3] - '0') << 4; - card->cversion.minormanuversion |= - (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf); - card->cardstate = CARD_RUNNING; - - for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { - if (VALID_APPLID(appl) && !APPL(appl)->releasing) { - B1_send_register(card->port, appl, - 1024 * (APPL(appl)->rparam.level3cnt+1), - APPL(appl)->rparam.level3cnt, - APPL(appl)->rparam.datablkcnt, - APPL(appl)->rparam.datablklen); - } - } - - set_bit(CARDNR(card), ¬ify_up_set); - queue_task(&tq_state_notify, &tq_scheduler); - - flag = ((__u8 *)(profp->manu))[1]; - switch (flag) { - case 0: cardname = cardtype2str(card->cardtype); break; - case 3: cardname = "PCMCIA B"; break; - case 4: cardname = "PCMCIA M1"; break; - case 5: cardname = "PCMCIA M2"; break; - case 6: cardname = "B1 V3.0"; break; - case 7: cardname = "B1 PCI"; break; - default: cardname = cname; break; - sprintf(cname, "AVM?%u", (unsigned int)flag); - break; - } - printk(KERN_NOTICE "b1capi: card %d \"%s\" ready.\n", - CARDNR(card), cardname); - flag = ((__u8 *)(profp->manu))[3]; - if (flag) - printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n", - CARDNR(card), - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - flag = ((__u8 *)(profp->manu))[5]; - if (flag) - printk(KERN_NOTICE "b1capi: card %d Linetype:%s%s%s%s\n", - CARDNR(card), - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); -} - -static void avmb1_card_down(avmb1_card * card, int notify) -{ - __u16 appl; - - card->cardstate = CARD_DETECTED; - - for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { - avmb1_ncci **pp, **nextpp; - for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { - if (NCCI2CTRL((*pp)->ncci) == card->cnr) { - avmb1_ncci *np = *pp; - *pp = np->next; - printk(KERN_INFO "b1capi: appl %d ncci 0x%x forced down!\n", appl, np->ncci); - kfree(np); - nextpp = pp; - } else { - nextpp = &(*pp)->next; - } - } - } - set_bit(CARDNR(card), ¬ify_down_set); - queue_task(&tq_state_notify, &tq_scheduler); - printk(KERN_NOTICE "b1capi: card %d down.\n", CARDNR(card)); -} - -/* ------------------------------------------------------------- */ - - -int avmb1_registercard(int port, int irq, int cardtype, int allocio) -{ - struct avmb1_card *card; - int irqval,i; - - - for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ; - - if (i == CAPI_MAXCONTR) { - printk(KERN_ERR "b1capi: out of controller slots\n"); - return -ENFILE; - } - - card = &cards[i]; - memset(card, 0, sizeof(avmb1_card)); - sprintf(card->name, "avmb1-%d", CARDNR(card)); - - if (allocio) - request_region(port, AVMB1_PORTLEN, card->name); - - if ((irqval = request_irq(irq, avmb1_interrupt, - SA_SHIRQ, card->name, card)) != 0) { - printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n", - irq, irqval); - release_region((unsigned short) port, AVMB1_PORTLEN); - return -EIO; - } - - card->cardstate = CARD_DETECTED; - ncards++; - card->cnr = CARDNR(card); - card->port = port; - card->irq = irq; - card->cardtype = cardtype; - return card->cnr; -} - -int avmb1_addcard(int port, int irq, int cardtype) -{ - return avmb1_registercard(port, irq, cardtype, 1); -} - -int avmb1_detectcard(int port, int irq, int cardtype) -{ - int rc; - - if (!B1_valid_irq(irq, cardtype)) { - printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n", - irq, cardtype2str(cardtype)); - return -EIO; - } - if ((rc = B1_detect(port, cardtype)) != 0) { - printk(KERN_NOTICE "b1capi: NO %s-card at 0x%x (%d)\n", - cardtype2str(cardtype), port, rc); - return -EIO; - } - B1_reset(port); - switch (cardtype) { - default: - case AVM_CARDTYPE_M1: - case AVM_CARDTYPE_M2: - case AVM_CARDTYPE_B1: - printk(KERN_NOTICE "b1capi: AVM-%s-Controller detected at 0x%x\n", cardtype2str(cardtype), port); - break; - case AVM_CARDTYPE_T1: - printk(KERN_NOTICE "b1capi: AVM-%s-Controller may be at 0x%x\n", cardtype2str(cardtype), port); - break; - } - - return 0; -} - -int avmb1_probecard(int port, int irq, int cardtype) -{ - if (check_region((unsigned short) port, AVMB1_PORTLEN)) { - printk(KERN_WARNING - "b1capi: ports 0x%03x-0x%03x in use.\n", - port, port + AVMB1_PORTLEN); - return -EIO; - } - return avmb1_detectcard(port, irq, cardtype); -} - -int avmb1_unregistercard(int cnr, int freeio) -{ - avmb1_card * card; - if (!VALID_CARD(cnr)) - return -ESRCH; - card = CARD(cnr); - if (card->cardstate == CARD_FREE) - return -ESRCH; - if (card->cardstate == CARD_RUNNING) - avmb1_card_down(card, freeio); - - free_irq(card->irq, card); - if (freeio) - release_region(card->port, AVMB1_PORTLEN); - card->cardstate = CARD_FREE; - return 0; -} - -int avmb1_resetcard(int cnr) -{ - avmb1_card * card; - - if (!VALID_CARD(cnr)) - return -ESRCH; - card = CARD(cnr); - if (card->cardstate == CARD_FREE) - return -ESRCH; - - if (card->cardstate == CARD_RUNNING) - avmb1_card_down(card, 0); - - B1_reset(card->port); - B1_reset(card->port); - - card->cardstate = CARD_DETECTED; - - return 0; -} - -/* ------------------------------------------------------------- */ -/* -------- CAPI2.0 Interface ---------------------------------- */ -/* ------------------------------------------------------------- */ - -static int capi_installed(void) -{ - int i; - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (cards[i].cardstate == CARD_RUNNING) - return 1; - } - return 0; -} - -static __u16 capi_register(capi_register_params * rparam, __u16 * applidp) -{ - int i; - int appl; - - if (rparam->datablklen < 128) - return CAPI_LOGBLKSIZETOSMALL; - - for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { - if (APPL_IS_FREE(appl)) - break; - } - if (appl > CAPI_MAXAPPL) - return CAPI_TOOMANYAPPLS; - - APPL_MARK_USED(appl); - skb_queue_head_init(&APPL(appl)->recv_queue); - - memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params)); - - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (cards[i].cardstate != CARD_RUNNING) - continue; - B1_send_register(cards[i].port, appl, - 1024 * (APPL(appl)->rparam.level3cnt + 1), - APPL(appl)->rparam.level3cnt, - APPL(appl)->rparam.datablkcnt, - APPL(appl)->rparam.datablklen); - } - *applidp = appl; - printk(KERN_INFO "b1capi: appl %d up\n", appl); - - return CAPI_NOERROR; -} - -static __u16 capi_release(__u16 applid) -{ - struct sk_buff *skb; - int i; - - if (ncards == 0) - return CAPI_REGNOTINSTALLED; - if (!VALID_APPLID(applid) || APPL(applid)->releasing) - return CAPI_ILLAPPNR; - while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) - kfree_skb(skb); - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (cards[i].cardstate != CARD_RUNNING) { - continue; - } - APPL(applid)->releasing++; - B1_send_release(cards[i].port, applid); - } - if (APPL(applid)->releasing == 0) { - APPL(applid)->signal = 0; - APPL_MARK_FREE(applid); - printk(KERN_INFO "b1capi: appl %d down\n", applid); - } - return CAPI_NOERROR; -} - -static __u16 capi_put_message(__u16 applid, struct sk_buff *skb) -{ - avmb1_ncci *np; - int contr; - if (ncards == 0) - return CAPI_REGNOTINSTALLED; - if (!VALID_APPLID(applid)) - return CAPI_ILLAPPNR; - if (skb->len < 12 - || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) - || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) - return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; - contr = CAPIMSG_CONTROLLER(skb->data); - if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) { - contr = 1; - if (CARD(contr)->cardstate != CARD_RUNNING) - return CAPI_REGNOTINSTALLED; - } - if (CARD(contr)->blocked) - return CAPI_SENDQUEUEFULL; - - if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 - && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ - && (np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0 - && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0) - return CAPI_SENDQUEUEFULL; - - B1_send_message(CARD(contr)->port, skb); - return CAPI_NOERROR; -} - -static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp) -{ - struct sk_buff *skb; - - if (!VALID_APPLID(applid)) - return CAPI_ILLAPPNR; - if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0) - return CAPI_RECEIVEQUEUEEMPTY; - *msgp = skb; - return CAPI_NOERROR; -} - -static __u16 capi_set_signal(__u16 applid, - void (*signal) (__u16 applid, __u32 param), - __u32 param) -{ - if (!VALID_APPLID(applid)) - return CAPI_ILLAPPNR; - APPL(applid)->signal = signal; - APPL(applid)->param = param; - return CAPI_NOERROR; -} - -static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]) -{ - if (contr == 0) { - strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); - return CAPI_NOERROR; - } - if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) - return 0x2002; - - strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); - return CAPI_NOERROR; -} - -static __u16 capi_get_version(__u16 contr, struct capi_version *verp) -{ - if (contr == 0) { - *verp = driver_version; - return CAPI_NOERROR; - } - if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) - return 0x2002; - - memcpy((void *) verp, &CARD(contr)->cversion, - sizeof(capi_version)); - return CAPI_NOERROR; -} - -static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN]) -{ - if (contr == 0) { - strncpy(serial, driver_serial, 8); - return CAPI_NOERROR; - } - if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) - return 0x2002; - - memcpy((void *) serial, CARD(contr)->version[VER_SERIAL], - CAPI_SERIAL_LEN); - serial[CAPI_SERIAL_LEN - 1] = 0; - return CAPI_NOERROR; -} - -static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp) -{ - if (contr == 0) { - profp->ncontroller = ncards; - return CAPI_NOERROR; - } - if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) - return 0x2002; - - memcpy((void *) profp, CARD(contr)->version[VER_PROFILE], - sizeof(struct capi_profile)); - return CAPI_NOERROR; -} - -static int capi_manufacturer(unsigned int cmd, void *data) -{ - unsigned long flags; - avmb1_loadandconfigdef ldef; - avmb1_extcarddef cdef; - avmb1_resetdef rdef; - avmb1_getdef gdef; - avmb1_card *card; - int rc; - - switch (cmd) { - case AVMB1_ADDCARD: - case AVMB1_ADDCARD_WITH_TYPE: - if (cmd == AVMB1_ADDCARD) { - if ((rc = copy_from_user((void *) &cdef, data, - sizeof(avmb1_carddef)))) - return rc; - cdef.cardtype = AVM_CARDTYPE_B1; - } else { - if ((rc = copy_from_user((void *) &cdef, data, - sizeof(avmb1_extcarddef)))) - return rc; - } - - if ((rc = avmb1_probecard(cdef.port, cdef.irq, cdef.cardtype)) != 0) - return rc; - - return avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype); - - case AVMB1_LOAD: - case AVMB1_LOAD_AND_CONFIG: - - if (cmd == AVMB1_LOAD) { - if ((rc = copy_from_user((void *) &ldef, data, - sizeof(avmb1_loaddef)))) - return rc; - ldef.t4config.len = 0; - ldef.t4config.data = 0; - } else { - if ((rc = copy_from_user((void *) &ldef, data, - sizeof(avmb1_loadandconfigdef)))) - return rc; - } - if (!VALID_CARD(ldef.contr)) - return -ESRCH; - - if (ldef.t4file.len <= 0) { - if (loaddebug) - printk(KERN_DEBUG "b1capi: load: invalid parameter length of t4file is %d ?\n", ldef.t4file.len); - return -EINVAL; - } - - card = CARD(ldef.contr); - save_flags(flags); - cli(); - if (card->cardstate != CARD_DETECTED) { - restore_flags(flags); - if (loaddebug) - printk(KERN_DEBUG "b1capi: load: contr=%d not in detect state\n", ldef.contr); - return -EBUSY; - } - card->cardstate = CARD_LOADING; - restore_flags(flags); - - if (loaddebug) { - printk(KERN_DEBUG "b1capi: load: reseting contr %d\n", - ldef.contr); - } - - B1_reset(card->port); - if ((rc = B1_load_t4file(card->port, &ldef.t4file))) { - B1_reset(card->port); - printk(KERN_ERR "b1capi: failed to load t4file!!\n"); - card->cardstate = CARD_DETECTED; - return rc; - } - B1_disable_irq(card->port); - - if (ldef.t4config.len > 0) { /* load config */ - if (loaddebug) { - printk(KERN_DEBUG "b1capi: loading config to contr %d\n", - ldef.contr); - } - if ((rc = B1_load_config(card->port, &ldef.t4config))) { - B1_reset(card->port); - printk(KERN_ERR "b1capi: failed to load config!!\n"); - card->cardstate = CARD_DETECTED; - return rc; - } - } - - if (loaddebug) { - printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n", - ldef.contr); - } - - if (!B1_loaded(card->port)) { - card->cardstate = CARD_DETECTED; - printk(KERN_ERR "b1capi: failed to load t4file.\n"); - return -EIO; - } - /* - * enable interrupt - */ - - card->cardstate = CARD_INITSTATE; - save_flags(flags); - cli(); - B1_assign_irq(card->port, card->irq, card->cardtype); - B1_enable_irq(card->port); - restore_flags(flags); - - if (loaddebug) { - printk(KERN_DEBUG "b1capi: load: irq enabled contr %d\n", - ldef.contr); - } - - /* - * init card - */ - B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1); - - if (loaddebug) { - printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n", - ldef.contr); - } - - while (card->cardstate != CARD_RUNNING) { - - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); /* 0.1 sec */ - - if (signal_pending(current)) - return -EINTR; - } - return 0; - - case AVMB1_RESETCARD: - if ((rc = copy_from_user((void *) &rdef, data, - sizeof(avmb1_resetdef)))) - return rc; - - return avmb1_resetcard(rdef.contr); - - case AVMB1_GET_CARDINFO: - if ((rc = copy_from_user((void *) &gdef, data, - sizeof(avmb1_getdef)))) - return rc; - - if (!VALID_CARD(gdef.contr)) - return -ESRCH; - - card = CARD(gdef.contr); - - gdef.cardstate = card->cardstate; - gdef.cardtype = card->cardtype; - - if ((rc = copy_to_user(data, (void *) &gdef, - sizeof(avmb1_getdef)))) - return rc; - - return 0; - } - return -EINVAL; -} - -struct capi_interface avmb1_interface = -{ - capi_installed, - capi_register, - capi_release, - capi_put_message, - capi_get_message, - capi_set_signal, - capi_get_manufacturer, - capi_get_version, - capi_get_serial, - capi_get_profile, - capi_manufacturer -}; - -/* ------------------------------------------------------------- */ -/* -------- Exported Functions --------------------------------- */ -/* ------------------------------------------------------------- */ - -struct capi_interface *attach_capi_interface(struct capi_interface_user *userp) -{ - struct capi_interface_user *p; - - for (p = capi_users; p; p = p->next) { - if (p == userp) { - printk(KERN_ERR "b1capi: double attach from %s\n", - userp->name); - return 0; - } - } - userp->next = capi_users; - capi_users = userp; - MOD_INC_USE_COUNT; - - return &avmb1_interface; -} - -int detach_capi_interface(struct capi_interface_user *userp) -{ - struct capi_interface_user **pp; - - for (pp = &capi_users; *pp; pp = &(*pp)->next) { - if (*pp == userp) { - *pp = userp->next; - userp->next = 0; - MOD_DEC_USE_COUNT; - return 0; - } - } - printk(KERN_ERR "b1capi: double detach from %s\n", userp->name); - return -1; -} - -/* ------------------------------------------------------------- */ -/* -------- Init & Cleanup ------------------------------------- */ -/* ------------------------------------------------------------- */ - -EXPORT_SYMBOL(attach_capi_interface); -EXPORT_SYMBOL(detach_capi_interface); -EXPORT_SYMBOL(avmb1_addcard); -EXPORT_SYMBOL(avmb1_probecard); -EXPORT_SYMBOL(avmb1_registercard); -EXPORT_SYMBOL(avmb1_unregistercard); -EXPORT_SYMBOL(avmb1_resetcard); -EXPORT_SYMBOL(avmb1_detectcard); - - -/* - * init / exit functions - */ - -#ifdef MODULE -#define avmb1_init init_module -#endif - -int avmb1_init(void) -{ - char *p; - char rev[10]; - - skb_queue_head_init(&recv_queue); - /* init_bh(CAPI_BH, do_capi_bh); */ - - tq_state_notify.routine = notify_handler; - tq_state_notify.data = 0; - - tq_recv_notify.routine = recv_handler; - tq_recv_notify.data = 0; - - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else - strcpy(rev, " ??? "); - -#ifdef MODULE - printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev); -#else - printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: started\n", rev); -#endif - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - char rev[10]; - char *p; - int i; - - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; - } else { - strcpy(rev, " ??? "); - } - - for (i = 0; i < CAPI_MAXCONTR; i++) { - if (cards[i].cardstate != CARD_FREE) { - /* - * disable card - */ - B1_disable_irq(cards[i].port); - avmb1_resetcard(i+1); - /* - * free kernel resources - */ - avmb1_unregistercard(i+1, 1); - } - } - schedule(); /* execute queued tasks .... */ - printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev); -} -#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.2.10/linux/drivers/isdn/avmb1/b1isa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1isa.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,238 @@ +/* + * $Id: b1isa.c,v 1.3 1999/07/09 15:05:40 keil Exp $ + * + * Module for AVM B1 ISA-card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1isa.c,v $ + * Revision 1.3 1999/07/09 15:05:40 keil + * compat.h is now isdn_compat.h + * + * Revision 1.2 1999/07/05 15:09:49 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:27 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.3 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth "); + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + +static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "b1_interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name); + return; + } + + card->interrupt = 1; + + b1_handle_interrupt(card); + + card->interrupt = 0; +} +/* ------------------------------------------------------------- */ + +static void b1isa_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + b1_reset(port); + b1_reset(port); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + +static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + avmcard *card; + int retval; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "b1isa: no memory.\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + sprintf(card->name, "b1isa-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->cardtype = avm_b1isa; + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "b1isa: ports 0x%03x-0x%03x in use.\n", + card->port, card->port + AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + if (b1_irq_table[card->irq & 0xf] == 0) { + printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); + kfree(card); + return -EINVAL; + } + if ( card->port != 0x150 && card->port != 0x250 + && card->port != 0x300 && card->port != 0x340) { + printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port); + kfree(card); + return -EINVAL; + } + b1_reset(card->port); + if ((retval = b1_detect(card->port, card->cardtype)) != 0) { + printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n", + card->port, retval); + kfree(card); + return -EIO; + } + b1_reset(card->port); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, b1isa_interrupt, 0, card->name, card); + if (retval) { + printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + card->ctrl = di->attach_ctr(driver, card->name, card); + if (!card->ctrl) { + printk(KERN_ERR "b1isa: attach controller failed.\n"); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + MOD_INC_USE_COUNT; + return 0; +} + +static char *b1isa_procinfo(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + if (!card) + return ""; + sprintf(card->infobuf, "%s %s 0x%x %d", + card->cardname[0] ? card->cardname : "-", + card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-", + card->port, card->irq + ); + return card->infobuf; +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver b1isa_driver = { + "b1isa", + "0.0", + b1_load_firmware, + b1_reset_ctr, + b1isa_remove_ctr, + b1_register_appl, + b1_release_appl, + b1_send_message, + + b1isa_procinfo, + b1ctl_read_proc, + 0, /* use standard driver_read_proc */ + + b1isa_add_card, +}; + +#ifdef MODULE +#define b1isa_init init_module +void cleanup_module(void); +#endif + +int b1isa_init(void) +{ + struct capi_driver *driver = &b1isa_driver; + char *p; + + if ((p = strchr(revision, ':'))) { + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); + *p = 0; + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + detach_capi_driver(&b1isa_driver); +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1lli.c linux/drivers/isdn/avmb1/b1lli.c --- v2.2.10/linux/drivers/isdn/avmb1/b1lli.c Wed Dec 23 09:44:41 1998 +++ linux/drivers/isdn/avmb1/b1lli.c Wed Dec 31 16:00:00 1969 @@ -1,749 +0,0 @@ -/* - * $Id: b1lli.c,v 1.6 1998/02/13 07:09:11 calle Exp $ - * - * ISDN lowlevel-module for AVM B1-card. - * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: b1lli.c,v $ - * Revision 1.6 1998/02/13 07:09:11 calle - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.5 1998/01/31 11:14:41 calle - * merged changes to 2.0 tree, prepare 2.1.82 to work. - * - * Revision 1.4 1997/12/10 20:00:48 calle - * get changes from 2.0 version - * - * Revision 1.1.2.2 1997/11/26 10:46:55 calle - * prepared for M1 (Mobile) and T1 (PMX) cards. - * prepared to set configuration after load to support other D-channel - * protocols, point-to-point and leased lines. - * - * Revision 1.3 1997/10/01 09:21:13 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.2 1997/07/13 12:22:42 calle - * bug fix for more than one controller in connect_req. - * debugoutput now with contrnr. - * - * - * Revision 1.1 1997/03/04 21:50:28 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "compat.h" -#include "capicmd.h" -#include "capiutil.h" - -/* - * LLI Messages to the ISDN-ControllerISDN Controller - */ - -#define SEND_POLL 0x72 /* - * after load <- RECEIVE_POLL - */ -#define SEND_INIT 0x11 /* - * first message <- RECEIVE_INIT - * int32 NumApplications int32 - * NumNCCIs int32 BoardNumber - */ -#define SEND_REGISTER 0x12 /* - * register an application int32 - * ApplIDId int32 NumMessages - * int32 NumB3Connections int32 - * NumB3Blocks int32 B3Size - * - * AnzB3Connection != 0 && - * AnzB3Blocks >= 1 && B3Size >= 1 - */ -#define SEND_RELEASE 0x14 /* - * deregister an application int32 - * ApplID - */ -#define SEND_MESSAGE 0x15 /* - * send capi-message int32 length - * capi-data ... - */ -#define SEND_DATA_B3_REQ 0x13 /* - * send capi-data-message int32 - * MsgLength capi-data ... int32 - * B3Length data .... - */ - -#define SEND_CONFIG 0x21 /* - */ - -/* - * LLI Messages from the ISDN-ControllerISDN Controller - */ - -#define RECEIVE_POLL 0x32 /* - * <- after SEND_POLL - */ -#define RECEIVE_INIT 0x27 /* - * <- after SEND_INIT int32 length - * byte total length b1struct board - * driver revision b1struct card - * type b1struct reserved b1struct - * serial number b1struct driver - * capability b1struct d-channel - * protocol b1struct CAPI-2.0 - * profile b1struct capi version - */ -#define RECEIVE_MESSAGE 0x21 /* - * <- after SEND_MESSAGE int32 - * AppllID int32 Length capi-data - * .... - */ -#define RECEIVE_DATA_B3_IND 0x22 /* - * received data int32 AppllID - * int32 Length capi-data ... - * int32 B3Length data ... - */ -#define RECEIVE_START 0x23 /* - * Handshake - */ -#define RECEIVE_STOP 0x24 /* - * Handshake - */ -#define RECEIVE_NEW_NCCI 0x25 /* - * int32 AppllID int32 NCCI int32 - * WindowSize - */ -#define RECEIVE_FREE_NCCI 0x26 /* - * int32 AppllID int32 NCCI - */ -#define RECEIVE_RELEASE 0x26 /* - * int32 AppllID int32 0xffffffff - */ - -#define WRITE_REGISTER 0x00 -#define READ_REGISTER 0x01 - -/* - * port offsets - */ - -#define B1_READ 0x00 -#define B1_WRITE 0x01 -#define B1_INSTAT 0x02 -#define B1_OUTSTAT 0x03 -#define B1_RESET 0x10 -#define B1_ANALYSE 0x04 -#define B1_IDENT 0x17 /* Hema card T1 */ -#define B1_IRQ_MASTER 0x12 /* Hema card T1 */ - -#define B1_STAT0(cardtype) ((cardtype) == AVM_CARDTYPE_M1 ? 0x81200000l : 0x80A00000l) -#define B1_STAT1(cardtype) (0x80E00000l) - - -static inline unsigned char b1outp(unsigned short base, - unsigned short offset, - unsigned char value) -{ - outb(value, base + offset); - return inb(base + B1_ANALYSE); -} - -static inline int B1_rx_full(unsigned short base) -{ - return inb(base + B1_INSTAT) & 0x1; -} - -static inline unsigned char B1_get_byte(unsigned short base) -{ - unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */ - while (!B1_rx_full(base) && time_before(jiffies, i)); - if (B1_rx_full(base)) - return inb(base + B1_READ); - printk(KERN_CRIT "b1lli: rx not full after 5 second\n"); - return 0; -} - -static inline unsigned int B1_get_word(unsigned short base) -{ - unsigned int val = 0; - val |= B1_get_byte(base); - val |= (B1_get_byte(base) << 8); - val |= (B1_get_byte(base) << 16); - val |= (B1_get_byte(base) << 24); - return val; -} - -static inline int B1_tx_empty(unsigned short base) -{ - return inb(base + B1_OUTSTAT) & 0x1; -} - -static inline void B1_put_byte(unsigned short base, unsigned char val) -{ - while (!B1_tx_empty(base)); - b1outp(base, B1_WRITE, val); -} - -static inline void B1_put_word(unsigned short base, unsigned int val) -{ - B1_put_byte(base, val & 0xff); - B1_put_byte(base, (val >> 8) & 0xff); - B1_put_byte(base, (val >> 16) & 0xff); - B1_put_byte(base, (val >> 24) & 0xff); -} - -static inline unsigned int B1_get_slice(unsigned short base, - unsigned char *dp) -{ - unsigned int len, i; - - len = i = B1_get_word(base); - while (i-- > 0) - *dp++ = B1_get_byte(base); - return len; -} - -static inline void B1_put_slice(unsigned short base, - unsigned char *dp, unsigned int len) -{ - B1_put_word(base, len); - while (len-- > 0) - B1_put_byte(base, *dp++); -} - -static void b1_wr_reg(unsigned short base, - unsigned int reg, - unsigned int value) -{ - B1_put_byte(base, WRITE_REGISTER); - B1_put_word(base, reg); - B1_put_word(base, value); -} - -static inline unsigned int b1_rd_reg(unsigned short base, - unsigned int reg) -{ - B1_put_byte(base, READ_REGISTER); - B1_put_word(base, reg); - return B1_get_word(base); - -} - -static inline void b1_set_test_bit(unsigned short base, - int cardtype, - int onoff) -{ - b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20); -} - -static inline int b1_get_test_bit(unsigned short base, - int cardtype) -{ - return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0; -} - -static int irq_table[16] = -{0, - 0, - 0, - 192, /* irq 3 */ - 32, /* irq 4 */ - 160, /* irq 5 */ - 96, /* irq 6 */ - 224, /* irq 7 */ - 0, - 64, /* irq 9 */ - 80, /* irq 10 */ - 208, /* irq 11 */ - 48, /* irq 12 */ - 0, - 0, - 112, /* irq 15 */ -}; - -int B1_valid_irq(unsigned irq, int cardtype) -{ - switch (cardtype) { - default: - case AVM_CARDTYPE_M1: - case AVM_CARDTYPE_M2: - case AVM_CARDTYPE_B1: - return irq_table[irq] != 0; - case AVM_CARDTYPE_T1: - return irq == 5; - } -} - -unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype) -{ - switch (cardtype) { - case AVM_CARDTYPE_T1: - return b1outp(base, B1_IRQ_MASTER, 0x08); - default: - case AVM_CARDTYPE_M1: - case AVM_CARDTYPE_M2: - case AVM_CARDTYPE_B1: - return b1outp(base, B1_RESET, irq_table[irq]); - } -} - -unsigned char B1_enable_irq(unsigned short base) -{ - return b1outp(base, B1_INSTAT, 0x02); -} - -unsigned char B1_disable_irq(unsigned short base) -{ - return b1outp(base, B1_INSTAT, 0x00); -} - -void B1_reset(unsigned short base) -{ - b1outp(base, B1_RESET, 0); - udelay(55 * 2 * 1000); /* 2 TIC's */ - - b1outp(base, B1_RESET, 1); - udelay(55 * 2 * 1000); /* 2 TIC's */ - - b1outp(base, B1_RESET, 0); - udelay(55 * 2 * 1000); /* 2 TIC's */ -} - -int B1_detect(unsigned short base, int cardtype) -{ - int onoff, i; - - if (cardtype == AVM_CARDTYPE_T1) - return 0; - - /* - * Statusregister 0000 00xx - */ - if ((inb(base + B1_INSTAT) & 0xfc) - || (inb(base + B1_OUTSTAT) & 0xfc)) - return 1; - /* - * Statusregister 0000 001x - */ - b1outp(base, B1_INSTAT, 0x2); /* enable irq */ - /* b1outp(base, B1_OUTSTAT, 0x2); */ - if ((inb(base + B1_INSTAT) & 0xfe) != 0x2 - /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */) - return 2; - /* - * Statusregister 0000 000x - */ - b1outp(base, B1_INSTAT, 0x0); /* disable irq */ - b1outp(base, B1_OUTSTAT, 0x0); - if ((inb(base + B1_INSTAT) & 0xfe) - || (inb(base + B1_OUTSTAT) & 0xfe)) - return 3; - - for (onoff = !0, i= 0; i < 10 ; i++) { - b1_set_test_bit(base, cardtype, onoff); - if (b1_get_test_bit(base, cardtype) != onoff) - return 4; - onoff = !onoff; - } - - if (cardtype == AVM_CARDTYPE_M1) - return 0; - - if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01) - return 5; - - return 0; -} - - -extern int loaddebug; - -int B1_load_t4file(unsigned short base, avmb1_t4file * t4file) -{ - /* - * Data is in user space !!! - */ - unsigned char buf[256]; - unsigned char *dp; - int i, left, retval; - - - dp = t4file->data; - left = t4file->len; - while (left > sizeof(buf)) { - retval = copy_from_user(buf, dp, sizeof(buf)); - if (retval) - return -EFAULT; - if (loaddebug) - printk(KERN_DEBUG "b1capi: loading: %d bytes ..", sizeof(buf)); - for (i = 0; i < sizeof(buf); i++) - B1_put_byte(base, buf[i]); - if (loaddebug) - printk("ok\n"); - left -= sizeof(buf); - dp += sizeof(buf); - } - if (left) { - retval = copy_from_user(buf, dp, left); - if (retval) - return -EFAULT; - if (loaddebug) - printk(KERN_DEBUG "b1capi: loading: %d bytes ..", left); - for (i = 0; i < left; i++) - B1_put_byte(base, buf[i]); - if (loaddebug) - printk("ok\n"); - } - return 0; -} - -int B1_load_config(unsigned short base, avmb1_t4file * config) -{ - /* - * Data is in user space !!! - */ - unsigned char buf[256]; - unsigned char *dp; - int i, j, left, retval; - - - dp = config->data; - left = config->len; - if (left) { - B1_put_byte(base, SEND_CONFIG); - B1_put_word(base, 1); - B1_put_byte(base, SEND_CONFIG); - B1_put_word(base, left); - } - while (left > sizeof(buf)) { - retval = copy_from_user(buf, dp, sizeof(buf)); - if (retval) - return -EFAULT; - if (loaddebug) - printk(KERN_DEBUG "b1capi: conf load: %d bytes ..", sizeof(buf)); - for (i = 0; i < sizeof(buf); ) { - B1_put_byte(base, SEND_CONFIG); - for (j=0; j < 4; j++) { - B1_put_byte(base, buf[i++]); - } - } - if (loaddebug) - printk("ok\n"); - left -= sizeof(buf); - dp += sizeof(buf); - } - if (left) { - retval = copy_from_user(buf, dp, left); - if (retval) - return -EFAULT; - if (loaddebug) - printk(KERN_DEBUG "b1capi: conf load: %d bytes ..", left); - for (i = 0; i < left; ) { - B1_put_byte(base, SEND_CONFIG); - for (j=0; j < 4; j++) { - if (i < left) - B1_put_byte(base, buf[i++]); - else - B1_put_byte(base, 0); - } - } - if (loaddebug) - printk("ok\n"); - } - return 0; -} - -int B1_loaded(unsigned short base) -{ - int i; - unsigned char ans; - - if (loaddebug) - printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n"); - for (i = jiffies + 10 * HZ; time_before(jiffies, i);) { - if (B1_tx_empty(base)) - break; - } - if (!B1_tx_empty(base)) { - printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n"); - return 0; - } - B1_put_byte(base, SEND_POLL); - printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n"); - for (i = jiffies + 10 * HZ; time_before(jiffies, i);) { - if (B1_rx_full(base)) { - if ((ans = B1_get_byte(base)) == RECEIVE_POLL) { - if (loaddebug) - printk(KERN_DEBUG "b1capi: loaded: ok\n"); - return 1; - } - printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans); - return 0; - } - } - printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n"); - return 0; -} - -/* - * ------------------------------------------------------------------- - */ -static inline void parse_version(avmb1_card * card) -{ - int i, j; - for (j = 0; j < AVM_MAXVERSION; j++) - card->version[j] = "\0\0" + 1; - for (i = 0, j = 0; - j < AVM_MAXVERSION && i < card->versionlen; - j++, i += card->versionbuf[i] + 1) - card->version[j] = &card->versionbuf[i + 1]; -} -/* - * ------------------------------------------------------------------- - */ - -void B1_send_init(unsigned short port, - unsigned int napps, unsigned int nncci, unsigned int cardnr) -{ - unsigned long flags; - - save_flags(flags); - cli(); - B1_put_byte(port, SEND_INIT); - B1_put_word(port, napps); - B1_put_word(port, nncci); - B1_put_word(port, cardnr); - restore_flags(flags); -} - -void B1_send_register(unsigned short port, - __u16 appid, __u32 nmsg, - __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize) -{ - unsigned long flags; - - save_flags(flags); - cli(); - B1_put_byte(port, SEND_REGISTER); - B1_put_word(port, appid); - B1_put_word(port, nmsg); - B1_put_word(port, nb3conn); - B1_put_word(port, nb3blocks); - B1_put_word(port, b3bsize); - restore_flags(flags); -} - -void B1_send_release(unsigned short port, - __u16 appid) -{ - unsigned long flags; - - save_flags(flags); - cli(); - B1_put_byte(port, SEND_RELEASE); - B1_put_word(port, appid); - restore_flags(flags); -} - -extern int showcapimsgs; - -void B1_send_message(unsigned short port, struct sk_buff *skb) -{ - unsigned long flags; - __u16 len = CAPIMSG_LEN(skb->data); - __u8 cmd = CAPIMSG_COMMAND(skb->data); - __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); - __u32 contr = CAPIMSG_CONTROL(skb->data); - - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - __u16 dlen = CAPIMSG_DATALEN(skb->data); - - if (showcapimsgs > 2) { - if (showcapimsgs & 1) { - printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n", - (unsigned long) contr, - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), len); - } else { - printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n", - (unsigned long) contr, - capi_message2str(skb->data)); - } - - } - save_flags(flags); - cli(); - B1_put_byte(port, SEND_DATA_B3_REQ); - B1_put_slice(port, skb->data, len); - B1_put_slice(port, skb->data + len, dlen); - restore_flags(flags); - } else { - if (showcapimsgs) { - - if (showcapimsgs & 1) { - printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n", - (unsigned long) contr, - CAPIMSG_APPID(skb->data), - capi_cmd2str(cmd, subcmd), len); - } else { - printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n", (unsigned long)contr, capi_message2str(skb->data)); - } - } - save_flags(flags); - cli(); - B1_put_byte(port, SEND_MESSAGE); - B1_put_slice(port, skb->data, len); - restore_flags(flags); - } - dev_kfree_skb(skb); -} - -/* - * ------------------------------------------------------------------- - */ - -void B1_handle_interrupt(avmb1_card * card) -{ - unsigned char b1cmd; - struct sk_buff *skb; - - unsigned ApplId; - unsigned MsgLen; - unsigned DataB3Len; - unsigned NCCI; - unsigned WindowSize; - - if (!B1_rx_full(card->port)) - return; - - b1cmd = B1_get_byte(card->port); - - switch (b1cmd) { - - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) B1_get_word(card->port); - MsgLen = B1_get_slice(card->port, card->msgbuf); - DataB3Len = B1_get_slice(card->port, card->databuf); - - if (showcapimsgs > 2) { - __u8 cmd = CAPIMSG_COMMAND(card->msgbuf); - __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf); - __u32 contr = CAPIMSG_CONTROL(card->msgbuf); - CAPIMSG_SETDATA(card->msgbuf, card->databuf); - if (showcapimsgs & 1) { - printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u/%u\n", - (unsigned long) contr, - CAPIMSG_APPID(card->msgbuf), - capi_cmd2str(cmd, subcmd), - MsgLen, DataB3Len); - } else { - printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n", (unsigned long)contr, capi_message2str(card->msgbuf)); - } - } - if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) { - printk(KERN_ERR "b1lli: incoming packet dropped\n"); - } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); - CAPIMSG_SETDATA(skb->data, skb->data + MsgLen); - avmb1_handle_capimsg(card, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) B1_get_word(card->port); - MsgLen = B1_get_slice(card->port, card->msgbuf); - if (showcapimsgs) { - __u8 cmd = CAPIMSG_COMMAND(card->msgbuf); - __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf); - __u32 contr = CAPIMSG_CONTROL(card->msgbuf); - if (showcapimsgs & 1) { - printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u\n", - (unsigned long) contr, - CAPIMSG_APPID(card->msgbuf), - capi_cmd2str(cmd, subcmd), - MsgLen); - } else { - printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n", - (unsigned long) contr, - capi_message2str(card->msgbuf)); - } - - } - if (!(skb = dev_alloc_skb(MsgLen))) { - printk(KERN_ERR "b1lli: incoming packet dropped\n"); - } else { - memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); - avmb1_handle_capimsg(card, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = B1_get_word(card->port); - NCCI = B1_get_word(card->port); - WindowSize = B1_get_word(card->port); - - if (showcapimsgs) - printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI); - - avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize); - - break; - - case RECEIVE_FREE_NCCI: - - ApplId = B1_get_word(card->port); - NCCI = B1_get_word(card->port); - - if (showcapimsgs) - printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI); - - avmb1_handle_free_ncci(card, ApplId, NCCI); - break; - - case RECEIVE_START: - if (card->blocked) - printk(KERN_DEBUG "b1lli: RESTART\n"); - card->blocked = 0; - break; - - case RECEIVE_STOP: - printk(KERN_DEBUG "b1lli: STOP\n"); - card->blocked = 1; - break; - - case RECEIVE_INIT: - - card->versionlen = B1_get_slice(card->port, card->versionbuf); - card->cardstate = CARD_ACTIVE; - parse_version(card); - printk(KERN_INFO "b1lli: %s-card (%s) now active\n", - card->version[VER_CARDTYPE], - card->version[VER_DRIVER]); - avmb1_card_ready(card); - break; - default: - printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd); - break; - } -} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.2.10/linux/drivers/isdn/avmb1/b1pci.c Thu May 21 13:45:01 1998 +++ linux/drivers/isdn/avmb1/b1pci.c Mon Aug 9 12:04:39 1999 @@ -1,40 +1,59 @@ /* - * $Id: b1pci.c,v 1.5 1998/01/31 11:14:43 calle Exp $ + * $Id: b1pci.c,v 1.14 1999/07/09 15:05:41 keil Exp $ * * Module for AVM B1 PCI-card. * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ - * Revision 1.5 1998/01/31 11:14:43 calle - * merged changes to 2.0 tree, prepare 2.1.82 to work. + * Revision 1.14 1999/07/09 15:05:41 keil + * compat.h is now isdn_compat.h * - * Revision 1.4 1997/12/10 20:00:50 calle - * get changes from 2.0 version + * Revision 1.13 1999/07/05 15:09:50 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. * - * Revision 1.3 1997/10/01 09:21:14 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. + * Revision 1.12 1999/07/01 15:26:29 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. * - * Revision 1.2 1997/05/18 09:24:13 calle - * added verbose disconnect reason reporting to avmb1. - * some fixes in capi20 interface. - * changed info messages for B1-PCI - * - * Revision 1.1 1997/03/30 17:10:42 calle - * added support for AVM-B1-PCI card. * */ #include #include #include -#include #include -#include "compat.h" +#include +#include +#include +#include +#include #include -#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.14 $"; + +/* ------------------------------------------------------------- */ #ifndef PCI_VENDOR_ID_AVM #define PCI_VENDOR_ID_AVM 0x1244 @@ -44,65 +63,213 @@ #define PCI_DEVICE_ID_AVM_B1 0x700 #endif -static char *revision = "$Revision: 1.5 $"; - /* ------------------------------------------------------------- */ MODULE_AUTHOR("Carsten Paeth "); /* ------------------------------------------------------------- */ +static struct capi_driver_interface *di; + /* ------------------------------------------------------------- */ -/* -------- Init & Cleanup ------------------------------------- */ + +static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "b1_interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name); + return; + } + + card->interrupt = 1; + + b1_handle_interrupt(card); + + card->interrupt = 0; +} /* ------------------------------------------------------------- */ -/* - * init / exit functions - */ +static void b1pci_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + b1_reset(port); + b1_reset(port); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + ctrl->driverdata = 0; + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + +static char *b1pci_procinfo(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + if (!card) + return ""; + sprintf(card->infobuf, "%s %s 0x%x %d", + card->cardname[0] ? card->cardname : "-", + card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-", + card->port, card->irq + ); + return card->infobuf; +} + +/* ------------------------------------------------------------- */ + +static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + avmcard *card; + int retval; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "b1pci: no memory.\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + sprintf(card->name, "b1pci-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->cardtype = avm_b1pci; + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "b1pci: ports 0x%03x-0x%03x in use.\n", + card->port, card->port + AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + b1_reset(card->port); + if ((retval = b1_detect(card->port, card->cardtype)) != 0) { + printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", + card->port, retval); + kfree(card); + return -EIO; + } + b1_reset(card->port); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, b1pci_interrupt, 0, card->name, card); + if (retval) { + printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + card->ctrl = di->attach_ctr(driver, card->name, card); + if (!card->ctrl) { + printk(KERN_ERR "b1pci: attach controller failed.\n"); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + MOD_INC_USE_COUNT; + + return 0; +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver b1pci_driver = { + "b1pci", + "0.0", + b1_load_firmware, + b1_reset_ctr, + b1pci_remove_ctr, + b1_register_appl, + b1_release_appl, + b1_send_message, + + b1pci_procinfo, + b1ctl_read_proc, + 0, /* use standard driver_read_proc */ + + 0, /* no add_card function */ +}; #ifdef MODULE #define b1pci_init init_module +void cleanup_module(void); #endif +static int ncards = 0; + int b1pci_init(void) { - char *p; - char rev[10]; - int rc; + struct capi_driver *driver = &b1pci_driver; struct pci_dev *dev = NULL; + char *p; + int retval; if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); *p = 0; - } else - strcpy(rev, " ??? "); + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } #ifdef CONFIG_PCI if (!pci_present()) { - printk(KERN_ERR "b1pci: no PCI bus present\n"); + printk(KERN_ERR "%s: no PCI bus present\n", driver->name); + detach_capi_driver(driver); return -EIO; } - printk(KERN_INFO "b1pci: revision %s\n", rev); - while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) { - unsigned int ioaddr = dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - unsigned int irq = dev->irq; + struct capicardparams param; + + param.port = dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + param.irq = dev->irq; printk(KERN_INFO - "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", - ioaddr, irq); - if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1)) != 0) { + "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", + driver->name, param.port, param.irq); + retval = b1pci_add_card(driver, ¶m); + if (retval != 0) { printk(KERN_ERR - "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", - ioaddr, irq); - return rc; + "%s: no AVM-B1 at i/o %#x, irq %d detected\n", + driver->name, param.port, param.irq); +#ifdef MODULE + cleanup_module(); +#endif + return retval; } - if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1)) < 0) - return rc; + ncards++; } - return 0; + if (ncards) { + printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n", + driver->name, ncards); + return 0; + } + printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name); + return -ESRCH; #else printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n"); return -EIO; @@ -112,5 +279,6 @@ #ifdef MODULE void cleanup_module(void) { + detach_capi_driver(&b1pci_driver); } #endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.2.10/linux/drivers/isdn/avmb1/b1pcmcia.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,267 @@ +/* + * $Id: b1pcmcia.c,v 1.3 1999/07/09 15:05:41 keil Exp $ + * + * Module for AVM B1/M1/M2 PCMCIA-card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: b1pcmcia.c,v $ + * Revision 1.3 1999/07/09 15:05:41 keil + * compat.h is now isdn_compat.h + * + * Revision 1.2 1999/07/05 15:09:51 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:30 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.3 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth "); + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + +static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "b1_interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name); + return; + } + + card->interrupt = 1; + + b1_handle_interrupt(card); + + card->interrupt = 0; +} +/* ------------------------------------------------------------- */ + +static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + b1_reset(port); + b1_reset(port); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + /* io addrsses managent by CardServices + * release_region(card->port, AVMB1_PORTLEN); + */ + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + +static int b1pcmcia_add_card(struct capi_driver *driver, + unsigned int port, + unsigned irq, + enum avmcardtype cardtype) +{ + avmcard *card; + int retval; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "b1pcmcia: no memory.\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + switch (cardtype) { + case avm_m1: sprintf(card->name, "m1-%x", port); break; + case avm_m2: sprintf(card->name, "m2-%x", port); break; + default: sprintf(card->name, "b1pcmcia-%x", port); break; + } + card->port = port; + card->irq = irq; + card->cardtype = cardtype; + + b1_reset(card->port); + if ((retval = b1_detect(card->port, card->cardtype)) != 0) { + printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n", + card->port, retval); + kfree(card); + return -EIO; + } + b1_reset(card->port); + + retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card); + if (retval) { + printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", card->irq); + kfree(card); + return -EBUSY; + } + + card->ctrl = di->attach_ctr(driver, card->name, card); + if (!card->ctrl) { + printk(KERN_ERR "b1pcmcia: attach controller failed.\n"); + free_irq(card->irq, card); + kfree(card); + return -EBUSY; + } + + MOD_INC_USE_COUNT; + return card->ctrl->cnr; +} + +/* ------------------------------------------------------------- */ + +static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + if (!card) + return ""; + sprintf(card->infobuf, "%s %s 0x%x %d", + card->cardname[0] ? card->cardname : "-", + card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-", + card->port, card->irq + ); + return card->infobuf; +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver b1pcmcia_driver = { + "b1pcmcia", + "0.0", + b1_load_firmware, + b1_reset_ctr, + b1pcmcia_remove_ctr, + b1_register_appl, + b1_release_appl, + b1_send_message, + + b1pcmcia_procinfo, + b1ctl_read_proc, + 0, /* use standard driver_read_proc */ + + 0, +}; + +/* ------------------------------------------------------------- */ + +int b1pcmcia_addcard_b1(unsigned int port, unsigned irq) +{ + return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia); +} + +int b1pcmcia_addcard_m1(unsigned int port, unsigned irq) +{ + return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1); +} + +int b1pcmcia_addcard_m2(unsigned int port, unsigned irq) +{ + return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2); +} + +int b1pcmcia_delcard(unsigned int port, unsigned irq) +{ + struct capi_ctr *ctrl; + avmcard *card; + + for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) { + card = (avmcard *)(ctrl->driverdata); + if (card->port == port && card->irq == irq) { + b1pcmcia_remove_ctr(ctrl); + return 0; + } + } + return -ESRCH; +} + +EXPORT_SYMBOL(b1pcmcia_addcard_b1); +EXPORT_SYMBOL(b1pcmcia_addcard_m1); +EXPORT_SYMBOL(b1pcmcia_addcard_m2); +EXPORT_SYMBOL(b1pcmcia_delcard); + +/* ------------------------------------------------------------- */ + +#ifdef MODULE +#define b1pcmcia_init init_module +void cleanup_module(void); +#endif + +int b1pcmcia_init(void) +{ + struct capi_driver *driver = &b1pcmcia_driver; + char *p; + + if ((p = strchr(revision, ':'))) { + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); + *p = 0; + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + detach_capi_driver(&b1pcmcia_driver); +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.2.10/linux/drivers/isdn/avmb1/capi.c Mon Aug 24 13:02:44 1998 +++ linux/drivers/isdn/avmb1/capi.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,55 @@ /* - * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $ + * $Id: capi.c,v 1.19 1999/07/09 15:05:42 keil Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.19 1999/07/09 15:05:42 keil + * compat.h is now isdn_compat.h + * + * Revision 1.18 1999/07/06 07:42:01 calle + * - changes in /proc interface + * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. + * + * Revision 1.17 1999/07/01 15:26:30 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * Revision 1.16 1999/07/01 08:22:57 keil + * compatibility macros now in + * + * Revision 1.15 1999/06/21 15:24:11 calle + * extend information in /proc. + * + * Revision 1.14 1999/06/10 16:51:03 calle + * Bugfix: open/release of control device was not handled correct. + * + * Revision 1.13 1998/08/28 04:32:25 calle + * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1 + * driver running with 2.1.118. + * + * Revision 1.12 1998/05/26 22:39:34 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * + * Revision 1.11 1998/03/09 17:46:37 he + * merged in 2.1.89 changes + * * Revision 1.10 1998/02/13 07:09:13 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -68,11 +112,12 @@ #include #include #include +#include #include #include #include -#include "compat.h" +#include #include "capiutil.h" #include "capicmd.h" #include "capidev.h" @@ -166,7 +211,10 @@ } copied = skb->len; - + if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) + cdev->nrecvdatapkt++; + else cdev->nrecvctlpkt++; kfree_skb(skb); return copied; @@ -195,7 +243,7 @@ skb = alloc_skb(count, GFP_USER); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { - dev_kfree_skb(skb); + kfree_skb(skb); return retval; } cmd = CAPIMSG_COMMAND(skb->data); @@ -204,11 +252,11 @@ if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { __u16 dlen = CAPIMSG_DATALEN(skb->data); if (mlen + dlen != count) { - dev_kfree_skb(skb); + kfree_skb(skb); return -EINVAL; } } else if (mlen != count) { - dev_kfree_skb(skb); + kfree_skb(skb); return -EINVAL; } CAPIMSG_SETAPPID(skb->data, cdev->applid); @@ -216,9 +264,12 @@ cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb); if (cdev->errcode) { - dev_kfree_skb(skb); + kfree_skb(skb); return -EIO; } + if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) + cdev->nsentdatapkt++; + else cdev->nsentctlpkt++; return count; } @@ -237,6 +288,9 @@ return POLLERR; cdev = &capidevs[minor]; +#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */ +#define poll_wait(f,wq,w) poll_wait((wq),(w)) +#endif poll_wait(file, &(cdev->recv_wait), wait); mask = POLLOUT | POLLWRNORM; if (!skb_queue_empty(&cdev->recv_queue)) @@ -411,16 +465,13 @@ capidevs[minor].is_open = 1; skb_queue_head_init(&capidevs[minor].recv_queue); MOD_INC_USE_COUNT; + capidevs[minor].nopen++; } else { - - if (!capidevs[minor].is_open) { - capidevs[minor].is_open = 1; - MOD_INC_USE_COUNT; - } + capidevs[minor].is_open++; + MOD_INC_USE_COUNT; } - return 0; } @@ -445,10 +496,13 @@ cdev->is_registered = 0; cdev->applid = 0; - while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) + while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) { kfree_skb(skb); + } + cdev->is_open = 0; + } else { + cdev->is_open--; } - cdev->is_open = 0; MOD_DEC_USE_COUNT; return 0; @@ -464,13 +518,90 @@ capi_ioctl, NULL, /* capi_mmap */ capi_open, - NULL, /* flush */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) + NULL, /* capi_flush */ +#endif capi_release, NULL, /* capi_fsync */ NULL, /* capi_fasync */ }; +/* -------- /proc functions ----------------------------------- */ +/* + * /proc/capi/capi20: + * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt + */ +static int proc_capidev_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capidev *cp; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXMINOR; i++) { + cp = &capidevs[i+1]; + if (cp->nopen == 0) continue; + len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n", + i+1, + cp->nopen, + cp->nrecvctlpkt, + cp->nrecvdatapkt, + cp->nsentctlpkt, + cp->nsentdatapkt); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (i >= CAPI_MAXMINOR) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +static struct procfsentries { + char *name; + mode_t mode; + int (*read_proc)(char *page, char **start, off_t off, + int count, int *eof, void *data); + struct proc_dir_entry *procent; +} procfsentries[] = { + /* { "capi", S_IFDIR, 0 }, */ + { "capi/capi20", 0 , proc_capidev_read_proc }, +}; + +static void proc_init(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=0; i < nelem; i++) { + struct procfsentries *p = procfsentries + i; + p->procent = create_proc_entry(p->name, p->mode, 0); + if (p->procent) p->procent->read_proc = p->read_proc; + } +} + +static void proc_exit(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=nelem-1; i >= 0; i--) { + struct procfsentries *p = procfsentries + i; + if (p->procent) { + remove_proc_entry(p->name, 0); + p->procent = 0; + } + } +} /* -------- init function and module interface ---------------------- */ #ifdef MODULE @@ -484,7 +615,16 @@ int capi_init(void) { +#ifdef COMPAT_HAS_NEW_WAITQ + int j; +#endif + memset(capidevs, 0, sizeof(capidevs)); +#ifdef COMPAT_HAS_NEW_WAITQ + for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) { + init_waitqueue_head(&capidevs[j].recv_wait); + } +#endif if (register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); @@ -496,12 +636,14 @@ unregister_chrdev(capi_major, "capi20"); return -EIO; } + (void)proc_init(); return 0; } #ifdef MODULE void cleanup_module(void) { + (void)proc_exit(); unregister_chrdev(capi_major, "capi20"); (void) detach_capi_interface(&cuser); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capidev.h linux/drivers/isdn/avmb1/capidev.h --- v2.2.10/linux/drivers/isdn/avmb1/capidev.h Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/avmb1/capidev.h Mon Aug 9 12:04:39 1999 @@ -1,11 +1,33 @@ /* - * $Id: capidev.h,v 1.1 1997/03/04 21:50:30 calle Exp $ + * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $ * * CAPI 2.0 Interface for Linux * * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidev.h,v $ + * Revision 1.4 1999/07/01 15:26:32 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * Revision 1.3 1999/07/01 08:22:58 keil + * compatibility macros now in + * + * Revision 1.2 1999/06/21 15:24:13 calle + * extend information in /proc. + * * Revision 1.1 1997/03/04 21:50:30 calle * Frirst version in isdn4linux * @@ -22,8 +44,18 @@ int is_registered; __u16 applid; struct sk_buff_head recv_queue; +#ifdef COMPAT_HAS_NEW_WAITQ + wait_queue_head_t recv_wait; +#else struct wait_queue *recv_wait; +#endif __u16 errcode; + /* Statistic */ + unsigned long nopen; + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; }; #define CAPI_MAXMINOR CAPI_MAXAPPL diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.2.10/linux/drivers/isdn/avmb1/capidrv.c Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/avmb1/capidrv.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,83 @@ /* - * $Id: capidrv.c,v 1.11 1998/02/13 07:09:15 calle Exp $ + * $Id: capidrv.c,v 1.23 1999/07/09 15:05:44 keil Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.23 1999/07/09 15:05:44 keil + * compat.h is now isdn_compat.h + * + * Revision 1.22 1999/07/06 07:24:14 calle + * Bugfix: call to kfree_skb in capidrv_signal was too early, + * thanks to Lars Heete . + * + * Revision 1.21 1999/07/01 15:26:34 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * Revision 1.20 1999/07/01 08:22:59 keil + * compatibility macros now in + * + * Revision 1.19 1999/06/29 16:16:54 calle + * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again. + * Also right unlocking (ISDN_CMD_UNLOCK) is done now. + * isdnlog should check returncode of read(2) calls. + * + * Revision 1.18 1999/06/21 15:24:15 calle + * extend information in /proc. + * + * Revision 1.17 1999/06/10 16:53:55 calle + * Removing of module b1pci will now remove card from lower level. + * + * Revision 1.16 1999/05/31 11:50:33 calle + * Bugfix: In if_sendbuf, skb_push'ed DATA_B3 header was not skb_pull'ed + * on failure, result in data block with DATA_B3 header transmitted + * + * Revision 1.15 1999/05/25 21:26:16 calle + * Include CAPI-Channelallocation (leased lines) from the 2.0 tree. + * + * Revision 1.14 1999/05/22 07:55:06 calle + * Added *V110* to AVM B1 driver. + * + * Revision 1.13 1998/06/26 15:12:55 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.12 1998/03/29 16:06:03 calle + * changes from 2.0 tree merged. + * + * Revision 1.3.2.10 1998/03/20 14:38:24 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * + * Revision 1.3.2.9 1998/03/20 09:01:12 calle + * Changes capi_register handling to get full support for 30 bchannels. + * + * Revision 1.3.2.8 1998/03/18 17:51:28 calle + * added controller number to error messages + * + * Revision 1.3.2.7 1998/02/27 15:40:47 calle + * T1 running with slow link. bugfix in capi_release. + * * Revision 1.11 1998/02/13 07:09:15 calle * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -71,15 +143,18 @@ #include #include #include +#include #include #include +#include +#include -#include "compat.h" +#include #include "capiutil.h" #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.23 $"; int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -135,6 +210,7 @@ __u16 msgid; /* to identfy CONNECT_CONF */ int chan; int state; + int leasedline; struct capidrv_ncci { struct capidrv_ncci *next; struct capidrv_plci *plcip; @@ -169,6 +245,12 @@ __u16 appid; int ncontr; struct capidrv_contr *contr_list; + + /* statistic */ + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; }; typedef struct capidrv_plci capidrv_plci; @@ -199,6 +281,10 @@ return 0; case ISDN_PROTO_L2_TRANS: return 1; + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: + return 2; } } @@ -212,6 +298,9 @@ return 0; case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: return 1; } } @@ -224,8 +313,43 @@ case ISDN_PROTO_L2_X75BUI: case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: + case ISDN_PROTO_L2_V11096: + case ISDN_PROTO_L2_V11019: + case ISDN_PROTO_L2_V11038: + default: + return 0; + } +} + +static _cstruct b1config_sync_v110(__u16 rate) +{ + /* CAPI-Spec "B1 Configuration" */ + static unsigned char buf[9]; + buf[0] = 8; /* len */ + /* maximum bitrate */ + buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff; + buf[3] = buf[4] = 0; /* reserved, bits per character */ + buf[5] = buf[6] = 0; /* reserved, parity */ + buf[7] = buf[9] = 0; /* reserved, stop bits */ + return buf; +} + +static _cstruct b1config(int l2, int l3) +{ + switch (l2) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + case ISDN_PROTO_L2_HDLC: + case ISDN_PROTO_L2_TRANS: default: return 0; + case ISDN_PROTO_L2_V11096: + return b1config_sync_v110(9600); + case ISDN_PROTO_L2_V11019: + return b1config_sync_v110(19200); + case ISDN_PROTO_L2_V11038: + return b1config_sync_v110(38400); } } @@ -378,8 +502,8 @@ return; } } - printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n", - plcip, plcip->plci); + printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n", + card->contrnr, plcip, plcip->plci); } /* -------- ncci management ------------------------------------------ */ @@ -497,9 +621,10 @@ size_t len; capi_cmsg2message(cmsg, cmsg->buf); len = CAPIMSG_LEN(cmsg->buf); - skb = dev_alloc_skb(len); + skb = alloc_skb(len, GFP_ATOMIC); memcpy(skb_put(skb, len), cmsg->buf, len); (*capifuncs->capi_put_message) (global.appid, skb); + global.nsentctlpkt++; } /* -------- state machine -------------------------------------------- */ @@ -512,15 +637,15 @@ static struct listenstatechange listentable[] = { - {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {}, + {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, + {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, + {}, }; static void listen_change_state(capidrv_contr * card, int event) @@ -529,15 +654,15 @@ while (p->event) { if (card->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n", - card->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n", + card->contrnr, card->state, p->nextstate); card->state = p->nextstate; return; } p++; } - printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n", - card->state, event); + printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n", + card->contrnr, card->state, event); } @@ -567,46 +692,57 @@ static struct plcistatechange plcitable[] = { /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, + {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0}, /* P-0.1 */ - {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, - {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, -{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0}, /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0}, /* P-3 */ -{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, -{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, -{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, -{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-5 */ -{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, /* P-6 */ - {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, - {}, + {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, + /* P-0.Res */ + {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, + {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0}, + /* P-RES */ + {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0}, + /* P-HELD */ + {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0}, + {}, }; static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event) @@ -615,8 +751,8 @@ while (p->event) { if (plci->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n", - plci->plci, plci->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n", + card->contrnr, plci->plci, plci->state, p->nextstate); plci->state = p->nextstate; if (p->changefunc) p->changefunc(card, plci); @@ -624,8 +760,8 @@ } p++; } - printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n", - plci->plci, plci->state, event); + printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n", + card->contrnr, plci->plci, plci->state, event); } /* ------------------------------------------------------------------ */ @@ -642,7 +778,7 @@ ncci->plcip->plci, 0, /* BChannelinformation */ 0, /* Keypadfacility */ - 0, /* Useruserdata */ + 0, /* Useruserdata */ /* $$$$ */ 0 /* Facilitydataarray */ ); send_message(card, &cmsg); @@ -667,34 +803,35 @@ static struct nccistatechange nccitable[] = { /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, - {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, -{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0}, /* N-5 */ - {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, - {}, + {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, + {}, }; static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event) @@ -703,8 +840,8 @@ while (p->event) { if (ncci->state == p->actstate && p->event == event) { if (debugmode) - printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n", - ncci->ncci, ncci->state, p->nextstate); + printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n", + card->contrnr, ncci->ncci, ncci->state, p->nextstate); if (p->nextstate == ST_NCCI_PREVIOUS) { ncci->state = ncci->oldstate; ncci->oldstate = p->actstate; @@ -718,8 +855,8 @@ } p++; } - printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n", - ncci->ncci, ncci->state, event); + printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n", + card->contrnr, ncci->ncci, ncci->state, event); } /* ------------------------------------------------------------------- */ @@ -752,8 +889,8 @@ case CAPI_LISTEN_CONF: /* Controller */ if (debugmode) - printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n", - cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); + printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n", + card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); if (cmsg->Info) { listen_change_state(card, EV_LISTEN_CONF_ERROR); } else if (card->cipmask == 0) { @@ -789,7 +926,8 @@ handle_dtrace_data(card, direction, 0, data, len); break; } - printk(KERN_INFO "capidrv: %s from controller 0x%x layer 0x%x, ignored\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController, layer); break; @@ -805,7 +943,8 @@ default: s = "unkown error"; break; } if (s) - printk(KERN_INFO "capidrv: %s from controller 0x%x function %d: %s\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController, cmsg->Function, s); @@ -822,14 +961,16 @@ goto ignored; default: - printk(KERN_ERR "capidrv: got %s from controller 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController); } return; ignored: - printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController); } @@ -842,12 +983,12 @@ int chan; if ((chan = new_bchan(card)) == -1) { - printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n"); + printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr); return; } bchan = &card->bchans[chan]; if ((plcip = new_plci(card, chan)) == 0) { - printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n"); + printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); return; } bchan->incoming = 1; @@ -869,7 +1010,8 @@ cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -877,6 +1019,7 @@ switch (card->interface.statcallb(&cmd)) { case 0: + case 3: /* No device matching this call. * and isdn_common.c has send a HANGUP command * which is ignored in state ST_PLCI_INCOMING, @@ -886,7 +1029,8 @@ cmsg->Reject = 1; /* ignore */ send_message(card, cmsg); plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -903,7 +1047,8 @@ * and CONNECT_RESP already sent. */ if (plcip->state == ST_PLCI_INCOMING) { - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -920,7 +1065,8 @@ plcip->msgid = cmsg->Messagenumber; send_message(card, cmsg); } else { - printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n", + printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n", + card->contrnr, cmd.parm.setup.phone, cmd.parm.setup.si1, cmd.parm.setup.si2, @@ -963,7 +1109,8 @@ case CAPI_DISCONNECT_IND: /* plci */ if (cmsg->Reason) { - printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); } @@ -981,7 +1128,8 @@ case CAPI_DISCONNECT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -994,7 +1142,8 @@ case CAPI_ALERT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -1007,7 +1156,8 @@ case CAPI_CONNECT_CONF: /* plci */ if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrPLCI); @@ -1040,7 +1190,7 @@ nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); if (!nccip) { - printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); break; /* $$$$ */ } capi_fill_CONNECT_B3_REQ(cmsg, @@ -1080,7 +1230,8 @@ break; } } - printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg)); + printk(KERN_ERR "capidrv-%d: %s\n", + card->contrnr, capi_cmsg2str(cmsg)); break; case CAPI_CONNECT_ACTIVE_CONF: /* plci */ @@ -1096,18 +1247,21 @@ goto ignored; default: - printk(KERN_ERR "capidrv: got %s for plci 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); } return; ignored: - printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); return; notfound: - printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrPLCI); return; @@ -1142,8 +1296,8 @@ cmd.arg = nccip->chan; card->interface.statcallb(&cmd); - printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n", - nccip->chan, nccip->ncci); + printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n", + card->contrnr, nccip->chan, nccip->ncci); break; case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ @@ -1167,9 +1321,10 @@ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); break; } - printk(KERN_ERR "capidrv: no mem for ncci, sorry\n"); + printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); } else { - printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } @@ -1192,7 +1347,8 @@ nccip->ncci = cmsg->adr.adrNCCI; if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); @@ -1242,7 +1398,8 @@ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) goto notfound; if (cmsg->Info) { - printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n", + printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->Info, capi_info2str(cmsg->Info), cmsg->adr.adrNCCI); @@ -1251,6 +1408,9 @@ break; case CAPI_RESET_B3_IND: /* ncci */ + if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) + goto notfound; + ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND); capi_cmsg_answer(cmsg); send_message(card, cmsg); break; @@ -1264,18 +1424,21 @@ goto ignored; default: - printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???", + printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } return; ignored: - printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n", + printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); return; notfound: - printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); } @@ -1290,10 +1453,12 @@ printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrController & 0x7f); + kfree_skb(skb); return; } if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { - printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", + printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", + card->contrnr, capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); kfree_skb(skb); @@ -1313,21 +1478,29 @@ while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) { capi_message2cmsg(&s_cmsg, skb->data); - if (debugmode > 1) - printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg)); + if (debugmode > 2) + printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n", + applid, capi_cmsg2str(&s_cmsg)); if (s_cmsg.Command == CAPI_DATA_B3 && s_cmsg.Subcommand == CAPI_IND) { handle_data(&s_cmsg, skb); + global.nrecvdatapkt++; continue; } - kfree_skb(skb); if ((s_cmsg.adr.adrController & 0xffffff00) == 0) handle_controller(&s_cmsg); else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) handle_plci(&s_cmsg); else handle_ncci(&s_cmsg); + /* + * data of skb used in s_cmsg, + * free data when s_cmsg is not used again + * thanks to Lars Heete + */ + kfree_skb(skb); + global.nrecvctlpkt++; } } @@ -1348,7 +1521,8 @@ isdn_ctrl cmd; if (!len) { - printk(KERN_DEBUG "avmb1_q931_data: len == %d\n", len); + printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", + card->contrnr, len); return; } @@ -1392,18 +1566,116 @@ static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card) { switch (c->arg) { + case 1: + debugmode = (int)(*((unsigned int *)c->parm.num)); + printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n", + card->contrnr, debugmode); + return 0; default: - printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", + card->contrnr, c->arg); return -EINVAL; } return -EINVAL; } +/* + * Handle leased lines (CAPI-Bundling) + */ + +struct internal_bchannelinfo { + unsigned short channelalloc; + unsigned short operation; + unsigned char cmask[31]; +}; + +static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) +{ + unsigned long bmask = 0; + int active = !0; + char *s; + int i; + + if (strncmp(teln, "FV:", 3) != 0) + return 1; + s = teln + 3; + while (*s && *s == ' ') s++; + if (!*s) return -2; + if (*s == 'p' || *s == 'P') { + active = 0; + s++; + } + if (*s == 'a' || *s == 'A') { + active = !0; + s++; + } + while (*s) { + int digit1 = 0; + int digit2 = 0; + if (!isdigit(*s)) return -3; + while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; } + if (digit1 <= 0 && digit1 > 30) return -4; + if (*s == 0 || *s == ',' || *s == ' ') { + bmask |= (1 << digit1); + digit1 = 0; + if (*s) s++; + continue; + } + if (*s != '-') return -5; + s++; + if (!isdigit(*s)) return -3; + while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; } + if (digit2 <= 0 && digit2 > 30) return -4; + if (*s == 0 || *s == ',' || *s == ' ') { + if (digit1 > digit2) + for (i = digit2; i <= digit1 ; i++) + bmask |= (1 << i); + else + for (i = digit1; i <= digit2 ; i++) + bmask |= (1 << i); + digit1 = digit2 = 0; + if (*s) s++; + continue; + } + return -6; + } + if (activep) *activep = active; + if (bmaskp) *bmaskp = bmask; + return 0; +} + +static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31]) +{ + unsigned long bmask; + int active; + int rc, i; + + rc = decodeFVteln(teln, &bmask, &active); + if (rc) return rc; + /* Length */ + AdditionalInfo[0] = 2+2+31; + /* Channel: 3 => use channel allocation */ + AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; + /* Operation: 0 => DTE mode, 1 => DCE mode */ + if (active) { + AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; + } else { + AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; + } + /* Channel mask array */ + AdditionalInfo[5] = 0; /* no D-Channel */ + for (i=1; i <= 30; i++) + AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0; + return 0; +} + static int capidrv_command(isdn_ctrl * c, capidrv_contr * card) { isdn_ctrl cmd; struct capidrv_bchan *bchan; struct capidrv_plci *plcip; + __u8 AdditionalInfo[1+2+2+31]; + int rc, isleasedline = 0; if (c->command == ISDN_CMD_IOCTL) return capidrv_ioctl(c, card); @@ -1414,7 +1686,8 @@ __u8 called[ISDN_MSNLEN + 2]; if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", + card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, @@ -1424,7 +1697,8 @@ bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->plcip) { - printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", + card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, @@ -1438,15 +1712,25 @@ strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); - - calling[0] = strlen(bchan->mynum) + 2; - calling[1] = 0; - calling[2] = 0x80; - strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); - - called[0] = strlen(bchan->num) + 1; - called[1] = 0x80; - strncpy(called + 2, bchan->num, ISDN_MSNLEN); + rc = FVteln2capi20(bchan->num, AdditionalInfo); + isleasedline = (rc == 0); + if (rc < 0) + printk(KERN_ERR "capidrv-%d: WARNING: illegal leased linedefinition \"%s\"\n", card->contrnr, bchan->num); + + if (isleasedline) { + calling[0] = 0; + called[0] = 0; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); + } else { + calling[0] = strlen(bchan->mynum) + 2; + calling[1] = 0; + calling[2] = 0x80; + strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); + called[0] = strlen(bchan->num) + 1; + called[1] = 0x80; + strncpy(called + 2, bchan->num, ISDN_MSNLEN); + } capi_fill_CONNECT_REQ(&cmdcmsg, global.appid, @@ -1460,13 +1744,14 @@ b1prot(bchan->l2, bchan->l3), /* B1protocol */ b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ - 0, /* B1configuration */ + b1config(bchan->l2, bchan->l3), /* B1configuration */ 0, /* B2configuration */ 0, /* B3configuration */ 0, /* BC */ 0, /* LLC */ 0, /* HLC */ - 0, /* BChannelinformation */ + /* BChannelinformation */ + isleasedline ? AdditionalInfo : 0, 0, /* Keypadfacility */ 0, /* Useruserdata */ 0 /* Facilitydataarray */ @@ -1479,6 +1764,7 @@ return -1; } plcip->msgid = cmdcmsg.Messagenumber; + plcip->leasedline = isleasedline; plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); send_message(card, &cmdcmsg); return 0; @@ -1486,10 +1772,11 @@ case ISDN_CMD_ACCEPTD: - if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n", - c->arg); bchan = &card->bchans[c->arg % card->nbchan]; + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n", + card->contrnr, + c->arg, bchan->l2, bchan->l3); capi_fill_CONNECT_RESP(&cmdcmsg, global.appid, @@ -1499,7 +1786,7 @@ b1prot(bchan->l2, bchan->l3), /* B1protocol */ b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ - 0, /* B1configuration */ + b1config(bchan->l2, bchan->l3), /* B1configuration */ 0, /* B2configuration */ 0, /* B3configuration */ 0, /* ConnectedNumber */ @@ -1517,19 +1804,22 @@ case ISDN_CMD_ACCEPTB: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", + card->contrnr, c->arg); return -ENOSYS; case ISDN_CMD_HANGUP: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n", + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", + card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->disconnecting) { if (debugmode) - printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n", + printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", + card->contrnr, c->arg); return 0; } @@ -1568,23 +1858,26 @@ case ISDN_CMD_SETL2: if (debugmode) - printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n", + printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", + card->contrnr, (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[c->arg % card->nbchan]; + bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l2 = (c->arg >> 8); return 0; case ISDN_CMD_SETL3: if (debugmode) - printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n", + printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", + card->contrnr, (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[c->arg % card->nbchan]; + bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l3 = (c->arg >> 8); return 0; case ISDN_CMD_SETEAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n", + printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", + card->contrnr, c->parm.num, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); @@ -1592,46 +1885,54 @@ case ISDN_CMD_CLREAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", + card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; bchan->msn[0] = 0; return 0; case ISDN_CMD_LOCK: if (debugmode > 1) - printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg); MOD_INC_USE_COUNT; break; case ISDN_CMD_UNLOCK: if (debugmode > 1) - printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n", + card->contrnr, c->arg); MOD_DEC_USE_COUNT; break; /* never called */ case ISDN_CMD_GETL2: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETL3: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETEAZ: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n", + card->contrnr); return -ENODEV; case ISDN_CMD_SETSIL: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n", + card->contrnr); return -ENODEV; case ISDN_CMD_GETSIL: if (debugmode) - printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n"); + printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n", + card->contrnr); return -ENODEV; default: - printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command); + printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", + card->contrnr, c->command); return -EINVAL; } return 0; @@ -1645,8 +1946,8 @@ return capidrv_command(c, card); printk(KERN_ERR - "capidrv: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); + "capidrv-%d: if_command %d called with invalid driverId %d!\n", + card->contrnr, c->command, c->driver); return -ENODEV; } @@ -1663,15 +1964,18 @@ __u16 datahandle; if (!card) { - printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", - id); + printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n", + card->contrnr, id); return 0; } + if (debugmode > 1) + printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", + card->contrnr, len, skb, doack); bchan = &card->bchans[channel % card->nbchan]; nccip = bchan->nccip; if (!nccip || nccip->state != ST_NCCI_ACTIVE) { - printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n", - card->name, channel); + printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", + card->contrnr, card->name, channel); return 0; } datahandle = nccip->datahandle; @@ -1689,22 +1993,23 @@ capi_cmsg2message(&sendcmsg, sendcmsg.buf); msglen = CAPIMSG_LEN(sendcmsg.buf); if (skb_headroom(skb) < msglen) { - struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len); + struct sk_buff *nskb = skb_realloc_headroom(skb, msglen); if (!nskb) { - printk(KERN_ERR "capidrv: if_sendbuf: no memory\n"); + printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", + card->contrnr); (void)capidrv_del_ack(nccip, datahandle); return 0; } -#if 0 - printk(KERN_DEBUG "capidrv: only %d bytes headroom\n", - skb_headroom(skb)); +#if 1 + printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n", + card->contrnr, skb_headroom(skb), msglen); #endif - memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen); - memcpy(skb_put(nskb, skb->len), skb->data, skb->len); + memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen); errcode = (*capifuncs->capi_put_message) (global.appid, nskb); if (errcode == CAPI_NOERROR) { dev_kfree_skb(skb); nccip->datahandle++; + global.nsentdatapkt++; return len; } (void)capidrv_del_ack(nccip, datahandle); @@ -1715,8 +2020,10 @@ errcode = (*capifuncs->capi_put_message) (global.appid, skb); if (errcode == CAPI_NOERROR) { nccip->datahandle++; + global.nsentdatapkt++; return len; } + skb_pull(skb, msglen); (void)capidrv_del_ack(nccip, datahandle); return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; } @@ -1729,8 +2036,8 @@ __u8 *p; if (!card) { - printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", - id); + printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n", + card->contrnr, id); return -ENODEV; } @@ -1761,8 +2068,8 @@ return; } if (strstr(manufacturer, "AVM") == 0) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible\n", - card->name); + printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", + card->name, manufacturer); return; } errcode = (*capifuncs->capi_get_version)(contr, &version); @@ -1776,7 +2083,7 @@ avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; avmversion[2] |= version.minormanuversion & 0x0f; - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { + if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 6)) { printk(KERN_INFO "%s: D2 trace enabled\n", card->name); capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, card->msgid++, @@ -1798,6 +2105,51 @@ send_message(card, &cmdcmsg); } +static void disable_dchannel_trace(capidrv_contr *card) +{ + __u8 manufacturer[CAPI_MANUFACTURER_LEN]; + capi_version version; + __u16 contr = card->contrnr; + __u16 errcode; + __u16 avmversion[3]; + + errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", + card->name, errcode); + return; + } + if (strstr(manufacturer, "AVM") == 0) { + printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", + card->name, manufacturer); + return; + } + errcode = (*capifuncs->capi_get_version)(contr, &version); + if (errcode != CAPI_NOERROR) { + printk(KERN_ERR "%s: can't get version (0x%x)\n", + card->name, errcode); + return; + } + avmversion[0] = (version.majormanuversion >> 4) & 0x0f; + avmversion[1] = (version.majormanuversion << 4) & 0xf0; + avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; + avmversion[2] |= version.minormanuversion & 0x0f; + + if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 6)) { + printk(KERN_INFO "%s: D2 trace disabled\n", card->name); + } else { + printk(KERN_INFO "%s: D3 trace disabled\n", card->name); + } + capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid, + card->msgid++, + contr, + 0x214D5641, /* ManuID */ + 0, /* Class */ + 1, /* Function */ + (_cstruct)"\004\000\000\000\000"); + send_message(card, &cmdcmsg); +} + static int capidrv_addcontr(__u16 contr, struct capi_profile *profp) { capidrv_contr *card; @@ -1834,6 +2186,9 @@ ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | ISDN_FEATURE_P_UNKNOWN; card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); @@ -1878,7 +2233,7 @@ printk(KERN_INFO "%s: now up (%d B channels)\n", card->name, card->nbchan); - enable_dchannel_trace(card); + enable_dchannel_trace(card); return 0; } @@ -1898,6 +2253,15 @@ return -1; } card = *pp; + + if (debugmode) + printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", + card->contrnr, card->myid); + + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + *pp = (*pp)->next; global.ncontr--; @@ -1911,10 +2275,6 @@ } kfree(card->bchans); - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - printk(KERN_INFO "%s: now down.\n", card->name); kfree(card); @@ -1925,16 +2285,77 @@ static void lower_callback(unsigned int cmd, __u16 contr, void *data) { + switch (cmd) { case KCI_CONTRUP: + printk(KERN_INFO "capidrv: controller %hu up\n", contr); (void) capidrv_addcontr(contr, (capi_profile *) data); break; case KCI_CONTRDOWN: + printk(KERN_INFO "capidrv: controller %hu down\n", contr); (void) capidrv_delcontr(contr); break; } } +/* + * /proc/capi/capidrv: + * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt + */ +static int proc_capidrv_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(page+len, "%lu %lu %lu %lu\n", + global.nrecvctlpkt, + global.nrecvdatapkt, + global.nsentctlpkt, + global.nsentdatapkt); + if (len < off) + return 0; + *eof = 1; + *start = page -off; + return ((count < len-off) ? count : len-off); +} + +static struct procfsentries { + char *name; + mode_t mode; + int (*read_proc)(char *page, char **start, off_t off, + int count, int *eof, void *data); + struct proc_dir_entry *procent; +} procfsentries[] = { + /* { "capi", S_IFDIR, 0 }, */ + { "capi/capidrv", 0 , proc_capidrv_read_proc }, +}; + +static void proc_init(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=0; i < nelem; i++) { + struct procfsentries *p = procfsentries + i; + p->procent = create_proc_entry(p->name, p->mode, 0); + if (p->procent) p->procent->read_proc = p->read_proc; + } +} + +static void proc_exit(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=nelem-1; i >= 0; i--) { + struct procfsentries *p = procfsentries + i; + if (p->procent) { + remove_proc_entry(p->name, 0); + p->procent = 0; + } + } +} + static struct capi_interface_user cuser = { "capidrv", lower_callback @@ -1965,8 +2386,8 @@ } else strcpy(rev, " ??? "); - rparam.level3cnt = 2; - rparam.datablkcnt = 8; + rparam.level3cnt = -2; /* number of bchannels twice */ + rparam.datablkcnt = 16; rparam.datablklen = 2048; errcode = (*capifuncs->capi_register) (&rparam, &global.appid); if (errcode) { @@ -1990,6 +2411,7 @@ continue; (void) capidrv_addcontr(contr, &profile); } + proc_init(); return 0; } @@ -2011,11 +2433,13 @@ for (card = global.contr_list; card; card = next) { next = card->next; + disable_dchannel_trace(card); capidrv_delcontr(card->contrnr); } (void) (*capifuncs->capi_release) (global.appid); detach_capi_interface(&cuser); + proc_exit(); printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capidrv.h linux/drivers/isdn/avmb1/capidrv.h --- v2.2.10/linux/drivers/isdn/avmb1/capidrv.h Thu May 29 21:53:05 1997 +++ linux/drivers/isdn/avmb1/capidrv.h Mon Aug 9 12:04:39 1999 @@ -1,11 +1,22 @@ /* - * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $ + * $Id: capidrv.h,v 1.2 1998/03/29 16:06:06 calle Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.h,v $ + * Revision 1.2 1998/03/29 16:06:06 calle + * changes from 2.0 tree merged. + * + * Revision 1.1.2.1 1998/03/20 14:38:28 calle + * capidrv: prepared state machines for suspend/resume/hold + * capidrv: fix bug in state machine if B1/T1 is out of nccis + * b1capi: changed some errno returns. + * b1capi: detect if you try to add same T1 to different io address. + * b1capi: change number of nccis depending on number of channels. + * b1lli: cosmetics + * * Revision 1.1 1997/03/04 21:50:33 calle * Frirst version in isdn4linux * @@ -49,34 +60,70 @@ #define ST_PLCI_ACCEPTING 6 /* P-4 */ #define ST_PLCI_DISCONNECTING 7 /* P-5 */ #define ST_PLCI_DISCONNECTED 8 /* P-6 */ +#define ST_PLCI_RESUMEING 9 /* P-0.Res */ +#define ST_PLCI_RESUME 10 /* P-Res */ +#define ST_PLCI_HELD 11 /* P-HELD */ -#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 */ -#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 */ -#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 */ -#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 */ -#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 */ -#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT */ +#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 + */ +#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 + */ +#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 + */ +#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 + */ +#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 + */ +#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT + */ #define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 - P-3 -> P-5 */ + P-3 -> P-5 + */ #define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 P-2 -> P-5 P-3 -> P-5 P-4 -> P-5 - P-ACT -> P-5 */ + P-ACT -> P-5 + P-Res -> P-5 (*) + P-HELD -> P-5 (*) + */ #define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 P-2 -> P-6 P-3 -> P-6 P-4 -> P-6 P-5 -> P-6 - P-ACT -> P-6 */ + P-ACT -> P-6 + P-Res -> P-6 (*) + P-HELD -> P-6 (*) + */ #define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 P-1 -> P-5 P-ACT -> P-5 P-2 -> P-5 P-3 -> P-5 - P-4 -> P-5 */ -#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 */ -#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 */ + P-4 -> P-5 + */ +#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 + */ +#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 + */ + +#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res + */ +#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res + */ +#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 + */ +#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT + */ +#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD + */ +#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT + */ +#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 + */ +#define EV_PLCI_CD_IND 20 /* P-2 -> P-5 + */ /* * per ncci state machine diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capilli.h linux/drivers/isdn/avmb1/capilli.h --- v2.2.10/linux/drivers/isdn/avmb1/capilli.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/capilli.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,109 @@ +/* + * $Id: capilli.h,v 1.2 1999/07/05 15:09:52 calle Exp $ + * + * Kernel CAPI 2.0 Driver Interface for Linux + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + */ +#ifndef __CAPILLI_H__ +#define __CAPILLI_H__ + +typedef struct capiloaddatapart { + int user; /* data in userspace ? */ + int len; + unsigned char *data; +} capiloaddatapart; + +typedef struct capiloaddata { + capiloaddatapart firmware; + capiloaddatapart configuration; +} capiloaddata; + +typedef struct capicardparams { + unsigned int port; + unsigned irq; + int cardtype; + int cardnr; +} capicardparams; + +struct capi_driver; + +struct capi_ctr { + struct capi_ctr *next; /* next ctr of same driver */ + struct capi_driver *driver; + int cnr; /* controller number */ + char name[32]; /* name of controller */ + volatile unsigned short cardstate; /* controller state */ + volatile int blocked; /* output blocked */ + int traceflag; /* capi trace */ + + void *driverdata; /* driver specific */ + + /* filled before calling ready callback */ + __u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */ + capi_version version; /* CAPI_GET_VERSION */ + capi_profile profile; /* CAPI_GET_PROFILE */ + __u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */ + + /* functions */ + void (*ready)(struct capi_ctr * card); + void (*reseted)(struct capi_ctr * card); + void (*suspend_output)(struct capi_ctr * card); + void (*resume_output)(struct capi_ctr * card); + void (*handle_capimsg)(struct capi_ctr * card, + __u16 appl, struct sk_buff *skb); + void (*appl_registered)(struct capi_ctr * card, __u16 appl); + void (*appl_released)(struct capi_ctr * card, __u16 appl); + + void (*new_ncci)(struct capi_ctr * card, + __u16 appl, __u32 ncci, __u32 winsize); + void (*free_ncci)(struct capi_ctr * card, __u16 appl, __u32 ncci); + + /* management information for kcapi */ + + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; + + struct proc_dir_entry *procent; + char procfn[128]; +}; + +struct capi_driver_interface { + struct capi_ctr *(*attach_ctr)(struct capi_driver *driver, char *name, void *data); + int (*detach_ctr)(struct capi_ctr *); +}; + +struct capi_driver { + char name[32]; /* driver name */ + char revision[32]; + int (*load_firmware)(struct capi_ctr *, capiloaddata *); + void (*reset_ctr)(struct capi_ctr *); + void (*remove_ctr)(struct capi_ctr *); + void (*register_appl)(struct capi_ctr *, __u16 appl, + capi_register_params *); + void (*release_appl)(struct capi_ctr *, __u16 appl); + void (*send_message)(struct capi_ctr *, struct sk_buff *skb); + + char *(*procinfo)(struct capi_ctr *); + int (*ctr_read_proc)(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *card); + int (*driver_read_proc)(char *page, char **start, off_t off, + int count, int *eof, struct capi_driver *driver); + + int (*add_card)(struct capi_driver *driver, capicardparams *data); + + /* intitialized by kcapi */ + struct capi_ctr *controller; /* list of controllers */ + struct capi_driver *next; + int ncontroller; + struct proc_dir_entry *procent; + char procfn[128]; +}; + +struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver); +void detach_capi_driver(struct capi_driver *driver); + +#endif /* __CAPILLI_H__ */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.2.10/linux/drivers/isdn/avmb1/capiutil.c Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/avmb1/capiutil.c Mon Aug 9 12:04:39 1999 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.c,v 1.6 1997/11/04 06:12:12 calle Exp $ + * $Id: capiutil.c,v 1.9 1999/07/09 15:05:46 keil Exp $ * * CAPI 2.0 convert capi message to capi message struct * @@ -7,6 +7,28 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.c,v $ + * Revision 1.9 1999/07/09 15:05:46 keil + * compat.h is now isdn_compat.h + * + * Revision 1.8 1999/07/01 15:26:37 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * Revision 1.7 1999/07/01 08:23:01 keil + * compatibility macros now in + * * Revision 1.6 1997/11/04 06:12:12 calle * capi.c: new read/write in file_ops since 2.1.60 * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. @@ -48,7 +70,7 @@ #include #include -#include "compat.h" +#include #include "capiutil.h" /* from CAPI2.0 DDK AVM Berlin GmbH */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/compat.h linux/drivers/isdn/avmb1/compat.h --- v2.2.10/linux/drivers/isdn/avmb1/compat.h Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/avmb1/compat.h Wed Dec 31 16:00:00 1969 @@ -1,41 +0,0 @@ -/* - * $Id: compat.h,v 1.3 1997/11/04 06:12:15 calle Exp $ - * - * Headerfile for Compartibility between different kernel versions - * - * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) - * - * $Log: compat.h,v $ - * Revision 1.3 1997/11/04 06:12:15 calle - * capi.c: new read/write in file_ops since 2.1.60 - * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware. - * capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON) - * compat.h: added #define LinuxVersionCode - * - * Revision 1.2 1997/10/01 09:21:22 fritz - * Removed old compatibility stuff for 2.0.X kernels. - * From now on, this code is for 2.1.X ONLY! - * Old stuff is still in the separate branch. - * - * Revision 1.1 1997/03/04 21:50:36 calle - * Frirst version in isdn4linux - * - * Revision 2.2 1997/02/12 09:31:39 calle - * new version - * - * Revision 1.1 1997/01/31 10:32:20 calle - * Initial revision - * - * - */ -#ifndef __COMPAT_H__ -#define __COMPAT_H__ - -#include -#include - -#ifndef LinuxVersionCode -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#endif - -#endif /* __COMPAT_H__ */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.2.10/linux/drivers/isdn/avmb1/kcapi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/kcapi.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1522 @@ +/* + * $Id: kcapi.c,v 1.5 1999/07/09 15:05:48 keil Exp $ + * + * Kernel CAPI 2.0 Module + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: kcapi.c,v $ + * Revision 1.5 1999/07/09 15:05:48 keil + * compat.h is now isdn_compat.h + * + * Revision 1.4 1999/07/08 14:15:17 calle + * Forgot to count down ncards in drivercb_detach_ctr. + * + * Revision 1.3 1999/07/06 07:42:02 calle + * - changes in /proc interface + * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. + * + * Revision 1.2 1999/07/05 15:09:52 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:42 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + */ +#define CONFIG_AVMB1_COMPAT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#ifdef CONFIG_AVMB1_COMPAT +#include +#endif + +static char *revision = "$Revision: 1.5 $"; + +/* ------------------------------------------------------------- */ + +#define CARD_FREE 0 +#define CARD_DETECTED 1 +#define CARD_LOADING 2 +#define CARD_RUNNING 3 + +/* ------------------------------------------------------------- */ + +int showcapimsgs = 0; + +MODULE_AUTHOR("Carsten Paeth "); +MODULE_PARM(showcapimsgs, "0-4i"); + +/* ------------------------------------------------------------- */ + +struct msgidqueue { + struct msgidqueue *next; + __u16 msgid; +}; + +struct capi_ncci { + struct capi_ncci *next; + __u16 applid; + __u32 ncci; + __u32 winsize; + int nmsg; + struct msgidqueue *msgidqueue; + struct msgidqueue *msgidlast; + struct msgidqueue *msgidfree; + struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW]; +}; + +struct capi_appl { + __u16 applid; + capi_register_params rparam; + int releasing; + __u32 param; + void (*signal) (__u16 applid, __u32 param); + struct sk_buff_head recv_queue; + int nncci; + struct capi_ncci *nccilist; + + unsigned long nrecvctlpkt; + unsigned long nrecvdatapkt; + unsigned long nsentctlpkt; + unsigned long nsentdatapkt; +}; + +/* ------------------------------------------------------------- */ + +static struct capi_version driver_version = {2, 0, 1, 1<<4}; +static char driver_serial[CAPI_SERIAL_LEN] = "4711"; +static char capi_manufakturer[64] = "AVM Berlin"; + +#define APPL(a) (&applications[(a)-1]) +#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a) +#define APPL_IS_FREE(a) (APPL(a)->applid == 0) +#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0); +#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0); + +#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f) + +#define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR) +#define CARD(c) (&cards[(c)-1]) +#define CARDNR(cp) (((cp)-cards)+1) + +static struct capi_appl applications[CAPI_MAXAPPL]; +static struct capi_ctr cards[CAPI_MAXCONTR]; +static int ncards = 0; +static struct sk_buff_head recv_queue; +static struct capi_interface_user *capi_users = 0; +static struct capi_driver *drivers; +#ifdef CONFIG_AVMB1_COMPAT +static struct capi_driver *b1isa_driver; +static struct capi_driver *t1isa_driver; +#endif +static long notify_up_set = 0; +static long notify_down_set = 0; + +static struct tq_struct tq_state_notify; +static struct tq_struct tq_recv_notify; + +/* -------- util functions ------------------------------------ */ + +static char *cardstate2str(unsigned short cardstate) +{ + switch (cardstate) { + default: + case CARD_FREE: return "free"; + case CARD_DETECTED: return "detected"; + case CARD_LOADING: return "loading"; + case CARD_RUNNING: return "running"; + } +} + +static inline int capi_cmd_valid(__u8 cmd) +{ + switch (cmd) { + case CAPI_ALERT: + case CAPI_CONNECT: + case CAPI_CONNECT_ACTIVE: + case CAPI_CONNECT_B3_ACTIVE: + case CAPI_CONNECT_B3: + case CAPI_CONNECT_B3_T90_ACTIVE: + case CAPI_DATA_B3: + case CAPI_DISCONNECT_B3: + case CAPI_DISCONNECT: + case CAPI_FACILITY: + case CAPI_INFO: + case CAPI_LISTEN: + case CAPI_MANUFACTURER: + case CAPI_RESET_B3: + case CAPI_SELECT_B_PROTOCOL: + return 1; + } + return 0; +} + +static inline int capi_subcmd_valid(__u8 subcmd) +{ + switch (subcmd) { + case CAPI_REQ: + case CAPI_CONF: + case CAPI_IND: + case CAPI_RESP: + return 1; + } + return 0; +} + +/* -------- /proc functions ----------------------------------- */ +/* + * /proc/capi/applications: + * applid l3cnt dblkcnt dblklen #ncci recvqueuelen + */ +static int proc_applications_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_appl *ap; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXAPPL; i++) { + ap = &applications[i]; + if (ap->applid == 0) continue; + len += sprintf(page+len, "%u %d %d %d %d %d\n", + ap->applid, + ap->rparam.level3cnt, + ap->rparam.datablkcnt, + ap->rparam.datablklen, + ap->nncci, + skb_queue_len(&ap->recv_queue)); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (i >= CAPI_MAXAPPL) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/ncci: + * applid ncci winsize nblk + */ +static int proc_ncci_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_appl *ap; + struct capi_ncci *np; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXAPPL; i++) { + ap = &applications[i]; + if (ap->applid == 0) continue; + for (np = ap->nccilist; np; np = np->next) { + len += sprintf(page+len, "%d 0x%x %d %d\n", + np->applid, + np->ncci, + np->winsize, + np->nmsg); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } + } +endloop: + if (i >= CAPI_MAXAPPL) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/driver: + * driver ncontroller + */ +static int proc_driver_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_driver *driver; + int len = 0; + off_t begin = 0; + + for (driver = drivers; driver; driver = driver->next) { + len += sprintf(page+len, "%-32s %d %s\n", + driver->name, + driver->ncontroller, + driver->revision); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (!driver) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/users: + * name + */ +static int proc_users_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_interface_user *cp; + int len = 0; + off_t begin = 0; + + for (cp = capi_users; cp ; cp = cp->next) { + len += sprintf(page+len, "%s\n", cp->name); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (cp == 0) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/controller: + * cnr driver cardstate name driverinfo + */ +static int proc_controller_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_ctr *cp; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXCONTR; i++) { + cp = &cards[i]; + if (cp->cardstate == CARD_FREE) continue; + len += sprintf(page+len, "%d %-10s %-8s %-16s %s\n", + cp->cnr, cp->driver->name, + cardstate2str(cp->cardstate), + cp->name, + cp->driver->procinfo ? cp->driver->procinfo(cp) : "" + ); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (i >= CAPI_MAXCONTR) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/applstats: + * applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt + */ +static int proc_applstats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_appl *ap; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXAPPL; i++) { + ap = &applications[i]; + if (ap->applid == 0) continue; + len += sprintf(page+len, "%u %lu %lu %lu %lu\n", + ap->applid, + ap->nrecvctlpkt, + ap->nrecvdatapkt, + ap->nsentctlpkt, + ap->nsentdatapkt); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (i >= CAPI_MAXAPPL) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * /proc/capi/contrstats: + * cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt + */ +static int proc_contrstats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_ctr *cp; + int i; + int len = 0; + off_t begin = 0; + + for (i=0; i < CAPI_MAXCONTR; i++) { + cp = &cards[i]; + if (cp->cardstate == CARD_FREE) continue; + len += sprintf(page+len, "%d %lu %lu %lu %lu\n", + cp->cnr, + cp->nrecvctlpkt, + cp->nrecvdatapkt, + cp->nsentctlpkt, + cp->nsentdatapkt); + if (len+begin > off+count) + goto endloop; + if (len+begin < off) { + begin += len; + len = 0; + } + } +endloop: + if (i >= CAPI_MAXCONTR) + *eof = 1; + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +static struct procfsentries { + char *name; + mode_t mode; + int (*read_proc)(char *page, char **start, off_t off, + int count, int *eof, void *data); + struct proc_dir_entry *procent; +} procfsentries[] = { + { "capi", S_IFDIR, 0 }, + { "capi/applications", 0 , proc_applications_read_proc }, + { "capi/ncci", 0 , proc_ncci_read_proc }, + { "capi/driver", 0 , proc_driver_read_proc }, + { "capi/users", 0 , proc_users_read_proc }, + { "capi/controller", 0 , proc_controller_read_proc }, + { "capi/applstats", 0 , proc_applstats_read_proc }, + { "capi/contrstats", 0 , proc_contrstats_read_proc }, + { "capi/drivers", S_IFDIR, 0 }, + { "capi/controllers", S_IFDIR, 0 }, +}; + +static void proc_capi_init(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=0; i < nelem; i++) { + struct procfsentries *p = procfsentries + i; + p->procent = create_proc_entry(p->name, p->mode, 0); + if (p->procent) p->procent->read_proc = p->read_proc; + } +} + +static void proc_capi_exit(void) +{ + int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); + int i; + + for (i=nelem-1; i >= 0; i--) { + struct procfsentries *p = procfsentries + i; + if (p->procent) { + remove_proc_entry(p->name, 0); + p->procent = 0; + } + } +} + +/* -------- NCCI Handling ------------------------------------- */ + +static inline void mq_init(struct capi_ncci * np) +{ + int i; + np->msgidqueue = 0; + np->msgidlast = 0; + np->nmsg = 0; + memset(np->msgidpool, 0, sizeof(np->msgidpool)); + np->msgidfree = &np->msgidpool[0]; + for (i = 1; i < np->winsize; i++) { + np->msgidpool[i].next = np->msgidfree; + np->msgidfree = &np->msgidpool[i]; + } +} + +static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid) +{ + struct msgidqueue *mq; + if ((mq = np->msgidfree) == 0) + return 0; + np->msgidfree = mq->next; + mq->msgid = msgid; + mq->next = 0; + if (np->msgidlast) + np->msgidlast->next = mq; + np->msgidlast = mq; + if (!np->msgidqueue) + np->msgidqueue = mq; + np->nmsg++; + return 1; +} + +static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid) +{ + struct msgidqueue **pp; + for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) { + if ((*pp)->msgid == msgid) { + struct msgidqueue *mq = *pp; + *pp = mq->next; + if (mq == np->msgidlast) + np->msgidlast = 0; + mq->next = np->msgidfree; + np->msgidfree = mq; + np->nmsg--; + return 1; + } + } + return 0; +} + +static void controllercb_appl_registered(struct capi_ctr * card, __u16 appl) +{ +} + +static void controllercb_appl_released(struct capi_ctr * card, __u16 appl) +{ + struct capi_ncci **pp, **nextpp; + for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { + if (NCCI2CTRL((*pp)->ncci) == card->cnr) { + struct capi_ncci *np = *pp; + *pp = np->next; + printk(KERN_INFO "kcapi: appl %d ncci 0x%x down!\n", appl, np->ncci); + kfree(np); + APPL(appl)->nncci--; + nextpp = pp; + } else { + nextpp = &(*pp)->next; + } + } + APPL(appl)->releasing--; + if (APPL(appl)->releasing <= 0) { + APPL(appl)->signal = 0; + APPL_MARK_FREE(appl); + printk(KERN_INFO "kcapi: appl %d down\n", appl); + } +} +/* + * ncci managment + */ + +static void controllercb_new_ncci(struct capi_ctr * card, + __u16 appl, __u32 ncci, __u32 winsize) +{ + struct capi_ncci *np; + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl); + return; + } + if ((np = (struct capi_ncci *) kmalloc(sizeof(struct capi_ncci), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "capi_new_ncci: alloc failed ncci 0x%x\n", ncci); + return; + } + if (winsize > CAPI_MAXDATAWINDOW) { + printk(KERN_ERR "capi_new_ncci: winsize %d too big, set to %d\n", + winsize, CAPI_MAXDATAWINDOW); + winsize = CAPI_MAXDATAWINDOW; + } + np->applid = appl; + np->ncci = ncci; + np->winsize = winsize; + mq_init(np); + np->next = APPL(appl)->nccilist; + APPL(appl)->nccilist = np; + APPL(appl)->nncci++; + printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci); + +} + +static void controllercb_free_ncci(struct capi_ctr * card, + __u16 appl, __u32 ncci) +{ + struct capi_ncci **pp; + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "free_ncci: illegal appl %d\n", appl); + return; + } + for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) { + if ((*pp)->ncci == ncci) { + struct capi_ncci *np = *pp; + *pp = np->next; + kfree(np); + APPL(appl)->nncci--; + printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci); + return; + } + } + printk(KERN_ERR "free_ncci: ncci 0x%x not found\n", ncci); +} + + +static struct capi_ncci *find_ncci(struct capi_appl * app, __u32 ncci) +{ + struct capi_ncci *np; + for (np = app->nccilist; np; np = np->next) { + if (np->ncci == ncci) + return np; + } + return 0; +} + +/* -------- Receiver ------------------------------------------ */ + +static void recv_handler(void *dummy) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&recv_queue)) != 0) { + __u16 appl = CAPIMSG_APPID(skb->data); + struct capi_ncci *np; + if (!VALID_APPLID(appl)) { + printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n", + appl, capi_message2str(skb->data)); + kfree_skb(skb); + continue; + } + if (APPL(appl)->signal == 0) { + printk(KERN_ERR "kcapi: recv_handler: applid %d has no signal function\n", + appl); + kfree_skb(skb); + continue; + } + if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF + && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0 + && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) { + printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n", + CAPIMSG_MSGID(skb->data), np->ncci); + } + if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 + && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { + APPL(appl)->nrecvdatapkt++; + } else { + APPL(appl)->nrecvctlpkt++; + } + skb_queue_tail(&APPL(appl)->recv_queue, skb); + (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param); + } +} + +static void controllercb_handle_capimsg(struct capi_ctr * card, + __u16 appl, struct sk_buff *skb) +{ + int showctl = 0; + __u8 cmd, subcmd; + + if (card->cardstate != CARD_RUNNING) { + printk(KERN_INFO "kcapi: controller %d not active, got: %s", + card->cnr, capi_message2str(skb->data)); + goto error; + } + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + if (cmd == CAPI_DATA_B3 && subcmd == CAPI_IND) { + card->nrecvdatapkt++; + if (card->traceflag > 2) showctl |= 2; + if (card->traceflag) showctl |= 2; + } else { + card->nrecvctlpkt++; + } + showctl |= (card->traceflag & 1); + if (showctl & 2) { + if (showctl & 1) { + printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n", + (unsigned long) card->cnr, + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); + } else { + printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n", + (unsigned long) card->cnr, + capi_message2str(skb->data)); + } + + } + skb_queue_tail(&recv_queue, skb); + queue_task(&tq_recv_notify, &tq_immediate); + mark_bh(IMMEDIATE_BH); + return; + +error: + kfree_skb(skb); +} + +/* -------- Notifier ------------------------------------------ */ + +static void notify_up(__u16 contr) +{ + struct capi_interface_user *p; + + printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile); + } +} + +static void notify_down(__u16 contr) +{ + struct capi_interface_user *p; + printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr); + for (p = capi_users; p; p = p->next) { + if (!p->callback) continue; + (*p->callback) (KCI_CONTRDOWN, contr, 0); + } +} + +static void notify_handler(void *dummy) +{ + __u16 contr; + + for (contr=1; VALID_CARD(contr); contr++) + if (test_and_clear_bit(contr, ¬ify_up_set)) + notify_up(contr); + for (contr=1; VALID_CARD(contr); contr++) + if (test_and_clear_bit(contr, ¬ify_down_set)) + notify_down(contr); +} + + +static void controllercb_ready(struct capi_ctr * card) +{ + __u16 appl; + + card->cardstate = CARD_RUNNING; + + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + if (!VALID_APPLID(appl)) continue; + if (APPL(appl)->releasing) continue; + card->driver->register_appl(card, appl, &APPL(appl)->rparam); + } + + set_bit(CARDNR(card), ¬ify_up_set); + queue_task(&tq_state_notify, &tq_scheduler); + + printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", + CARDNR(card), card->name); +} + +static void controllercb_reseted(struct capi_ctr * card) +{ + __u16 appl; + + if (card->cardstate == CARD_FREE) + return; + if (card->cardstate == CARD_DETECTED) + return; + + card->cardstate = CARD_DETECTED; + + memset(card->manu, 0, sizeof(card->manu)); + memset(&card->version, 0, sizeof(card->version)); + memset(&card->profile, 0, sizeof(card->profile)); + memset(card->serial, 0, sizeof(card->serial)); + + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + struct capi_ncci **pp, **nextpp; + for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) { + if (NCCI2CTRL((*pp)->ncci) == card->cnr) { + struct capi_ncci *np = *pp; + *pp = np->next; + printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci); + kfree(np); + nextpp = pp; + } else { + nextpp = &(*pp)->next; + } + } + } + set_bit(CARDNR(card), ¬ify_down_set); + queue_task(&tq_state_notify, &tq_scheduler); + printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card)); +} + +static void controllercb_suspend_output(struct capi_ctr *card) +{ + if (!card->blocked) { + printk(KERN_DEBUG "kcapi: card %d suspend\n", CARDNR(card)); + card->blocked = 1; + } +} + +static void controllercb_resume_output(struct capi_ctr *card) +{ + if (card->blocked) { + printk(KERN_DEBUG "kcapi: card %d resume\n", CARDNR(card)); + card->blocked = 0; + } +} + +/* ------------------------------------------------------------- */ + + +struct capi_ctr * +drivercb_attach_ctr(struct capi_driver *driver, char *name, void *driverdata) +{ + struct capi_ctr *card, **pp; + int i; + + for (i=0; i < CAPI_MAXCONTR && cards[i].cardstate != CARD_FREE; i++) ; + + if (i == CAPI_MAXCONTR) { + printk(KERN_ERR "kcapi: out of controller slots\n"); + return 0; + } + card = &cards[i]; + memset(card, 0, sizeof(struct capi_ctr)); + card->driver = driver; + card->cnr = CARDNR(card); + strncpy(card->name, name, sizeof(card->name)); + card->cardstate = CARD_DETECTED; + card->blocked = 0; + card->driverdata = driverdata; + card->traceflag = showcapimsgs; + + card->ready = controllercb_ready; + card->reseted = controllercb_reseted; + card->suspend_output = controllercb_suspend_output; + card->resume_output = controllercb_resume_output; + card->handle_capimsg = controllercb_handle_capimsg; + card->appl_registered = controllercb_appl_registered; + card->appl_released = controllercb_appl_released; + card->new_ncci = controllercb_new_ncci; + card->free_ncci = controllercb_free_ncci; + + for (pp = &driver->controller; *pp; pp = &(*pp)->next) ; + card->next = 0; + *pp = card; + driver->ncontroller++; + sprintf(card->procfn, "capi/controllers/%d", card->cnr); + card->procent = create_proc_entry(card->procfn, 0, 0); + if (card->procent) { + card->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->ctr_read_proc; + card->procent->data = card; + } + + ncards++; + printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", + card->cnr, card->name); + return card; +} + +static int drivercb_detach_ctr(struct capi_ctr *card) +{ + struct capi_driver *driver = card->driver; + struct capi_ctr **pp; + + if (card->cardstate == CARD_FREE) + return 0; + if (card->cardstate != CARD_DETECTED) + controllercb_reseted(card); + for (pp = &driver->controller; *pp ; pp = &(*pp)->next) { + if (*pp == card) { + *pp = card->next; + driver->ncontroller--; + ncards--; + break; + } + } + if (card->procent) { + remove_proc_entry(card->procfn, 0); + card->procent = 0; + } + card->cardstate = CARD_FREE; + printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n", + card->cnr, card->name); + return 0; +} + +/* ------------------------------------------------------------- */ + +/* fallback if no driver read_proc function defined by driver */ + +static int driver_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct capi_driver *driver = (struct capi_driver *)data; + int len = 0; + + len += sprintf(page+len, "%-16s %s\n", "name", driver->name); + len += sprintf(page+len, "%-16s %s\n", "revision", driver->revision); + + if (len < off) + return 0; + *eof = 1; + *start = page - off; + return ((count < len-off) ? count : len-off); +} + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface di = { + drivercb_attach_ctr, + drivercb_detach_ctr, +}; + +struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver) +{ + struct capi_driver **pp; + + for (pp = &drivers; *pp; pp = &(*pp)->next) ; + driver->next = 0; + *pp = driver; + printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name); +#ifdef CONFIG_AVMB1_COMPAT + if (strcmp(driver->name, "b1isa") == 0 && driver->add_card) + b1isa_driver = driver; + if (strcmp(driver->name, "t1isa") == 0 && driver->add_card) + t1isa_driver = driver; +#endif + sprintf(driver->procfn, "capi/drivers/%s", driver->name); + driver->procent = create_proc_entry(driver->procfn, 0, 0); + if (driver->procent) { + if (driver->driver_read_proc) { + driver->procent->read_proc = + (int (*)(char *,char **,off_t,int,int *,void *)) + driver->driver_read_proc; + } else { + driver->procent->read_proc = driver_read_proc; + } + driver->procent->data = driver; + } + return &di; +} + +void detach_capi_driver(struct capi_driver *driver) +{ + struct capi_driver **pp; + for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ; + if (*pp) { + *pp = (*pp)->next; +#ifdef CONFIG_AVMB1_COMPAT + if (driver == b1isa_driver) b1isa_driver = 0; + if (driver == t1isa_driver) t1isa_driver = 0; +#endif + printk(KERN_NOTICE "kcapi: driver %s detached\n", driver->name); + } else { + printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name); + } + if (driver->procent) { + remove_proc_entry(driver->procfn, 0); + driver->procent = 0; + } +} + +/* ------------------------------------------------------------- */ +/* -------- CAPI2.0 Interface ---------------------------------- */ +/* ------------------------------------------------------------- */ + +static int capi_installed(void) +{ + int i; + for (i = 0; i < CAPI_MAXCONTR; i++) { + if (cards[i].cardstate == CARD_RUNNING) + return 1; + } + return 0; +} + +static __u16 capi_register(capi_register_params * rparam, __u16 * applidp) +{ + int appl; + int i; + + if (rparam->datablklen < 128) + return CAPI_LOGBLKSIZETOSMALL; + + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + if (APPL_IS_FREE(appl)) + break; + } + if (appl > CAPI_MAXAPPL) + return CAPI_TOOMANYAPPLS; + + APPL_MARK_USED(appl); + skb_queue_head_init(&APPL(appl)->recv_queue); + APPL(appl)->nncci = 0; + + memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params)); + + for (i = 0; i < CAPI_MAXCONTR; i++) { + if (cards[i].cardstate != CARD_RUNNING) + continue; + cards[i].driver->register_appl(&cards[i], appl, + &APPL(appl)->rparam); + } + *applidp = appl; + printk(KERN_INFO "kcapi: appl %d up\n", appl); + + return CAPI_NOERROR; +} + +static __u16 capi_release(__u16 applid) +{ + struct sk_buff *skb; + int i; + + if (!VALID_APPLID(applid) || APPL(applid)->releasing) + return CAPI_ILLAPPNR; + while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) + kfree_skb(skb); + for (i = 0; i < CAPI_MAXCONTR; i++) { + if (cards[i].cardstate != CARD_RUNNING) + continue; + APPL(applid)->releasing++; + cards[i].driver->release_appl(&cards[i], applid); + } + if (APPL(applid)->releasing <= 0) { + APPL(applid)->signal = 0; + APPL_MARK_FREE(applid); + printk(KERN_INFO "kcapi: appl %d down\n", applid); + } + return CAPI_NOERROR; +} + +static __u16 capi_put_message(__u16 applid, struct sk_buff *skb) +{ + struct capi_ncci *np; + int contr; + int showctl = 0; + __u8 cmd, subcmd; + + if (ncards == 0) + return CAPI_REGNOTINSTALLED; + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + if (skb->len < 12 + || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data)) + || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data))) + return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; + contr = CAPIMSG_CONTROLLER(skb->data); + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) { + contr = 1; + if (CARD(contr)->cardstate != CARD_RUNNING) + return CAPI_REGNOTINSTALLED; + } + if (CARD(contr)->blocked) + return CAPI_SENDQUEUEFULL; + + cmd = CAPIMSG_COMMAND(skb->data); + subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + if (cmd == CAPI_DATA_B3 && subcmd== CAPI_REQ) { + if ((np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0 + && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0) + return CAPI_SENDQUEUEFULL; + CARD(contr)->nsentdatapkt++; + APPL(applid)->nsentdatapkt++; + if (CARD(contr)->traceflag > 2) showctl |= 2; + } else { + CARD(contr)->nsentctlpkt++; + APPL(applid)->nsentctlpkt++; + if (CARD(contr)->traceflag) showctl |= 2; + } + showctl |= (CARD(contr)->traceflag & 1); + if (showctl & 2) { + if (showctl & 1) { + printk(KERN_DEBUG "kcapi: put [0x%lx] id#%d %s len=%u\n", + (unsigned long) contr, + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); + } else { + printk(KERN_DEBUG "kcapi: put [0x%lx] %s\n", + (unsigned long) contr, + capi_message2str(skb->data)); + } + + } + CARD(contr)->driver->send_message(CARD(contr), skb); + return CAPI_NOERROR; +} + +static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp) +{ + struct sk_buff *skb; + + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0) + return CAPI_RECEIVEQUEUEEMPTY; + *msgp = skb; + return CAPI_NOERROR; +} + +static __u16 capi_set_signal(__u16 applid, + void (*signal) (__u16 applid, __u32 param), + __u32 param) +{ + if (!VALID_APPLID(applid)) + return CAPI_ILLAPPNR; + APPL(applid)->signal = signal; + APPL(applid)->param = param; + return CAPI_NOERROR; +} + +static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]) +{ + if (contr == 0) { + strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN); + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + strncpy(buf, CARD(contr)->manu, CAPI_MANUFACTURER_LEN); + return CAPI_NOERROR; +} + +static __u16 capi_get_version(__u16 contr, struct capi_version *verp) +{ + if (contr == 0) { + *verp = driver_version; + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + memcpy((void *) verp, &CARD(contr)->version, sizeof(capi_version)); + return CAPI_NOERROR; +} + +static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN]) +{ + if (contr == 0) { + strncpy(serial, driver_serial, CAPI_SERIAL_LEN); + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + strncpy((void *) serial, CARD(contr)->serial, CAPI_SERIAL_LEN); + return CAPI_NOERROR; +} + +static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp) +{ + if (contr == 0) { + profp->ncontroller = ncards; + return CAPI_NOERROR; + } + if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) + return 0x2002; + + memcpy((void *) profp, &CARD(contr)->profile, + sizeof(struct capi_profile)); + return CAPI_NOERROR; +} + +#ifdef CONFIG_AVMB1_COMPAT +static int old_capi_manufacturer(unsigned int cmd, void *data) +{ + avmb1_loadandconfigdef ldef; + avmb1_extcarddef cdef; + avmb1_resetdef rdef; + avmb1_getdef gdef; + struct capi_driver *driver; + struct capi_ctr *card; + capicardparams cparams; + capiloaddata ldata; + int retval; + + switch (cmd) { + case AVMB1_ADDCARD: + case AVMB1_ADDCARD_WITH_TYPE: + if (cmd == AVMB1_ADDCARD) { + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(avmb1_carddef)))) + return retval; + cdef.cardtype = AVM_CARDTYPE_B1; + } else { + if ((retval = copy_from_user((void *) &cdef, data, + sizeof(avmb1_extcarddef)))) + return retval; + } + cparams.port = cdef.port; + cparams.irq = cdef.irq; + cparams.cardnr = cdef.cardnr; + + switch (cdef.cardtype) { + case AVM_CARDTYPE_B1: driver = b1isa_driver; break; + case AVM_CARDTYPE_T1: driver = t1isa_driver; break; + default: driver = 0; + } + if (!driver || !driver->add_card) { + return -EIO; + } + + return driver->add_card(driver, &cparams); + + case AVMB1_LOAD: + case AVMB1_LOAD_AND_CONFIG: + + if (cmd == AVMB1_LOAD) { + if ((retval = copy_from_user((void *) &ldef, data, + sizeof(avmb1_loaddef)))) + return retval; + ldef.t4config.len = 0; + ldef.t4config.data = 0; + } else { + if ((retval = copy_from_user((void *) &ldef, data, + sizeof(avmb1_loadandconfigdef)))) + return retval; + } + if (!VALID_CARD(ldef.contr)) + return -ESRCH; + + card = CARD(ldef.contr); + if (card->cardstate == CARD_FREE) + return -ESRCH; + + if (ldef.t4file.len <= 0) { + printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len); + return -EINVAL; + } + if (ldef.t4file.data == 0) { + printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n"); + return -EINVAL; + } + + ldata.firmware.user = 1; + ldata.firmware.data = ldef.t4file.data; + ldata.firmware.len = ldef.t4file.len; + ldata.configuration.user = 1; + ldata.configuration.data = ldef.t4config.data; + ldata.configuration.len = ldef.t4config.len; + + if (card->cardstate != CARD_DETECTED) { + printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr); + return -EBUSY; + } + card->cardstate = CARD_LOADING; + + retval = card->driver->load_firmware(card, &ldata); + + if (retval) { + card->cardstate = CARD_DETECTED; + return retval; + } + + while (card->cardstate != CARD_RUNNING) { + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); /* 0.1 sec */ + + if (signal_pending(current)) + return -EINTR; + } + return 0; + + case AVMB1_RESETCARD: + if ((retval = copy_from_user((void *) &rdef, data, + sizeof(avmb1_resetdef)))) + return retval; + if (!VALID_CARD(rdef.contr)) + return -ESRCH; + card = CARD(rdef.contr); + + if (card->cardstate == CARD_FREE) + return -ESRCH; + if (card->cardstate == CARD_DETECTED) + return 0; + + card->driver->reset_ctr(card); + + while (card->cardstate > CARD_DETECTED) { + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); /* 0.1 sec */ + + if (signal_pending(current)) + return -EINTR; + } + return 0; + + case AVMB1_GET_CARDINFO: + if ((retval = copy_from_user((void *) &gdef, data, + sizeof(avmb1_getdef)))) + return retval; + + if (!VALID_CARD(gdef.contr)) + return -ESRCH; + + card = CARD(gdef.contr); + + if (card->cardstate == CARD_FREE) + return -ESRCH; + + gdef.cardstate = card->cardstate; + if (card->driver == b1isa_driver) + gdef.cardtype = AVM_CARDTYPE_B1; + else if (card->driver == t1isa_driver) + gdef.cardtype = AVM_CARDTYPE_T1; + else gdef.cardtype = AVM_CARDTYPE_B1; + + if ((retval = copy_to_user(data, (void *) &gdef, + sizeof(avmb1_getdef)))) + return retval; + + return 0; + + case AVMB1_REMOVECARD: + if ((retval = copy_from_user((void *) &rdef, data, + sizeof(avmb1_resetdef)))) + return retval; + + if (!VALID_CARD(rdef.contr)) + return -ESRCH; + card = CARD(rdef.contr); + + if (card->cardstate == CARD_FREE) + return -ESRCH; + + if (card->cardstate != CARD_DETECTED) + return -EBUSY; + + card->driver->remove_ctr(card); + + while (card->cardstate != CARD_FREE) { + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); /* 0.1 sec */ + + if (signal_pending(current)) + return -EINTR; + } + return 0; + } + return -EINVAL; +} +#endif + +static int capi_manufacturer(unsigned int cmd, void *data) +{ + struct capi_ctr *card; + kcapi_flagdef fdef; + int retval; + + switch (cmd) { +#ifdef CONFIG_AVMB1_COMPAT + case AVMB1_ADDCARD: + case AVMB1_ADDCARD_WITH_TYPE: + case AVMB1_LOAD: + case AVMB1_LOAD_AND_CONFIG: + case AVMB1_RESETCARD: + case AVMB1_GET_CARDINFO: + case AVMB1_REMOVECARD: + return old_capi_manufacturer(cmd, data); +#endif + case KCAPI_CMD_TRACE: + if ((retval = copy_from_user((void *) &fdef, data, + sizeof(kcapi_flagdef)))) + return retval; + + if (!VALID_CARD(fdef.contr)) + return -ESRCH; + card = CARD(fdef.contr); + if (card->cardstate == CARD_FREE) + return -ESRCH; + card->traceflag = fdef.flag; + printk(KERN_INFO "kcapi: contr %d set trace=%d\n", + card->cnr, card->traceflag); + return 0; + } + return -EINVAL; +} + +struct capi_interface avmb1_interface = +{ + capi_installed, + capi_register, + capi_release, + capi_put_message, + capi_get_message, + capi_set_signal, + capi_get_manufacturer, + capi_get_version, + capi_get_serial, + capi_get_profile, + capi_manufacturer +}; + +/* ------------------------------------------------------------- */ +/* -------- Exported Functions --------------------------------- */ +/* ------------------------------------------------------------- */ + +struct capi_interface *attach_capi_interface(struct capi_interface_user *userp) +{ + struct capi_interface_user *p; + + for (p = capi_users; p; p = p->next) { + if (p == userp) { + printk(KERN_ERR "kcapi: double attach from %s\n", + userp->name); + return 0; + } + } + userp->next = capi_users; + capi_users = userp; + MOD_INC_USE_COUNT; + printk(KERN_NOTICE "kcapi: %s attached\n", userp->name); + + return &avmb1_interface; +} + +int detach_capi_interface(struct capi_interface_user *userp) +{ + struct capi_interface_user **pp; + + for (pp = &capi_users; *pp; pp = &(*pp)->next) { + if (*pp == userp) { + *pp = userp->next; + userp->next = 0; + MOD_DEC_USE_COUNT; + printk(KERN_NOTICE "kcapi: %s detached\n", userp->name); + return 0; + } + } + printk(KERN_ERR "kcapi: double detach from %s\n", userp->name); + return -1; +} + +/* ------------------------------------------------------------- */ +/* -------- Init & Cleanup ------------------------------------- */ +/* ------------------------------------------------------------- */ + +EXPORT_SYMBOL(attach_capi_interface); +EXPORT_SYMBOL(detach_capi_interface); +EXPORT_SYMBOL(attach_capi_driver); +EXPORT_SYMBOL(detach_capi_driver); + +/* + * init / exit functions + */ + +#ifdef MODULE +#define kcapi_init init_module +#endif + +int kcapi_init(void) +{ + char *p; + char rev[10]; + + skb_queue_head_init(&recv_queue); + /* init_bh(CAPI_BH, do_capi_bh); */ + + tq_state_notify.routine = notify_handler; + tq_state_notify.data = 0; + + tq_recv_notify.routine = recv_handler; + tq_recv_notify.data = 0; + + proc_capi_init(); + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else + strcpy(rev, "1.0"); + +#ifdef MODULE + printk(KERN_NOTICE "CAPI-driver Rev%s: loaded\n", rev); +#else + printk(KERN_NOTICE "CAPI-driver Rev%s: started\n", rev); +#endif + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + char rev[10]; + char *p; + + if ((p = strchr(revision, ':'))) { + strcpy(rev, p + 1); + p = strchr(rev, '$'); + *p = 0; + } else { + strcpy(rev, "1.0"); + } + + schedule(); /* execute queued tasks .... */ + proc_capi_exit(); + printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev); +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.2.10/linux/drivers/isdn/avmb1/t1isa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/avmb1/t1isa.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,545 @@ +/* + * $Id: t1isa.c,v 1.4 1999/07/09 15:05:50 keil Exp $ + * + * Module for AVM T1 HEMA-card. + * + * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: t1isa.c,v $ + * Revision 1.4 1999/07/09 15:05:50 keil + * compat.h is now isdn_compat.h + * + * Revision 1.3 1999/07/06 07:42:04 calle + * - changes in /proc interface + * - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb. + * + * Revision 1.2 1999/07/05 15:09:54 calle + * - renamed "appl_release" to "appl_released". + * - version und profile data now cleared on controller reset + * - extended /proc interface, to allow driver and controller specific + * informations to include by driver hackers. + * + * Revision 1.1 1999/07/01 15:26:44 calle + * complete new version (I love it): + * + new hardware independed "capi_driver" interface that will make it easy to: + * - support other controllers with CAPI-2.0 (i.e. USB Controller) + * - write a CAPI-2.0 for the passive cards + * - support serial link CAPI-2.0 boxes. + * + wrote "capi_driver" for all supported cards. + * + "capi_driver" (supported cards) now have to be configured with + * make menuconfig, in the past all supported cards where included + * at once. + * + new and better informations in /proc/capi/ + * + new ioctl to switch trace of capi messages per controller + * using "avmcapictrl trace [contr] on|off|...." + * + complete testcircle with all supported cards and also the + * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "capicmd.h" +#include "capiutil.h" +#include "capilli.h" +#include "avmcard.h" + +static char *revision = "$Revision: 1.4 $"; + +/* ------------------------------------------------------------- */ + +MODULE_AUTHOR("Carsten Paeth "); + +/* ------------------------------------------------------------- */ + +static struct capi_driver_interface *di; + +/* ------------------------------------------------------------- */ + +static int hema_irq_table[16] = +{0, + 0, + 0, + 0x80, /* irq 3 */ + 0, + 0x90, /* irq 5 */ + 0, + 0xA0, /* irq 7 */ + 0, + 0xB0, /* irq 9 */ + 0xC0, /* irq 10 */ + 0xD0, /* irq 11 */ + 0xE0, /* irq 12 */ + 0, + 0, + 0xF0, /* irq 15 */ +}; + +static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr) +{ + unsigned char cregs[8]; + unsigned char reverse_cardnr; + unsigned long flags; + unsigned char dummy; + int i; + + reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1) + | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3); + cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf); + cregs[1] = 0x00; /* fast & slow link connected to CON1 */ + cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */ + cregs[3] = 0; + cregs[4] = 0x11; /* zero wait state */ + cregs[5] = hema_irq_table[irq & 0xf]; + cregs[6] = 0; + cregs[7] = 0; + + save_flags(flags); + cli(); + /* board reset */ + t1outp(base, T1_RESETBOARD, 0xf); + udelay(100 * 1000); + dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */ + + /* write config */ + dummy = (base >> 4) & 0xff; + for (i=1;i<=0xf;i++) t1outp(base, i, dummy); + t1outp(base, HEMA_PAL_ID & 0xf, dummy); + t1outp(base, HEMA_PAL_ID >> 4, cregs[0]); + for(i=1;i<7;i++) t1outp(base, 0, cregs[i]); + t1outp(base, ((base >> 4)) & 0x3, cregs[7]); + restore_flags(flags); + + udelay(100 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); + udelay(10 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 1); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1); + udelay(100 * 1000); + t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); + t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); + udelay(10 * 1000); + t1outp(base, T1_FASTLINK+T1_ANALYSE, 0); + udelay(5 * 1000); + t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0); + + if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */ + return 1; + if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */ + return 2; + if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0) + return 3; + if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70) + return 4; + if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0) + return 5; + if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1) + return 6; + if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */ + return 7; + if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0) + return 8; + if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0) + return 9; + return 0; +} + +static void t1_handle_interrupt(avmcard * card) +{ + struct capi_ctr *ctrl = card->ctrl; + unsigned char b1cmd; + struct sk_buff *skb; + + unsigned ApplId; + unsigned MsgLen; + unsigned DataB3Len; + unsigned NCCI; + unsigned WindowSize; + + while (b1_rx_full(card->port)) { + + b1cmd = b1_get_byte(card->port); + + switch (b1cmd) { + + case RECEIVE_DATA_B3_IND: + + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = t1_get_slice(card->port, card->msgbuf); + DataB3Len = t1_get_slice(card->port, card->databuf); + + if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "t1isa: incoming packet dropped\n"); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len); + CAPIMSG_SETDATA(skb->data, skb->data + MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_MESSAGE: + + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = t1_get_slice(card->port, card->msgbuf); + if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + printk(KERN_ERR "t1isa: incoming packet dropped\n"); + } else { + memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); + ctrl->handle_capimsg(ctrl, ApplId, skb); + } + break; + + case RECEIVE_NEW_NCCI: + + ApplId = b1_get_word(card->port); + NCCI = b1_get_word(card->port); + WindowSize = b1_get_word(card->port); + + ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize); + + break; + + case RECEIVE_FREE_NCCI: + + ApplId = b1_get_word(card->port); + NCCI = b1_get_word(card->port); + + if (NCCI != 0xffffffff) + ctrl->free_ncci(ctrl, ApplId, NCCI); + else ctrl->appl_released(ctrl, ApplId); + break; + + case RECEIVE_START: + b1_put_byte(card->port, SEND_POLLACK); + ctrl->resume_output(ctrl); + break; + + case RECEIVE_STOP: + ctrl->suspend_output(ctrl); + break; + + case RECEIVE_INIT: + + card->versionlen = t1_get_slice(card->port, card->versionbuf); + b1_parse_version(card); + printk(KERN_INFO "%s: %s-card (%s) now active\n", + card->name, + card->version[VER_CARDTYPE], + card->version[VER_DRIVER]); + ctrl->ready(ctrl); + break; + + case RECEIVE_TASK_READY: + ApplId = (unsigned) b1_get_word(card->port); + MsgLen = t1_get_slice(card->port, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: task %d \"%s\" ready.\n", + card->name, ApplId, card->msgbuf); + break; + + case RECEIVE_DEBUGMSG: + MsgLen = t1_get_slice(card->port, card->msgbuf); + card->msgbuf[MsgLen--] = 0; + while ( MsgLen >= 0 + && ( card->msgbuf[MsgLen] == '\n' + || card->msgbuf[MsgLen] == '\r')) + card->msgbuf[MsgLen--] = 0; + printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); + break; + + case 0xff: + printk(KERN_ERR "%s: card reseted ?\n", card->name); + return; + default: + printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", + card->name, b1cmd); + return; + } + } +} + +/* ------------------------------------------------------------- */ + +static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs) +{ + avmcard *card; + + card = (avmcard *) devptr; + + if (!card) { + printk(KERN_WARNING "t1_interrupt: wrong device\n"); + return; + } + if (card->interrupt) { + printk(KERN_ERR "t1_interrupt: reentering interrupt hander (%s)\n", card->name); + return; + } + + card->interrupt = 1; + + t1_handle_interrupt(card); + + card->interrupt = 0; +} +/* ------------------------------------------------------------- */ + +static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + int retval; + + t1_disable_irq(port); + b1_reset(port); + + if ((retval = b1_load_t4file(port, &data->firmware))) { + b1_reset(port); + printk(KERN_ERR "%s: failed to load t4file!!\n", + card->name); + return retval; + } + + if (data->configuration.len > 0 && data->configuration.data) { + if ((retval = b1_load_config(port, &data->configuration))) { + b1_reset(port); + printk(KERN_ERR "%s: failed to load config!!\n", + card->name); + return retval; + } + } + + if (!b1_loaded(port)) { + printk(KERN_ERR "%s: failed to load t4file.\n", card->name); + return -EIO; + } + + save_flags(flags); + cli(); + b1_setinterrupt(port, card->irq, card->cardtype); + b1_put_byte(port, SEND_INIT); + b1_put_word(port, AVM_NAPPS); + b1_put_word(port, AVM_NCCI_PER_CHANNEL*30); + b1_put_word(port, ctrl->cnr - 1); + restore_flags(flags); + + return 0; +} + +void t1isa_reset_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + t1_disable_irq(port); + b1_reset(port); + b1_reset(port); + + memset(card->version, 0, sizeof(card->version)); + ctrl->reseted(ctrl); +} + +static void t1isa_remove_ctr(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + + t1_disable_irq(port); + b1_reset(port); + b1_reset(port); + t1_reset(port); + + di->detach_ctr(ctrl); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + + MOD_DEC_USE_COUNT; +} + +/* ------------------------------------------------------------- */ + +static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p) +{ + struct capi_ctr *ctrl; + avmcard *card; + int retval; + + card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC); + + if (!card) { + printk(KERN_WARNING "t1isa: no memory.\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(avmcard)); + sprintf(card->name, "t1isa-%x", p->port); + card->port = p->port; + card->irq = p->irq; + card->cardtype = avm_t1isa; + card->cardnr = p->cardnr; + + if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) { + printk(KERN_WARNING "t1isa: illegal port 0x%x.\n", card->port); + kfree(card); + return -EINVAL; + } + + if (check_region(card->port, AVMB1_PORTLEN)) { + printk(KERN_WARNING + "t1isa: ports 0x%03x-0x%03x in use.\n", + card->port, card->port + AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + if (hema_irq_table[card->irq & 0xf] == 0) { + printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq); + kfree(card); + return -EINVAL; + } + for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) { + if (((avmcard *)(ctrl->driverdata))->cardnr == card->cardnr) { + printk(KERN_WARNING "t1isa: card with number %d already installed.\n", card->cardnr); + kfree(card); + return -EBUSY; + } + } + if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) { + printk(KERN_NOTICE "t1isa: NO card at 0x%x (%d)\n", + card->port, retval); + kfree(card); + return -EIO; + } + t1_disable_irq(card->port); + b1_reset(card->port); + + request_region(p->port, AVMB1_PORTLEN, card->name); + + retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card); + if (retval) { + printk(KERN_ERR "t1isa: unable to get IRQ %d.\n", card->irq); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + card->ctrl = di->attach_ctr(driver, card->name, card); + if (!card->ctrl) { + printk(KERN_ERR "t1isa: attach controller failed.\n"); + free_irq(card->irq, card); + release_region(card->port, AVMB1_PORTLEN); + kfree(card); + return -EBUSY; + } + + MOD_INC_USE_COUNT; + return 0; +} + +static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + unsigned int port = card->port; + unsigned long flags; + __u16 len = CAPIMSG_LEN(skb->data); + __u8 cmd = CAPIMSG_COMMAND(skb->data); + __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); + + save_flags(flags); + cli(); + if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { + __u16 dlen = CAPIMSG_DATALEN(skb->data); + b1_put_byte(port, SEND_DATA_B3_REQ); + t1_put_slice(port, skb->data, len); + t1_put_slice(port, skb->data + len, dlen); + } else { + b1_put_byte(port, SEND_MESSAGE); + t1_put_slice(port, skb->data, len); + } + restore_flags(flags); + dev_kfree_skb(skb); +} +/* ------------------------------------------------------------- */ + +static char *t1isa_procinfo(struct capi_ctr *ctrl) +{ + avmcard *card = (avmcard *)(ctrl->driverdata); + if (!card) + return ""; + sprintf(card->infobuf, "%s %s 0x%x %d %d", + card->cardname[0] ? card->cardname : "-", + card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-", + card->port, card->irq, card->cardnr + ); + return card->infobuf; +} + + +/* ------------------------------------------------------------- */ + +static struct capi_driver t1isa_driver = { + "t1isa", + "0.0", + t1isa_load_firmware, + t1isa_reset_ctr, + t1isa_remove_ctr, + b1_register_appl, + b1_release_appl, + t1isa_send_message, + + t1isa_procinfo, + b1ctl_read_proc, + 0, /* use standard driver_read_proc */ + + t1isa_add_card, +}; + +#ifdef MODULE +#define t1isa_init init_module +void cleanup_module(void); +#endif + +int t1isa_init(void) +{ + struct capi_driver *driver = &t1isa_driver; + char *p; + + if ((p = strchr(revision, ':'))) { + strncpy(driver->revision, p + 1, sizeof(driver->revision)); + p = strchr(driver->revision, '$'); + *p = 0; + } + + printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); + + di = attach_capi_driver(driver); + + if (!di) { + printk(KERN_ERR "%s: failed to attach capi_driver\n", + driver->name); + return -EIO; + } + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + detach_capi_driver(&t1isa_driver); +} +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/divert/Makefile linux/drivers/isdn/divert/Makefile --- v2.2.10/linux/drivers/isdn/divert/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/divert/Makefile Mon Aug 9 12:04:39 1999 @@ -0,0 +1,21 @@ +L_OBJS := +LX_OBJS := +M_OBJS := +MX_OBJS := +O_OBJS := +OX_OBJS := +L_TARGET := +O_TARGET := + +O_OBJS += isdn_divert.o divert_procfs.o +O_TARGET := dss1_divert.o +M_OBJS += dss1_divert.o +OX_OBJS += divert_init.o + +include $(TOPDIR)/Rules.make + + + + + + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c --- v2.2.10/linux/drivers/isdn/divert/divert_init.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/divert/divert_init.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,105 @@ +/* + * $Id: divert_init.c,v 1.3 1999/07/05 20:21:39 werner Exp $ + * + * Module init for DSS1 diversion services for i4l. + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * + * 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, 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. + * + * $Log: divert_init.c,v $ + * Revision 1.3 1999/07/05 20:21:39 werner + * changes to use diversion sources for all kernel versions. + * removed static device, only proc filesystem used + * + * Revision 1.2 1999/07/04 21:37:30 werner + * Ported from kernel version 2.0 + * + * + * + */ + +#include +#include +#include +#include "isdn_divert.h" + +/********************/ +/* needed externals */ +/********************/ +extern int printk(const char *fmt,...); + +/****************************************/ +/* structure containing interface to hl */ +/****************************************/ +isdn_divert_if divert_if = + { DIVERT_IF_MAGIC, /* magic value */ + DIVERT_CMD_REG, /* register cmd */ + ll_callback, /* callback routine from ll */ + NULL, /* command still not specified */ + NULL, /* drv_to_name */ + NULL, /* name_to_drv */ + }; + +/*************************/ +/* Module interface code */ +/* no cmd line parms */ +/*************************/ +int init_module(void) +{ int i; + + if (divert_dev_init()) + { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n"); + return(-EIO); + } + if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) + { divert_dev_deinit(); + printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n",i); + return(-EIO); + } +#if (LINUX_VERSION_CODE < 0x020111) + register_symtab(0); +#endif + printk(KERN_INFO "dss1_divert module successfully installed\n"); + return(0); +} /* init_module */ + +/**********************/ +/* Module deinit code */ +/**********************/ +void cleanup_module(void) +{ int flags; + int i; + + save_flags(flags); + cli(); + divert_if.cmd = DIVERT_CMD_REL; /* release */ + if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) + { printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i); + restore_flags(flags); + return; + } + if (divert_dev_deinit()) + { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n"); + restore_flags(flags); + return; + } + restore_flags(flags); + deleterule(-1); /* delete all rules and free mem */ + deleteprocs(); + printk(KERN_INFO "dss1_divert module successfully removed \n"); +} /* cleanup_module */ + + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.2.10/linux/drivers/isdn/divert/divert_procfs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/divert/divert_procfs.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,444 @@ +/* + * $Id: divert_procfs.c,v 1.3 1999/07/05 20:21:41 werner Exp $ + * + * Filesystem handling for the diversion supplementary services. + * + * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de) + * + * 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, 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. + * + * $Log: divert_procfs.c,v $ + * Revision 1.3 1999/07/05 20:21:41 werner + * changes to use diversion sources for all kernel versions. + * removed static device, only proc filesystem used + * + * Revision 1.2 1999/07/04 21:37:31 werner + * Ported from kernel version 2.0 + * + * + * + */ + +#include +#define __NO_VERSION__ +#include +#include +#if (LINUX_VERSION_CODE >= 0x020117) +#include +#endif +#ifdef CONFIG_PROC_FS + #include +#else + #include +#endif +#include +#include "isdn_divert.h" + +/*********************************/ +/* Variables for interface queue */ +/*********************************/ +ulong if_used = 0; /* number of interface users */ +static struct divert_info *divert_info_head = NULL; /* head of queue */ +static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ +static struct wait_queue *rd_queue = 0; /* Queue IO */ + +/*********************************/ +/* put an info buffer into queue */ +/*********************************/ +void put_info_buffer(char *cp) +{ struct divert_info *ib; + int flags; + + if (if_used <= 0) return; + if (!cp) return; + if (!*cp) return; + if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info)+strlen(cp), GFP_ATOMIC))) return; /* no memory */ + strcpy(ib->info_start,cp); /* set output string */ + ib->next = NULL; + save_flags(flags); + cli(); + ib->usage_cnt = if_used; + if (!divert_info_head) + divert_info_head = ib; /* new head */ + else + divert_info_tail->next = ib; /* follows existing messages */ + divert_info_tail = ib; /* new tail */ + restore_flags(flags); + + /* delete old entrys */ + while (divert_info_head->next) + { if ((divert_info_head->usage_cnt <= 0) && + (divert_info_head->next->usage_cnt <= 0)) + { ib = divert_info_head; + divert_info_head = divert_info_head->next; + kfree(ib); + } + else break; + } /* divert_info_head->next */ + wake_up_interruptible(&(rd_queue)); +} /* put_info_buffer */ + +/**********************************/ +/* deflection device read routine */ +/**********************************/ +#if (LINUX_VERSION_CODE < 0x020117) +static int isdn_divert_read(struct inode *inode, struct file *file, char *buf, RWARG count) +#else +static ssize_t isdn_divert_read(struct file *file, char *buf, size_t count, loff_t *off) +#endif +{ struct divert_info *inf; + int len; + + if (!*((struct divert_info **)file->private_data)) + { if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + interruptible_sleep_on(&(rd_queue)); + } + if (!(inf = *((struct divert_info **)file->private_data))) return(0); + + inf->usage_cnt--; /* new usage count */ + (struct divert_info **)file->private_data = &inf->next; /* next structure */ + if ((len = strlen(inf->info_start)) <= count) + { if (copy_to_user(buf, inf->info_start, len)) + return -EFAULT; + file->f_pos += len; + return(len); + } + return(0); +} /* isdn_divert_read */ + +/**********************************/ +/* deflection device write routine */ +/**********************************/ +#if (LINUX_VERSION_CODE < 0x020117) +static int isdn_divert_write(struct inode *inode, struct file *file, const char *buf, RWARG count) +#else +static ssize_t isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t *off) +#endif +{ + return(-ENODEV); +} /* isdn_divert_write */ + + +/***************************************/ +/* select routines for various kernels */ +/***************************************/ +#if (LINUX_VERSION_CODE < 0x020117) +static int isdn_divert_select(struct inode *inode, struct file *file, int type, select_table * st) +{ + if (*((struct divert_info **)file->private_data)) + return 1; + else + { if (st) select_wait(&(rd_queue), st); + return 0; + } +} /* isdn_divert_select */ +#else +static unsigned int isdn_divert_poll(struct file *file, poll_table * wait) +{ unsigned int mask = 0; + + poll_wait(file, &(rd_queue), wait); + /* mask = POLLOUT | POLLWRNORM; */ + if (*((struct divert_info **)file->private_data)) + { mask |= POLLIN | POLLRDNORM; + } + return mask; +} /* isdn_divert_poll */ +#endif + +/****************/ +/* Open routine */ +/****************/ +static int isdn_divert_open(struct inode *ino, struct file *filep) +{ int flags; + + MOD_INC_USE_COUNT; + save_flags(flags); + cli(); + if_used++; + if (divert_info_head) + (struct divert_info **)filep->private_data = &(divert_info_tail->next); + else + (struct divert_info **)filep->private_data = &divert_info_head; + restore_flags(flags); + /* start_divert(); */ + return(0); +} /* isdn_divert_open */ + +/*******************/ +/* close routine */ +/*******************/ +#if (LINUX_VERSION_CODE < 0x020117) +static void isdn_divert_close(struct inode *ino, struct file *filep) +#else +static int isdn_divert_close(struct inode *ino, struct file *filep) +#endif +{ struct divert_info *inf; + int flags; + + save_flags(flags); + cli(); + if_used--; + inf = *((struct divert_info **)filep->private_data); + while (inf) + { inf->usage_cnt--; + inf = inf->next; + } + restore_flags(flags); + if (if_used <= 0) + while (divert_info_head) + { inf = divert_info_head; + divert_info_head = divert_info_head->next; + kfree(inf); + } + MOD_DEC_USE_COUNT; +#if (LINUX_VERSION_CODE < 0x020117) +#else + return(0); +#endif +} /* isdn_divert_close */ + +/*********/ +/* IOCTL */ +/*********/ +static int isdn_divert_ioctl(struct inode *inode, struct file *file, + uint cmd, ulong arg) +{ divert_ioctl dioctl; + int i, flags; + divert_rule *rulep; + char *cp; + + if ((i = copy_from_user(&dioctl,(char *) arg, sizeof(dioctl)))) + return(i); + + switch (cmd) + { + case IIOCGETVER: + dioctl.drv_version = DIVERT_IIOC_VERSION ; /* set version */ + break; + + case IIOCGETDRV: + if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0) + return(-EINVAL); + break; + + case IIOCGETNAM: + cp = divert_if.drv_to_name(dioctl.getid.drvid); + if (!cp) return(-EINVAL); + if (!*cp) return(-EINVAL); + strcpy(dioctl.getid.drvnam,cp); + break; + + case IIOCGETRULE: + if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) + return(-EINVAL); + dioctl.getsetrule.rule = *rulep; /* copy data */ + break; + + case IIOCMODRULE: + if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) + return(-EINVAL); + save_flags(flags); + cli(); + *rulep = dioctl.getsetrule.rule; /* copy data */ + restore_flags(flags); + return(0); /* no copy required */ + break; + + case IIOCINSRULE: + return(insertrule(dioctl.getsetrule.ruleidx,&dioctl.getsetrule.rule)); + break; + + case IIOCDELRULE: + return(deleterule(dioctl.getsetrule.ruleidx)); + break; + + case IIOCDODFACT: + return(deflect_extern_action(dioctl.fwd_ctrl.subcmd, + dioctl.fwd_ctrl.callid, + dioctl.fwd_ctrl.to_nr)); + + case IIOCDOCFACT: + case IIOCDOCFDIS: + case IIOCDOCFINT: + if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) + return(-EINVAL); /* invalid driver */ + if ((i = cf_command(dioctl.cf_ctrl.drvid, + (cmd == IIOCDOCFACT) ? 1: (cmd == IIOCDOCFDIS) ? 0:2, + dioctl.cf_ctrl.cfproc, + dioctl.cf_ctrl.msn, + dioctl.cf_ctrl.service, + dioctl.cf_ctrl.fwd_nr, + &dioctl.cf_ctrl.procid))) + return(i); + break; + + default: + return(-EINVAL); + } /* switch cmd */ + return(copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */ +} /* isdn_divert_ioctl */ + + +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE < 0x020117) +static LSTYPE +isdn_divert_lseek(struct inode *inode, struct file *file, LSARG offset, int orig) +#else +static loff_t +isdn_divert_lseek(struct file *file, loff_t offset, int orig) +#endif +{ + return -ESPIPE; +} + +#if (LINUX_VERSION_CODE < 0x020117) +static struct file_operations isdn_fops = +{ + isdn_divert_lseek, + isdn_divert_read, + isdn_divert_write, + NULL, /* isdn_readdir */ + isdn_divert_select, /* isdn_select */ + isdn_divert_ioctl, /* isdn_ioctl */ + NULL, /* isdn_mmap */ + isdn_divert_open, + isdn_divert_close, + NULL /* fsync */ +}; + +#else + +static struct file_operations isdn_fops = +{ + isdn_divert_lseek, + isdn_divert_read, + isdn_divert_write, + NULL, /* isdn_readdir */ + isdn_divert_poll, /* isdn_poll */ + isdn_divert_ioctl, /* isdn_ioctl */ + NULL, /* isdn_mmap */ + isdn_divert_open, + NULL, /* flush */ + isdn_divert_close, + NULL /* fsync */ +}; +#endif /* kernel >= 2.1 */ + + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_isdn_inode_ops = { + &isdn_fops, /* isdn divert special file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/****************************/ +/* isdn subdir in /proc/net */ +/****************************/ +static struct proc_dir_entry isdn_proc_entry = + { 0, 4, "isdn", S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, 0, + &proc_dir_inode_operations,NULL,NULL,NULL,NULL,NULL + }; + +static struct proc_dir_entry isdn_divert_entry = +{ 0, 6, "divert",S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_isdn_inode_ops, + NULL + }; + +/*****************************************************************/ +/* variables used for automatic determining existence of proc fs */ +/*****************************************************************/ +static int (*proc_reg_dynamic)(struct proc_dir_entry *, struct proc_dir_entry *) = NULL; +static int (*proc_unreg)(struct proc_dir_entry *, int) = NULL; + +#endif CONFIG_PROC_FS + +/***************************************************************************/ +/* divert_dev_init must be called before the proc filesystem may be used */ +/***************************************************************************/ +int divert_dev_init(void) +{ int i; + +#ifdef CONFIG_PROC_FS +#if (LINUX_VERSION_CODE < 0x020117) + (void *) proc_reg_dynamic = get_module_symbol("","proc_register_dynamic"); + (void *) proc_unreg = get_module_symbol("","proc_unregister"); + if (proc_unreg) + { i = proc_reg_dynamic(&proc_net,&isdn_proc_entry); + if (i) return(i); + i = proc_reg_dynamic(&isdn_proc_entry,&isdn_divert_entry); + if (i) + { proc_unreg(&proc_net,isdn_proc_entry.low_ino); + return(i); + } + } /* proc exists */ +#else + (void *) proc_reg_dynamic = get_module_symbol("","proc_register"); + (void *) proc_unreg = get_module_symbol("","proc_unregister"); + if (proc_unreg) + { i = proc_reg_dynamic(proc_net,&isdn_proc_entry); + if (i) return(i); + i = proc_reg_dynamic(&isdn_proc_entry,&isdn_divert_entry); + if (i) + { proc_unreg(proc_net,isdn_proc_entry.low_ino); + return(i); + } + } /* proc exists */ +#endif +#endif CONFIG_PROC_FS + + return(0); +} /* divert_dev_init */ + +/***************************************************************************/ +/* divert_dev_deinit must be called before leaving isdn when included as */ +/* a module. */ +/***************************************************************************/ +int divert_dev_deinit(void) +{ int i; + +#ifdef CONFIG_PROC_FS + if (proc_unreg) + { i = proc_unreg(&isdn_proc_entry,isdn_divert_entry.low_ino); + if (i) return(i); +#if (LINUX_VERSION_CODE < 0x020117) + i = proc_unreg(&proc_net,isdn_proc_entry.low_ino); +#else + i = proc_unreg(proc_net,isdn_proc_entry.low_ino); +#endif + if (i) return(i); + } /* proc exists */ +#endif CONFIG_PROC_FS + + return(0); +} /* divert_dev_deinit */ + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c --- v2.2.10/linux/drivers/isdn/divert/isdn_divert.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/divert/isdn_divert.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,902 @@ +/* + * $Id: isdn_divert.c,v 1.2 1999/07/04 21:37:32 werner Exp $ + * + * DSS1 main diversion supplementary handling for i4l. + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * + * 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, 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. + * + * $Log: isdn_divert.c,v $ + * Revision 1.2 1999/07/04 21:37:32 werner + * Ported from kernel version 2.0 + * + * + * + */ + + + +#include +#define __NO_VERSION__ +#include +#include +#include +#include "isdn_divert.h" + +/**********************************/ +/* structure keeping calling info */ +/**********************************/ +struct call_struc + { isdn_ctrl ics; /* delivered setup + driver parameters */ + ulong divert_id; /* Id delivered to user */ + unsigned char akt_state; /* actual state */ + char deflect_dest[35]; /* deflection destination */ + struct timer_list timer; /* timer control structure */ + char info[90]; /* device info output */ + struct call_struc *next; /* pointer to next entry */ + struct call_struc *prev; + }; + + +/********************************************/ +/* structure keeping deflection table entry */ +/********************************************/ +struct deflect_struc + { struct deflect_struc *next,*prev; + divert_rule rule; /* used rule */ + }; + + +/*****************************************/ +/* variables for main diversion services */ +/*****************************************/ +/* diversion/deflection processes */ +static struct call_struc *divert_head = NULL; /* head of remembered entrys */ +static ulong next_id = 1; /* next info id */ +static struct deflect_struc *table_head = NULL; +static struct deflect_struc *table_tail = NULL; +static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */ + +/***************************/ +/* timer callback function */ +/***************************/ +static void deflect_timer_expire(ulong arg) +{ int flags; + struct call_struc *cs = (struct call_struc *) arg; + + save_flags(flags); + cli(); + del_timer(&cs->timer); /* delete active timer */ + restore_flags(flags); + + switch(cs->akt_state) + { case DEFLECT_PROCEED: + cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */ + divert_if.ll_cmd(&cs->ics); + save_flags(flags); + cli(); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + add_timer(&cs->timer); + restore_flags(flags); + break; + + case DEFLECT_ALERT: + cs->ics.command = ISDN_CMD_REDIR; /* protocol */ + strcpy(cs->ics.parm.setup.phone,cs->deflect_dest); + strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed"); + divert_if.ll_cmd(&cs->ics); + save_flags(flags); + cli(); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + add_timer(&cs->timer); + restore_flags(flags); + break; + + case DEFLECT_AUTODEL: + default: + save_flags(flags); + cli(); + if (cs->prev) + cs->prev->next = cs->next; /* forward link */ + else + divert_head = cs->next; + if (cs->next) + cs->next->prev = cs->prev; /* back link */ + restore_flags(flags); + kfree(cs); + return; + + } /* switch */ +} /* deflect_timer_func */ + + +/*****************************************/ +/* handle call forwarding de/activations */ +/* 0 = deact, 1 = act, 2 = interrogate */ +/*****************************************/ +int cf_command(int drvid, int mode, + u_char proc, char *msn, + u_char service, char *fwd_nr, ulong *procid) +{ int retval,msnlen,flags; + int fwd_len; + char *p,*ielenp,tmp[60]; + struct call_struc *cs; + + if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */ + if ((proc & 0x7F) > 2) return(-EINVAL); + proc &= 3; + p = tmp; + *p++ = 0x30; /* enumeration */ + ielenp = p++; /* remember total length position */ + *p++ = 0xa; /* proc tag */ + *p++ = 1; /* length */ + *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */ + *p++ = 0xa; /* service tag */ + *p++ = 1; /* length */ + *p++ = service; /* service to handle */ + + if (mode == 1) + { if (!*fwd_nr) return(-EINVAL); /* destination missing */ + if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */ + fwd_len = strlen(fwd_nr); + *p++ = 0x30; /* number enumeration */ + *p++ = fwd_len + 2; /* complete forward to len */ + *p++ = 0x80; /* fwd to nr */ + *p++ = fwd_len; /* length of number */ + strcpy(p,fwd_nr); /* copy number */ + p += fwd_len; /* pointer beyond fwd */ + } /* activate */ + + msnlen = strlen(msn); + *p++ = 0x80; /* msn number */ + if (msnlen > 1) + { *p++ = msnlen; /* length */ + strcpy(p,msn); + p += msnlen; + } + else *p++ = 0; + + *ielenp = p - ielenp - 1; /* set total IE length */ + + /* allocate mem for information struct */ + if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) + return(-ENOMEM); /* no memory */ + init_timer(&cs->timer); + cs->info[0] = '\0'; + cs->timer.function = deflect_timer_expire; + cs->timer.data = (ulong) cs; /* pointer to own structure */ + cs->ics.driver = drvid; + cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */ + cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */ + cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */ + cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */ + cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */ + cs->ics.parm.dss1_io.data = tmp; /* start of buffer */ + + save_flags(flags); + cli(); + cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */ + restore_flags(flags); + *procid = cs->ics.parm.dss1_io.ll_id; + + sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n", + (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT, + cs->ics.parm.dss1_io.ll_id, + (mode != 2) ? "" : "0 ", + divert_if.drv_to_name(cs->ics.driver), + msn, + service & 0xFF, + proc, + (mode != 1) ? "" : " 0 ", + (mode != 1) ? "" : fwd_nr); + + retval = divert_if.ll_cmd(&cs->ics); /* excute command */ + + if (!retval) + { cs->prev = NULL; + save_flags(flags); + cli(); + cs->next = divert_head; + divert_head = cs; + restore_flags(flags); + } + else + kfree(cs); + return(retval); +} /* cf_command */ + + +/****************************************/ +/* handle a external deflection command */ +/****************************************/ +int deflect_extern_action(u_char cmd, ulong callid, char *to_nr) +{ struct call_struc *cs; + isdn_ctrl ic; + int flags; + int i; + + if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */ + cs = divert_head; /* start of parameter list */ + while (cs) + { if (cs->divert_id == callid) break; /* found */ + cs = cs->next; + } /* search entry */ + if (!cs) return(-EINVAL); /* invalid callid */ + + ic.driver = cs->ics.driver; + ic.arg = cs->ics.arg; + i = -EINVAL; + if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */ + switch (cmd & 0x7F) + { case 0: /* hangup */ + del_timer(&cs->timer); + ic.command = ISDN_CMD_HANGUP; + i = divert_if.ll_cmd(&ic); + save_flags(flags); + cli(); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + add_timer(&cs->timer); + restore_flags(flags); + break; + + case 1: /* alert */ + if (cs->akt_state == DEFLECT_ALERT) return(0); + cmd &= 0x7F; /* never wait */ + del_timer(&cs->timer); + ic.command = ISDN_CMD_ALERT; + if ((i = divert_if.ll_cmd(&ic))) + { save_flags(flags); + cli(); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + add_timer(&cs->timer); + restore_flags(flags); + } + else + cs->akt_state = DEFLECT_ALERT; + break; + + case 2: /* redir */ + del_timer(&cs->timer); + strcpy(cs->ics.parm.setup.phone, to_nr); + strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual"); + ic.command = ISDN_CMD_REDIR; + if ((i = divert_if.ll_cmd(&ic))) + { save_flags(flags); + cli(); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + add_timer(&cs->timer); + restore_flags(flags); + } + else + cs->akt_state = DEFLECT_ALERT; + break; + + } /* switch */ + return(i); +} /* deflect_extern_action */ + +/********************************/ +/* insert a new rule before idx */ +/********************************/ +int insertrule(int idx, divert_rule *newrule) +{ struct deflect_struc *ds,*ds1; + int flags; + + if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc), + GFP_KERNEL))) + return(-ENOMEM); /* no memory */ + + ds->rule = *newrule; /* set rule */ + + save_flags(flags); + cli(); + + if (idx >= 0) + { ds1 = table_head; + while ((ds1) && (idx > 0)) + { idx--; + ds1 = ds1->next; + } + if (!ds1) idx = -1; + } + + if (idx < 0) + { ds->prev = table_tail; /* previous entry */ + ds->next = NULL; /* end of chain */ + if (ds->prev) + ds->prev->next = ds; /* last forward */ + else + table_head = ds; /* is first entry */ + table_tail = ds; /* end of queue */ + } + else + { ds->next = ds1; /* next entry */ + ds->prev = ds1->prev; /* prev entry */ + ds1->prev = ds; /* backward chain old element */ + if (!ds->prev) + table_head = ds; /* first element */ + } + + restore_flags(flags); + return(0); +} /* insertrule */ + +/***********************************/ +/* delete the rule at position idx */ +/***********************************/ +int deleterule(int idx) +{ struct deflect_struc *ds,*ds1; + int flags; + + if (idx < 0) + { save_flags(flags); + cli(); + ds = table_head; + table_head = NULL; + table_tail = NULL; + restore_flags(flags); + while (ds) + { ds1 = ds; + ds = ds->next; + kfree(ds1); + } + return(0); + } + + save_flags(flags); + cli(); + ds = table_head; + + while ((ds) && (idx > 0)) + { idx--; + ds = ds->next; + } + + if (!ds) + { restore_flags(flags); + return(-EINVAL); + } + + if (ds->next) + ds->next->prev = ds->prev; /* backward chain */ + else + table_tail = ds->prev; /* end of chain */ + + if (ds->prev) + ds->prev->next = ds->next; /* forward chain */ + else + table_head = ds->next; /* start of chain */ + + restore_flags(flags); + kfree(ds); + return(0); +} /* deleterule */ + +/*******************************************/ +/* get a pointer to a specific rule number */ +/*******************************************/ +divert_rule *getruleptr(int idx) +{ struct deflect_struc *ds = table_head; + + if (idx < 0) return(NULL); + while ((ds) && (idx >= 0)) + { if (!(idx--)) + { return(&ds->rule); + break; + } + ds = ds->next; + } + return(NULL); +} /* getruleptr */ + +/*************************************************/ +/* called from common module on an incoming call */ +/*************************************************/ +int isdn_divert_icall(isdn_ctrl *ic) +{ int retval = 0; + int flags; + struct call_struc *cs = NULL; + struct deflect_struc *dv; + char *p,*p1; + u_char accept; + + /* first check the internal deflection table */ + for (dv = table_head; dv ; dv = dv->next ) + { /* scan table */ + if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) || + ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL))) + continue; /* call option check */ + if (!(dv->rule.drvid & (1L << ic->driver))) + continue; /* driver not matching */ + if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1)) + continue; /* si1 not matching */ + if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2)) + continue; /* si2 not matching */ + + p = dv->rule.my_msn; + p1 = ic->parm.setup.eazmsn; + accept = 0; + while (*p) + { /* complete compare */ + if (*p == '-') + { accept = 1; /* call accepted */ + break; + } + if (*p++ != *p1++) + break; /* not accepted */ + if ((!*p) && (!*p1)) + accept = 1; + } /* complete compare */ + if (!accept) continue; /* not accepted */ + + if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0])) + { p = dv->rule.caller; + p1 = ic->parm.setup.phone; + accept = 0; + while (*p) + { /* complete compare */ + if (*p == '-') + { accept = 1; /* call accepted */ + break; + } + if (*p++ != *p1++) + break; /* not accepted */ + if ((!*p) && (!*p1)) + accept = 1; + } /* complete compare */ + if (!accept) continue; /* not accepted */ + } + + switch (dv->rule.action) + { case DEFLECT_IGNORE: + return(0); + break; + + case DEFLECT_ALERT: + case DEFLECT_PROCEED: + case DEFLECT_REPORT: + case DEFLECT_REJECT: + if (dv->rule.action == DEFLECT_PROCEED) + if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime))) + return(0); /* no external deflection needed */ + if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) + return(0); /* no memory */ + init_timer(&cs->timer); + cs->info[0] = '\0'; + cs->timer.function = deflect_timer_expire; + cs->timer.data = (ulong) cs; /* pointer to own structure */ + + cs->ics = *ic; /* copy incoming data */ + if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0"); + if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0"); + cs->ics.parm.setup.screen = dv->rule.screen; + if (dv->rule.waittime) + cs->timer.expires = jiffies + (HZ * dv->rule.waittime); + else + if (dv->rule.action == DEFLECT_PROCEED) + cs->timer.expires = jiffies + (HZ * extern_wait_max); + else + cs->timer.expires = 0; + cs->akt_state = dv->rule.action; + save_flags(flags); + cli(); + cs->divert_id = next_id++; /* new sequence number */ + restore_flags(flags); + cs->prev = NULL; + if (cs->akt_state == DEFLECT_ALERT) + { strcpy(cs->deflect_dest,dv->rule.to_nr); + if (!cs->timer.expires) + { strcpy(ic->parm.setup.eazmsn,"Testtext direkt"); + ic->parm.setup.screen = dv->rule.screen; + strcpy(ic->parm.setup.phone,dv->rule.to_nr); + cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ + cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); + retval = 4; + } + else + retval = 1; /* alerting */ + } + else + { cs->deflect_dest[0] = '\0'; + retval = 3; /* only proceed */ + } + sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", + cs->akt_state, + cs->divert_id, + divert_if.drv_to_name(cs->ics.driver), + (ic->command == ISDN_STAT_ICALLW) ? "1":"0", + cs->ics.parm.setup.phone, + cs->ics.parm.setup.eazmsn, + cs->ics.parm.setup.si1, + cs->ics.parm.setup.si2, + cs->ics.parm.setup.screen, + dv->rule.waittime, + cs->deflect_dest); + if ((dv->rule.action == DEFLECT_REPORT) || + (dv->rule.action == DEFLECT_REJECT)) + { put_info_buffer(cs->info); + kfree(cs); /* remove */ + return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */ + } + break; + + default: + return(0); /* ignore call */ + break; + } /* switch action */ + break; + } /* scan_table */ + + if (cs) + { cs->prev = NULL; + save_flags(flags); + cli(); + cs->next = divert_head; + divert_head = cs; + if (cs->timer.expires) add_timer(&cs->timer); + restore_flags(flags); + + put_info_buffer(cs->info); + return(retval); + } + else + return(0); +} /* isdn_divert_icall */ + + +void deleteprocs(void) +{ struct call_struc *cs, *cs1; + int flags; + + save_flags(flags); + cli(); + cs = divert_head; + divert_head = NULL; + while (cs) + { del_timer(&cs->timer); + cs1 = cs; + cs = cs->next; + kfree(cs1); + } + restore_flags(flags); +} /* deleteprocs */ + +/****************************************************/ +/* put a address including address type into buffer */ +/****************************************************/ +int put_address(char *st, u_char *p, int len) +{ u_char retval = 0; + u_char adr_typ = 0; /* network standard */ + + if (len < 2) return(retval); + if (*p == 0xA1) + { retval = *(++p) + 2; /* total length */ + if (retval > len) return(0); /* too short */ + len = retval - 2; /* remaining length */ + if (len < 3) return(0); + if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0); + adr_typ = *(++p); + len -= 3; + p++; + if (len < 2) return(0); + if (*p++ != 0x12) return(0); + if (*p > len) return(0); /* check number length */ + len = *p++; + } + else + if (*p == 0x80) + { retval = *(++p) + 2; /* total length */ + if (retval > len) return(0); + len = retval - 2; + p++; + } + else + return(0); /* invalid address information */ + + sprintf(st,"%d ",adr_typ); + st += strlen(st); + if (!len) + *st++ = '-'; + else + while (len--) + *st++ = *p++; + *st = '\0'; + return(retval); +} /* put_address */ + +/*************************************/ +/* report a succesfull interrogation */ +/*************************************/ +int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) +{ char *src = ic->parm.dss1_io.data; + int restlen = ic->parm.dss1_io.datalen; + int cnt = 1; + u_char n,n1; + char st[90], *p, *stp; + + if (restlen < 2) return(-100); /* frame too short */ + if (*src++ != 0x30) return(-101); + if ((n = *src++) > 0x81) return(-102); /* invalid length field */ + restlen -= 2; /* remaining bytes */ + if (n == 0x80) + { if (restlen < 2) return(-103); + if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104); + restlen -= 2; + } + else + if ( n == 0x81) + { n = *src++; + restlen--; + if (n > restlen) return(-105); + restlen = n; + } + else + if (n > restlen) return(-106); + else + restlen = n; /* standard format */ + if (restlen < 3) return(-107); /* no procedure */ + if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108); + restlen -= 3; + if (restlen < 2) return(-109); /* list missing */ + if (*src == 0x31) + { src++; + if ((n = *src++) > 0x81) return(-110); /* invalid length field */ + restlen -= 2; /* remaining bytes */ + if (n == 0x80) + { if (restlen < 2) return(-111); + if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112); + restlen -= 2; + } + else + if ( n == 0x81) + { n = *src++; + restlen--; + if (n > restlen) return(-113); + restlen = n; + } + else + if (n > restlen) return(-114); + else + restlen = n; /* standard format */ + } /* result list header */ + + while (restlen >= 2) + { stp = st; + sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id, + cnt++,divert_if.drv_to_name(ic->driver)); + stp += strlen(stp); + if (*src++ != 0x30) return(-115); /* invalid enum */ + n = *src++; + restlen -= 2; + if (n > restlen) return(-116); /* enum length wrong */ + restlen -= n; + p = src; /* one entry */ + src += n; + if (!(n1 = put_address(stp,p,n & 0xFF))) continue; + stp += strlen(stp); + p += n1; + n -= n1; + if (n < 6) continue; /* no service and proc */ + if ((*p++ != 0x0A) || (*p++ != 1)) continue; + sprintf(stp," 0x%02x ",(*p++) & 0xFF); + stp += strlen(stp); + if ((*p++ != 0x0A) || (*p++ != 1)) continue; + sprintf(stp,"%d ",(*p++) & 0xFF); + stp += strlen(stp); + n -= 6; + if (n > 2) + { if (*p++ != 0x30) continue; + if (*p > (n-2)) continue; + n = *p++; + if (!(n1 = put_address(stp,p,n & 0xFF))) continue; + stp += strlen(stp); + } + sprintf(stp,"\n"); + put_info_buffer(st); + } /* while restlen */ + if (restlen) return(-117); + return(0); +} /* interrogate_success */ + +/*********************************************/ +/* callback for protocol specific extensions */ +/*********************************************/ +int prot_stat_callback(isdn_ctrl *ic) +{ struct call_struc *cs, *cs1; + int i,flags; + + cs = divert_head; /* start of list */ + cs1 = NULL; + while (cs) + { if (ic->driver == cs->ics.driver) + { switch (cs->ics.arg) + { case DSS1_CMD_INVOKE: + if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) && + (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) + { switch (ic->arg) + { case DSS1_STAT_INVOKE_ERR: + sprintf(cs->info,"128 0x%lx 0x%x\n", + ic->parm.dss1_io.ll_id, + ic->parm.dss1_io.timeout); + put_info_buffer(cs->info); + break; + + case DSS1_STAT_INVOKE_RES: + switch (cs->ics.parm.dss1_io.proc) + { case 7: + case 8: + put_info_buffer(cs->info); + break; + + case 11: + i = interrogate_success(ic,cs); + if (i) + sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT, + ic->parm.dss1_io.ll_id,i); + put_info_buffer(cs->info); + break; + + default: + printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc); + break; + } + + +#if 0 + sprintf(st, "0x%lx 0x%lx",ic->arg, ic->parm.dss1_io.ll_id); + p = st + strlen(st); + p1 = ic->parm.dss1_io.data; + i = ic->parm.dss1_io.datalen; + while ((i > 0) && (p - st < 530)) + { p += sprintf(p," %02x",(*p1++) & 0xFF); + i--; + } + sprintf(p, "\n"); + put_info_buffer(st); +#endif + break; + + default: + printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg); + break; + } + cs1 = cs; /* remember structure */ + cs = NULL; + continue; /* abort search */ + } /* id found */ + break; + + case DSS1_CMD_INVOKE_ABORT: + printk(KERN_WARNING "dss1_divert unhandled invoke abort\n"); + break; + + default: + printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg); + break; + } /* switch ics.arg */ + cs = cs->next; + } /* driver ok */ + } + + if (!cs1) + { printk(KERN_WARNING "dss1_divert unhandled process\n"); + return(0); + } + + if (cs1->ics.driver == -1) + { save_flags(flags); + cli(); + del_timer(&cs1->timer); + if (cs1->prev) + cs1->prev->next = cs1->next; /* forward link */ + else + divert_head = cs1->next; + if (cs1->next) + cs1->next->prev = cs1->prev; /* back link */ + restore_flags(flags); + kfree(cs1); + } + + return(0); +} /* prot_stat_callback */ + + +/***************************/ +/* status callback from HL */ +/***************************/ +int isdn_divert_stat_callback(isdn_ctrl *ic) +{ struct call_struc *cs, *cs1; + int flags, retval; + + retval = -1; + cs = divert_head; /* start of list */ + while (cs) + { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg)) + { switch (ic->command) + { case ISDN_STAT_DHUP: + sprintf(cs->info,"129 0x%lx\n",cs->divert_id); + del_timer(&cs->timer); + cs->ics.driver = -1; + break; + + case ISDN_STAT_CAUSE: + sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num); + break; + + case ISDN_STAT_REDIR: + sprintf(cs->info,"131 0x%lx\n",cs->divert_id); + del_timer(&cs->timer); + cs->ics.driver = -1; + break; + + default: + sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command)); + break; + } + put_info_buffer(cs->info); + retval = 0; + } + cs1 = cs; + cs = cs->next; + if (cs1->ics.driver == -1) + { + save_flags(flags); + cli(); + if (cs1->prev) + cs1->prev->next = cs1->next; /* forward link */ + else + divert_head = cs1->next; + if (cs1->next) + cs1->next->prev = cs1->prev; /* back link */ + restore_flags(flags); + kfree(cs1); + } + } + return(retval); /* not found */ +} /* isdn_divert_stat_callback */ + + +/********************/ +/* callback from ll */ +/********************/ +int ll_callback(isdn_ctrl *ic) +{ + switch (ic->command) + { case ISDN_STAT_ICALL: + case ISDN_STAT_ICALLW: + return(isdn_divert_icall(ic)); + break; + + case ISDN_STAT_PROT: + if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) + { if (ic->arg != DSS1_STAT_INVOKE_BRD) + return(prot_stat_callback(ic)); + else + return(0); /* DSS1 invoke broadcast */ + } + else + return(-1); /* protocol not euro */ + + default: + return(isdn_divert_stat_callback(ic)); + } +} /* ll_callback */ + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/divert/isdn_divert.h linux/drivers/isdn/divert/isdn_divert.h --- v2.2.10/linux/drivers/isdn/divert/isdn_divert.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/divert/isdn_divert.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,159 @@ +/* + * $Id: isdn_divert.h,v 1.2 1999/07/04 21:37:33 werner Exp $ + * + * Header for the diversion supplementary ioctl interface. + * + * Copyright 1998 by Werner Cornelius (werner@ikt.de) + * + * 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, 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. + * + * $Log: isdn_divert.h,v $ + * Revision 1.2 1999/07/04 21:37:33 werner + * Ported from kernel version 2.0 + * + * + * + */ + + + +#include +#include +#include + +/******************************************/ +/* IOCTL codes for interface to user prog */ +/******************************************/ +#define DIVERT_IIOC_VERSION 0x01 /* actual version */ +#define IIOCGETVER _IO('I', 1) /* get version of interface */ +#define IIOCGETDRV _IO('I', 2) /* get driver number */ +#define IIOCGETNAM _IO('I', 3) /* get driver name */ +#define IIOCGETRULE _IO('I', 4) /* read one rule */ +#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */ +#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */ +#define IIOCDELRULE _IO('I', 7) /* delete a rule */ +#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */ +#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */ +#define IIOCDOCFDIS _IO('I',10) /* deactivate control forwarding in PBX */ +#define IIOCDOCFINT _IO('I',11) /* interrogate control forwarding in PBX */ + +/*************************************/ +/* states reported through interface */ +/*************************************/ +#define DEFLECT_IGNORE 0 /* ignore incoming call */ +#define DEFLECT_REPORT 1 /* only report */ +#define DEFLECT_PROCEED 2 /* deflect when externally triggered */ +#define DEFLECT_ALERT 3 /* alert and deflect after delay */ +#define DEFLECT_REJECT 4 /* reject immediately */ +#define DIVERT_ACTIVATE 5 /* diversion activate */ +#define DIVERT_DEACTIVATE 6 /* diversion deactivate */ +#define DIVERT_REPORT 7 /* interrogation result */ +#define DEFLECT_AUTODEL 255 /* only for internal use */ + +#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */ + +typedef struct + { ulong drvid; /* driver ids, bit mapped */ + char my_msn[35]; /* desired msn, subaddr allowed */ + char caller[35]; /* caller id, partial string with * + subaddr allowed */ + char to_nr[35]; /* deflected to number incl. subaddress */ + u_char si1,si2; /* service indicators, si1=bitmask, si1+2 0 = all */ + u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */ + u_char callopt; /* option for call handling: + 0 = all calls + 1 = only non waiting calls + 2 = only waiting calls */ + u_char action; /* desired action: + 0 = don't report call -> ignore + 1 = report call, do not allow/proceed for deflection + 2 = report call, send proceed, wait max waittime secs + 3 = report call, alert and deflect after waittime + 4 = report call, reject immediately + actions 1-2 only take place if interface is opened + */ + u_char waittime; /* maximum wait time for proceeding */ + } divert_rule; + +typedef union + { int drv_version; /* return of driver version */ + struct + { int drvid; /* id of driver */ + char drvnam[30]; /* name of driver */ + } getid; + struct + { int ruleidx; /* index of rule */ + divert_rule rule; /* rule parms */ + } getsetrule; + struct + { u_char subcmd; /* 0 = hangup/reject, + 1 = alert, + 2 = deflect */ + ulong callid; /* id of call delivered by ascii output */ + char to_nr[35]; /* destination when deflect, + else uus1 string (maxlen 31), + data from rule used if empty */ + } fwd_ctrl; + struct + { int drvid; /* id of driver */ + u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */ + ulong procid; /* process id returned when no error */ + u_char service; /* basically coded service, 0 = all */ + char msn[25]; /* desired msn, empty = all */ + char fwd_nr[35];/* forwarded to number + subaddress */ + } cf_ctrl; + } divert_ioctl; + +#ifdef __KERNEL__ + +#include +#include + +#define AUTODEL_TIME 30 /* timeout in s to delete internal entrys */ + +/**************************************************/ +/* structure keeping ascii info for device output */ +/**************************************************/ +struct divert_info + { struct divert_info *next; + ulong usage_cnt; /* number of files still to work */ + char info_start[2]; /* info string start */ + }; + + +/**************/ +/* Prototypes */ +/**************/ +extern ulong if_used; /* number of interface users */ +extern int divert_dev_deinit(void); +extern int divert_dev_init(void); +extern void put_info_buffer(char *); +extern int ll_callback(isdn_ctrl *); +extern isdn_divert_if divert_if; +extern divert_rule *getruleptr(int); +extern int insertrule(int, divert_rule *); +extern int deleterule(int); +extern void deleteprocs(void); +extern int deflect_extern_action(u_char, ulong, char *); +extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *); + +#endif __KERNEL__ + + + + + + + + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile --- v2.2.10/linux/drivers/isdn/eicon/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/Makefile Mon Aug 9 12:04:39 1999 @@ -0,0 +1,13 @@ +L_OBJS := +M_OBJS := +O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o + +O_TARGET := +ifeq ($(CONFIG_ISDN_DRV_EICON),y) + O_TARGET += eicon.o +else + O_TARGET += eicon.o + M_OBJS = eicon.o +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.2.10/linux/drivers/isdn/eicon/eicon.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,544 @@ +/* $Id: eicon.h,v 1.7 1999/07/11 17:16:23 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * + * Copyright 1998 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon.h,v $ + * Revision 1.7 1999/07/11 17:16:23 armin + * Bugfixes in queue handling. + * Added DSP-DTMF decoder functions. + * Reorganized ack_handler. + * + * Revision 1.6 1999/06/09 19:31:24 armin + * Wrong PLX size for request_region() corrected. + * Added first MCA code from Erik Weber. + * + * Revision 1.5 1999/03/29 11:19:41 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.4 1999/03/02 12:37:42 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.3 1999/01/24 20:14:07 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.2 1999/01/10 18:46:04 armin + * Bug with wrong values in HLC fixed. + * Bytes to send are counted and limited now. + * + * Revision 1.1 1999/01/01 18:09:41 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + + +#ifndef eicon_h +#define eicon_h + +#define EICON_IOCTL_SETMMIO 0 +#define EICON_IOCTL_GETMMIO 1 +#define EICON_IOCTL_SETIRQ 2 +#define EICON_IOCTL_GETIRQ 3 +#define EICON_IOCTL_LOADBOOT 4 +#define EICON_IOCTL_ADDCARD 5 +#define EICON_IOCTL_GETTYPE 6 +#define EICON_IOCTL_LOADPCI 7 +#define EICON_IOCTL_LOADISA 8 +#define EICON_IOCTL_GETVER 9 + +#define EICON_IOCTL_MANIF 90 + +#define EICON_IOCTL_FREEIT 97 +#define EICON_IOCTL_TEST 98 +#define EICON_IOCTL_DEBUGVAR 99 + +/* Bus types */ +#define EICON_BUS_ISA 1 +#define EICON_BUS_MCA 2 +#define EICON_BUS_PCI 3 + +/* Constants for describing Card-Type */ +#define EICON_CTYPE_S 0 +#define EICON_CTYPE_SX 1 +#define EICON_CTYPE_SCOM 2 +#define EICON_CTYPE_QUADRO 3 +#define EICON_CTYPE_S2M 4 +#define EICON_CTYPE_MAESTRA 5 +#define EICON_CTYPE_MAESTRAQ 6 +#define EICON_CTYPE_MAESTRAQ_U 7 +#define EICON_CTYPE_MAESTRAP 8 +#define EICON_CTYPE_ISABRI 0x10 +#define EICON_CTYPE_ISAPRI 0x20 +#define EICON_CTYPE_MASK 0x0f +#define EICON_CTYPE_QUADRO_NR(n) (n<<4) + +#define MAX_HEADER_LEN 10 + +/* Struct for adding new cards */ +typedef struct eicon_cdef { + int membase; + int irq; + char id[10]; +} eicon_cdef; + +#define EICON_ISA_BOOT_MEMCHK 1 +#define EICON_ISA_BOOT_NORMAL 2 + +/* Struct for downloading protocol via ioctl for ISA cards */ +/* same struct for downloading protocol via ioctl for MCA cards */ +typedef struct { + /* start-up parameters */ + unsigned char tei; + unsigned char nt2; + unsigned char skip1; + unsigned char WatchDog; + unsigned char Permanent; + unsigned char XInterface; + unsigned char StableL2; + unsigned char NoOrderCheck; + unsigned char HandsetType; + unsigned char skip2; + unsigned char LowChannel; + unsigned char ProtVersion; + unsigned char Crc4; + unsigned char Loopback; + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + unsigned char boot_opt; + unsigned long bootstrap_len; + unsigned long firmware_len; + unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */ +} eicon_isa_codebuf; + +/* Struct for downloading protocol via ioctl for PCI cards */ +typedef struct { + /* start-up parameters */ + unsigned char tei; + unsigned char nt2; + unsigned char WatchDog; + unsigned char Permanent; + unsigned char XInterface; + unsigned char StableL2; + unsigned char NoOrderCheck; + unsigned char HandsetType; + unsigned char LowChannel; + unsigned char ProtVersion; + unsigned char Crc4; + unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */ + unsigned char Loopback; /* switch card into Loopback mode */ + struct q931_link_s + { + unsigned char oad[32]; + unsigned char osa[32]; + unsigned char spid[32]; + } l[2]; + unsigned long protocol_len; + unsigned int dsp_code_num; + unsigned long dsp_code_len[9]; + unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */ +} eicon_pci_codebuf; + +/* Data for downloading protocol via ioctl */ +typedef union { + eicon_isa_codebuf isa; + eicon_isa_codebuf mca; + eicon_pci_codebuf pci; +} eicon_codebuf; + +/* Data for Management interface */ +typedef struct { + int count; + int pos; + int length[50]; + unsigned char data[700]; +} eicon_manifbuf; + + +#ifdef __KERNEL__ + +/* Kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct { + __u16 length __attribute__ ((packed)); /* length of data/parameter field */ + __u8 P[1]; /* data/parameter field */ +} eicon_PBUFFER; + +#include "eicon_isa.h" + +/* Macro for delay via schedule() */ +#define SLEEP(j) { \ + current->state = TASK_INTERRUPTIBLE; \ + schedule_timeout(j); \ +} + +#endif /* KERNEL */ + + +#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 + +#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48 +#define DSP_FILE_FORMAT_VERSION_BCD 0x0100 + +typedef struct tag_dsp_combifile_header +{ + char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); + __u16 format_version_bcd __attribute__ ((packed)); + __u16 header_size __attribute__ ((packed)); + __u16 combifile_description_size __attribute__ ((packed)); + __u16 directory_entries __attribute__ ((packed)); + __u16 directory_size __attribute__ ((packed)); + __u16 download_count __attribute__ ((packed)); + __u16 usage_mask_size __attribute__ ((packed)); +} t_dsp_combifile_header; + +typedef struct tag_dsp_combifile_directory_entry +{ + __u16 card_type_number __attribute__ ((packed)); + __u16 file_set_number __attribute__ ((packed)); +} t_dsp_combifile_directory_entry; + +typedef struct tag_dsp_file_header +{ + char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed)); + __u16 format_version_bcd __attribute__ ((packed)); + __u16 download_id __attribute__ ((packed)); + __u16 download_flags __attribute__ ((packed)); + __u16 required_processing_power __attribute__ ((packed)); + __u16 interface_channel_count __attribute__ ((packed)); + __u16 header_size __attribute__ ((packed)); + __u16 download_description_size __attribute__ ((packed)); + __u16 memory_block_table_size __attribute__ ((packed)); + __u16 memory_block_count __attribute__ ((packed)); + __u16 segment_table_size __attribute__ ((packed)); + __u16 segment_count __attribute__ ((packed)); + __u16 symbol_table_size __attribute__ ((packed)); + __u16 symbol_count __attribute__ ((packed)); + __u16 total_data_size_dm __attribute__ ((packed)); + __u16 data_block_count_dm __attribute__ ((packed)); + __u16 total_data_size_pm __attribute__ ((packed)); + __u16 data_block_count_pm __attribute__ ((packed)); +} t_dsp_file_header; + +typedef struct tag_dsp_memory_block_desc +{ + __u16 alias_memory_block; + __u16 memory_type; + __u16 address; + __u16 size; /* DSP words */ +} t_dsp_memory_block_desc; + +typedef struct tag_dsp_segment_desc +{ + __u16 memory_block; + __u16 attributes; + __u16 base; + __u16 size; + __u16 alignment; /* ==0 -> no other legal start address than base */ +} t_dsp_segment_desc; + +typedef struct tag_dsp_symbol_desc +{ + __u16 symbol_id; + __u16 segment; + __u16 offset; + __u16 size; /* DSP words */ +} t_dsp_symbol_desc; + +typedef struct tag_dsp_data_block_header +{ + __u16 attributes; + __u16 segment; + __u16 offset; + __u16 size; /* DSP words */ +} t_dsp_data_block_header; + +typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */ +{ + __u16 download_id; + __u16 download_flags; + __u16 required_processing_power; + __u16 interface_channel_count; + __u16 excess_header_size; + __u16 memory_block_count; + __u16 segment_count; + __u16 symbol_count; + __u16 data_block_count_dm; + __u16 data_block_count_pm; + __u8 * p_excess_header_data __attribute__ ((packed)); + char * p_download_description __attribute__ ((packed)); + t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed)); + t_dsp_segment_desc *p_segment_table __attribute__ ((packed)); + t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed)); + __u16 * p_data_blocks_dm __attribute__ ((packed)); + __u16 * p_data_blocks_pm __attribute__ ((packed)); +} t_dsp_download_desc; + + +#ifdef __KERNEL__ + +typedef struct { + __u8 Req; /* pending request */ + __u8 Rc; /* return code received */ + __u8 Ind; /* indication received */ + __u8 ReqCh; /* channel of current Req */ + __u8 RcCh; /* channel of current Rc */ + __u8 IndCh; /* channel of current Ind */ + __u8 D3Id; /* ID used by this entity */ + __u8 B2Id; /* ID used by this entity */ + __u8 GlobalId; /* reserved field */ + __u8 XNum; /* number of X-buffers */ + __u8 RNum; /* number of R-buffers */ + struct sk_buff_head X; /* X-buffer queue */ + struct sk_buff_head R; /* R-buffer queue */ + __u8 RNR; /* receive not ready flag */ + __u8 complete; /* receive complete status */ + __u8 busy; /* busy flag */ + __u16 ref; /* saved reference */ +} entity; + + +typedef struct { + int No; /* Channel Number */ + unsigned short callref; /* Call Reference */ + unsigned short fsm_state; /* Current D-Channel state */ + unsigned short eazmask; /* EAZ-Mask for this Channel */ + int queued; /* User-Data Bytes in TX queue */ + int waitq; /* User-Data Bytes in wait queue */ + int waitpq; /* User-Data Bytes in packet queue */ + unsigned short plci; + unsigned short ncci; + unsigned char l2prot; /* Layer 2 protocol */ + unsigned char l3prot; /* Layer 3 protocol */ + entity e; /* Entity */ + char cpn[32]; /* remember cpn */ + char oad[32]; /* remember oad */ + unsigned char cause[2]; /* Last Cause */ + unsigned char si1; + unsigned char si2; +} eicon_chan; + +typedef struct { + eicon_chan *ptr; +} eicon_chan_ptr; + +#include "eicon_pci.h" + +#define EICON_FLAGS_RUNNING 1 /* Cards driver activated */ +#define EICON_FLAGS_PVALID 2 /* Cards port is valid */ +#define EICON_FLAGS_IVALID 4 /* Cards irq is valid */ +#define EICON_FLAGS_MVALID 8 /* Cards membase is valid */ +#define EICON_FLAGS_LOADED 8 /* Firmware loaded */ + +#define EICON_BCH 2 /* # of channels per card */ + +/* D-Channel states */ +#define EICON_STATE_NULL 0 +#define EICON_STATE_ICALL 1 +#define EICON_STATE_OCALL 2 +#define EICON_STATE_IWAIT 3 +#define EICON_STATE_OWAIT 4 +#define EICON_STATE_IBWAIT 5 +#define EICON_STATE_OBWAIT 6 +#define EICON_STATE_BWAIT 7 +#define EICON_STATE_BHWAIT 8 +#define EICON_STATE_BHWAIT2 9 +#define EICON_STATE_DHWAIT 10 +#define EICON_STATE_DHWAIT2 11 +#define EICON_STATE_BSETUP 12 +#define EICON_STATE_ACTIVE 13 +#define EICON_STATE_ICALLW 14 +#define EICON_STATE_LISTEN 15 +#define EICON_STATE_WMCONN 16 + +#define EICON_MAX_QUEUED 8000 /* 2 * maxbuff */ + +#define EICON_LOCK_TX 0 +#define EICON_LOCK_RX 1 + +typedef union { + eicon_isa_card isa; + eicon_pci_card pci; + eicon_isa_card mca; +} eicon_hwif; + +typedef struct { + __u8 ret; + __u8 id; + __u8 ch; +} eicon_ack; + +typedef struct { + __u8 code; + __u8 id; + __u8 ch; +} eicon_req; + +typedef struct { + __u8 ret; + __u8 id; + __u8 ch; + __u8 more; +} eicon_indhdr; + +typedef struct msn_entry { + char eaz; + char msn[16]; + struct msn_entry * next; +} msn_entry; + +/* + * Per card driver data + */ +typedef struct eicon_card { + eicon_hwif hwif; /* Hardware dependant interface */ + u_char ptype; /* Protocol type (1TR6 or Euro) */ + u_char bus; /* Bustype (ISA, MCA, PCI) */ + u_char type; /* Cardtype (EICON_CTYPE_...) */ + struct eicon_card *qnext; /* Pointer to next quadro adapter */ + int Feature; /* Protocol Feature Value */ + struct eicon_card *next; /* Pointer to next device struct */ + int myid; /* Driver-Nr. assigned by linklevel */ + unsigned long flags; /* Statusflags */ + unsigned long ilock; /* Semaphores for IRQ-Routines */ + struct sk_buff_head rcvq; /* Receive-Message queue */ + struct sk_buff_head sndq; /* Send-Message queue */ + struct sk_buff_head rackq; /* Req-Ack-Message queue */ + struct sk_buff_head sackq; /* Data-Ack-Message queue */ + u_char *ack_msg; /* Ptr to User Data in User skb */ + __u16 need_b3ack; /* Flag: Need ACK for current skb */ + struct sk_buff *sbuf; /* skb which is currently sent */ + struct tq_struct snd_tq; /* Task struct for xmit bh */ + struct tq_struct rcv_tq; /* Task struct for rcv bh */ + struct tq_struct ack_tq; /* Task struct for ack bh */ + msn_entry *msn_list; + unsigned short msgnum; /* Message number for sending */ + eicon_chan* IdTable[256]; /* Table to find entity */ + __u16 ref_in; + __u16 ref_out; + int nchannels; /* Number of B-Channels */ + int ReadyInt; /* Ready Interrupt */ + eicon_chan *bch; /* B-Channel status/control */ + char status_buf[256]; /* Buffer for status messages */ + char *status_buf_read; + char *status_buf_write; + char *status_buf_end; + isdn_if interface; /* Interface to upper layer */ + char regname[35]; /* Name used for request_region */ +#ifdef CONFIG_MCA + int mca_slot; /* # of cards MCA slot */ +#endif +} eicon_card; + +/* -----------------------------------------------------------** +** The PROTOCOL_FEATURE_STRING ** +** defines capabilities and ** +** features of the actual protocol code. It's used as a bit ** +** mask. ** +** The following Bits are defined: ** +** -----------------------------------------------------------*/ +#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */ +#define PROTCAP_MANIF 0x0002 /* Management interface implemented */ +#define PROTCAP_V_42 0x0004 /* V42 implemented */ +#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */ +#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */ +#define PROTCAP_FREE4 0x0020 /* not used */ +#define PROTCAP_FREE5 0x0040 /* not used */ +#define PROTCAP_FREE6 0x0080 /* not used */ +#define PROTCAP_FREE7 0x0100 /* not used */ +#define PROTCAP_FREE8 0x0200 /* not used */ +#define PROTCAP_FREE9 0x0400 /* not used */ +#define PROTCAP_FREE10 0x0800 /* not used */ +#define PROTCAP_FREE11 0x1000 /* not used */ +#define PROTCAP_FREE12 0x2000 /* not used */ +#define PROTCAP_FREE13 0x4000 /* not used */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ + +#include "eicon_idi.h" + +extern eicon_card *cards; +extern char *eicon_ctype_name[]; + + +extern __inline__ void eicon_schedule_tx(eicon_card *card) +{ + queue_task(&card->snd_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +extern __inline__ void eicon_schedule_rx(eicon_card *card) +{ + queue_task(&card->rcv_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +extern __inline__ void eicon_schedule_ack(eicon_card *card) +{ + queue_task(&card->ack_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +extern char *eicon_find_eaz(eicon_card *, char); +extern int eicon_addcard(int, int, int, char *); +extern void eicon_io_transmit(eicon_card *card); +extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); +extern void eicon_io_rcv_dispatch(eicon_card *ccard); +extern void eicon_io_ack_dispatch(eicon_card *ccard); +#ifdef CONFIG_MCA +extern int eicon_mca_find_card(int, int, int, char *); +extern int eicon_mca_probe(int, int, int, int, char *); +extern int eicon_info(char *, int , void *); +#endif /* CONFIG_MCA */ + +extern ulong DebugVar; + +#endif /* __KERNEL__ */ + +#endif /* eicon_h */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_dsp.h linux/drivers/isdn/eicon/eicon_dsp.h --- v2.2.10/linux/drivers/isdn/eicon/eicon_dsp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_dsp.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,313 @@ +/* $Id: eicon_dsp.h,v 1.3 1999/07/11 17:16:24 armin Exp $ + * + * ISDN lowlevel-module for Eicon.Diehl active cards. + * DSP definitions + * + * Copyright 1999 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_dsp.h,v $ + * Revision 1.3 1999/07/11 17:16:24 armin + * Bugfixes in queue handling. + * Added DSP-DTMF decoder functions. + * Reorganized ack_handler. + * + * Revision 1.2 1999/03/29 11:19:42 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.1 1999/03/02 12:18:54 armin + * First checkin of DSP defines for audio features. + * + * + */ + +#ifndef DSP_H +#define DSP_H + +#define DSP_UDATA_REQUEST_RECONFIGURE 0 +/* +parameters: + reconfigure delay (in 8kHz samples) + reconfigure code + reconfigure hdlc preamble flags +*/ + +#define DSP_RECONFIGURE_TX_FLAG 0x8000 +#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000 +#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000 +#define DSP_RECONFIGURE_HDLC_FLAG 0x1000 +#define DSP_RECONFIGURE_SYNC_FLAG 0x0800 +#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff +#define DSP_RECONFIGURE_IDLE 0 +#define DSP_RECONFIGURE_V25 1 +#define DSP_RECONFIGURE_V21_CH2 2 +#define DSP_RECONFIGURE_V27_2400 3 +#define DSP_RECONFIGURE_V27_4800 4 +#define DSP_RECONFIGURE_V29_7200 5 +#define DSP_RECONFIGURE_V29_9600 6 +#define DSP_RECONFIGURE_V33_12000 7 +#define DSP_RECONFIGURE_V33_14400 8 +#define DSP_RECONFIGURE_V17_7200 9 +#define DSP_RECONFIGURE_V17_9600 10 +#define DSP_RECONFIGURE_V17_12000 11 +#define DSP_RECONFIGURE_V17_14400 12 + +/* +data indications if transparent framer + data 0 + data 1 + ... + +data indications if HDLC framer + data 0 + data 1 + ... + CRC 0 + CRC 1 + preamble flags +*/ + +#define DSP_UDATA_REQUEST_SWITCH_FRAMER 1 +/* +parameters: + transmit framer type + receive framer type +*/ + +#define DSP_REQUEST_SWITCH_FRAMER_HDLC 0 +#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT 1 +#define DSP_REQUEST_SWITCH_FRAMER_ASYNC 2 + + +#define DSP_UDATA_REQUEST_CLEARDOWN 2 +/* +parameters: + - none - +*/ + + +#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON 3 +/* +parameters: + - none - +*/ + + +#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF 4 +/* +parameters: + - none - +*/ + + +#define DSP_UDATA_INDICATION_SYNC 0 +/* +returns: + time of sync (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_OFF 1 +/* +returns: + time of DCD off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_DCD_ON 2 +/* +returns: + time of DCD on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s, max of tx and rx speed) + roundtrip delay (ms) + connected speed tx (bit/s) + connected speed rx (bit/s) +*/ + +#define DSP_UDATA_INDICATION_CTS_OFF 3 +/* +returns: + time of CTS off (sampled from counter at 8kHz) +*/ + +#define DSP_UDATA_INDICATION_CTS_ON 4 +/* +returns: + time of CTS on (sampled from counter at 8kHz) + connected norm + connected options + connected speed (bit/s, max of tx and rx speed) + roundtrip delay (ms) + connected speed tx (bit/s) + connected speed rx (bit/s) +*/ + +typedef struct eicon_dsp_ind { + __u16 time __attribute__ ((packed)); + __u8 norm __attribute__ ((packed)); + __u16 options __attribute__ ((packed)); + __u32 speed __attribute__ ((packed)); + __u16 delay __attribute__ ((packed)); + __u32 txspeed __attribute__ ((packed)); + __u32 rxspeed __attribute__ ((packed)); +} eicon_dsp_ind; + +#define DSP_CONNECTED_NORM_UNSPECIFIED 0 +#define DSP_CONNECTED_NORM_V21 1 +#define DSP_CONNECTED_NORM_V23 2 +#define DSP_CONNECTED_NORM_V22 3 +#define DSP_CONNECTED_NORM_V22_BIS 4 +#define DSP_CONNECTED_NORM_V32_BIS 5 +#define DSP_CONNECTED_NORM_V34 6 +#define DSP_CONNECTED_NORM_V8 7 +#define DSP_CONNECTED_NORM_BELL_212A 8 +#define DSP_CONNECTED_NORM_BELL_103 9 +#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10 +#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11 +#define DSP_CONNECTED_NORM_V90 12 +#define DSP_CONNECTED_NORM_V21_CH2 13 +#define DSP_CONNECTED_NORM_V27_TER 14 +#define DSP_CONNECTED_NORM_V29 15 +#define DSP_CONNECTED_NORM_V33 16 +#define DSP_CONNECTED_NORM_V17 17 + +#define DSP_CONNECTED_OPTION_TRELLIS 0x0001 +#define DSP_CONNECTED_OPTION_V42_TRANS 0x0002 +#define DSP_CONNECTED_OPTION_V42_LAPM 0x0004 +#define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008 +#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010 + + +#define DSP_UDATA_INDICATION_DISCONNECT 5 +/* +returns: + cause +*/ + +#define DSP_DISCONNECT_CAUSE_NONE 0x00 +#define DSP_DISCONNECT_CAUSE_BUSY_TONE 0x01 +#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE 0x02 +#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY 0x03 +#define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04 +#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05 + + +#define DSP_UDATA_INDICATION_TX_CONFIRMATION 6 +/* +returns: + confirmation number +*/ + + +#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS 16 +/* +parameters: + tone duration (ms) + gap duration (ms) + digit 0 tone code + ... + digit n tone code +*/ + +#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH 5 + +#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ 0x00 +#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ 0x01 +#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ 0x02 +#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ 0x03 +#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK 0x03 +#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ 0x00 +#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ 0x04 +#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ 0x08 +#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ 0x0c +#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK 0x0c + +#define DSP_DTMF_DIGIT_TONE_CODE_0 0x07 +#define DSP_DTMF_DIGIT_TONE_CODE_1 0x00 +#define DSP_DTMF_DIGIT_TONE_CODE_2 0x04 +#define DSP_DTMF_DIGIT_TONE_CODE_3 0x08 +#define DSP_DTMF_DIGIT_TONE_CODE_4 0x01 +#define DSP_DTMF_DIGIT_TONE_CODE_5 0x05 +#define DSP_DTMF_DIGIT_TONE_CODE_6 0x09 +#define DSP_DTMF_DIGIT_TONE_CODE_7 0x02 +#define DSP_DTMF_DIGIT_TONE_CODE_8 0x06 +#define DSP_DTMF_DIGIT_TONE_CODE_9 0x0a +#define DSP_DTMF_DIGIT_TONE_CODE_STAR 0x03 +#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK 0x0b +#define DSP_DTMF_DIGIT_TONE_CODE_A 0x0c +#define DSP_DTMF_DIGIT_TONE_CODE_B 0x0d +#define DSP_DTMF_DIGIT_TONE_CODE_C 0x0e +#define DSP_DTMF_DIGIT_TONE_CODE_D 0x0f + + +#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT 16 +/* +returns: + - none - + One indication will be sent for every request. +*/ + + +#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER 17 +/* +parameters: + tone duration (ms) + gap duration (ms) +*/ +typedef struct enable_dtmf_s { + __u16 tone; + __u16 gap; +} enable_dtmf_s; + +#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18 +/* +parameters: + - none - +*/ + +#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17 +/* +returns: + digit 0 tone code + ... + digit n tone code +*/ + +#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH 1 + + +#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18 +/* +returns: + - none - +*/ + +#define DSP_UDATA_INDICATION_FAX_CALLING_TONE 19 +/* +returns: + - none - +*/ + +#define DSP_UDATA_INDICATION_ANSWER_TONE 20 +/* +returns: + - none - +*/ + +#endif /* DSP_H */ + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.2.10/linux/drivers/isdn/eicon/eicon_idi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_idi.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1638 @@ +/* $Id: eicon_idi.c,v 1.10 1999/07/11 17:16:24 armin Exp $ + * + * ISDN lowlevel-module for Eicon.Diehl active cards. + * IDI interface + * + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_idi.c,v $ + * Revision 1.10 1999/07/11 17:16:24 armin + * Bugfixes in queue handling. + * Added DSP-DTMF decoder functions. + * Reorganized ack_handler. + * + * Revision 1.9 1999/03/29 11:19:42 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.8 1999/03/02 12:37:43 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.7 1999/02/03 18:34:35 armin + * Channel selection for outgoing calls w/o CHI. + * Added channel # in debug messages. + * L2 Transparent should work with 800 byte/packet now. + * + * Revision 1.6 1999/01/26 07:18:59 armin + * Bug with wrong added CPN fixed. + * + * Revision 1.5 1999/01/24 20:14:11 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.4 1999/01/10 18:46:05 armin + * Bug with wrong values in HLC fixed. + * Bytes to send are counted and limited now. + * + * Revision 1.3 1999/01/05 14:49:34 armin + * Added experimental usage of full BC and HLC for + * speech, 3.1kHz audio, fax gr.2/3 + * + * Revision 1.2 1999/01/04 13:19:29 armin + * Channel status with listen-request wrong - fixed. + * + * Revision 1.1 1999/01/01 18:09:41 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#define __NO_VERSION__ +#include "eicon.h" +#include "eicon_idi.h" +#include "eicon_dsp.h" + +#undef EICON_FULL_SERVICE_OKTETT + +char *eicon_idi_revision = "$Revision: 1.10 $"; + +eicon_manifbuf *manbuf; + +static char BC_Speech[3] = { 0x80, 0x90, 0xa3 }; +static char BC_31khz[3] = { 0x90, 0x90, 0xa3 }; +static char BC_64k[2] = { 0x88, 0x90 }; +static char BC_video[3] = { 0x91, 0x90, 0xa5 }; + +#ifdef EICON_FULL_SERVICE_OKTETT +/* +static char HLC_telephony[2] = { 0x91, 0x81 }; +*/ +static char HLC_faxg3[2] = { 0x91, 0x84 }; +#endif + +int eicon_idi_manage_assign(eicon_card *card); +int eicon_idi_manage_remove(eicon_card *card); + +int +idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan) +{ + int l = 0; + int tmp; + + tmp = 0; + if (!signet) { + /* Signal Layer */ + reqbuf->XBuffer.P[l++] = CAI; + reqbuf->XBuffer.P[l++] = 1; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = KEY; + reqbuf->XBuffer.P[l++] = 3; + reqbuf->XBuffer.P[l++] = 'I'; + reqbuf->XBuffer.P[l++] = '4'; + reqbuf->XBuffer.P[l++] = 'L'; + reqbuf->XBuffer.P[l++] = SHIFT|6; + reqbuf->XBuffer.P[l++] = SIN; + reqbuf->XBuffer.P[l++] = 2; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = 0; /* end */ + reqbuf->Req = ASSIGN; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 0; + reqbuf->XBuffer.length = l; + reqbuf->Reference = 0; /* Sig Entity */ + } + else { + /* Network Layer */ + reqbuf->XBuffer.P[l++] = CAI; + reqbuf->XBuffer.P[l++] = 1; + reqbuf->XBuffer.P[l++] = chan->e.D3Id; + reqbuf->XBuffer.P[l++] = LLC; + reqbuf->XBuffer.P[l++] = 2; + switch(chan->l2prot) { + case ISDN_PROTO_L2_HDLC: + reqbuf->XBuffer.P[l++] = 2; + break; + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + reqbuf->XBuffer.P[l++] = 5; + break; + case ISDN_PROTO_L2_TRANS: + case ISDN_PROTO_L2_MODEM: + reqbuf->XBuffer.P[l++] = 2; + break; + default: + reqbuf->XBuffer.P[l++] = 1; + } + switch(chan->l3prot) { + case ISDN_PROTO_L3_TRANS: + default: + reqbuf->XBuffer.P[l++] = 4; + } + reqbuf->XBuffer.P[l++] = 0; /* end */ + reqbuf->Req = ASSIGN; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 0x20; + reqbuf->XBuffer.length = l; + reqbuf->Reference = 1; /* Net Entity */ + } + return(0); +} + +int +idi_put_req(eicon_REQ *reqbuf, int rq, int signet) +{ + reqbuf->Req = rq; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.length = 1; + reqbuf->XBuffer.P[0] = 0; + reqbuf->Reference = signet; + return(0); +} + +int +idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) +{ + int l = 9; + reqbuf->Req = CALL_RES; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.P[0] = CAI; + reqbuf->XBuffer.P[1] = 6; + reqbuf->XBuffer.P[2] = 9; + reqbuf->XBuffer.P[3] = 0; + reqbuf->XBuffer.P[4] = 0; + reqbuf->XBuffer.P[5] = 0; + reqbuf->XBuffer.P[6] = 32; + reqbuf->XBuffer.P[7] = 3; + switch(chan->l2prot) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + case ISDN_PROTO_L2_HDLC: + reqbuf->XBuffer.P[1] = 1; + reqbuf->XBuffer.P[2] = 0x05; + l = 4; + break; + case ISDN_PROTO_L2_V11096: + reqbuf->XBuffer.P[2] = 0x0d; + reqbuf->XBuffer.P[3] = 5; + reqbuf->XBuffer.P[4] = 0; + break; + case ISDN_PROTO_L2_V11019: + reqbuf->XBuffer.P[2] = 0x0d; + reqbuf->XBuffer.P[3] = 6; + reqbuf->XBuffer.P[4] = 0; + break; + case ISDN_PROTO_L2_V11038: + reqbuf->XBuffer.P[2] = 0x0d; + reqbuf->XBuffer.P[3] = 7; + reqbuf->XBuffer.P[4] = 0; + break; + case ISDN_PROTO_L2_MODEM: + reqbuf->XBuffer.P[2] = 0x11; + reqbuf->XBuffer.P[3] = 7; + reqbuf->XBuffer.P[4] = 0; + reqbuf->XBuffer.P[5] = 0; + reqbuf->XBuffer.P[6] = 128; + reqbuf->XBuffer.P[7] = 0; + break; + case ISDN_PROTO_L2_TRANS: + switch(chan->l3prot) { + case ISDN_PROTO_L3_TRANSDSP: + reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */ + } + break; + } + reqbuf->XBuffer.P[8] = 0; + reqbuf->XBuffer.length = l; + reqbuf->Reference = 0; /* Sig Entity */ + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Call_Res\n", chan->No); + return(0); +} + +int +idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) +{ + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan_ptr *chan2; + + skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); + if (DebugVar & 8) + printk(KERN_DEBUG "idi_req: Ch%d: 0x%02x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig"); + if (layer) cmd |= 0x700; + switch(cmd) { + case ASSIGN: + case ASSIGN|0x700: + idi_assign_req(reqbuf, layer, chan); + break; + case REMOVE: + case REMOVE|0x700: + idi_put_req(reqbuf, REMOVE, layer); + break; + case INDICATE_REQ: + idi_put_req(reqbuf, INDICATE_REQ, 0); + break; + case HANGUP: + idi_put_req(reqbuf, HANGUP, 0); + break; + case REJECT: + idi_put_req(reqbuf, REJECT, 0); + break; + case CALL_ALERT: + idi_put_req(reqbuf, CALL_ALERT, 0); + break; + case CALL_RES: + idi_call_res_req(reqbuf, chan); + break; + case IDI_N_CONNECT|0x700: + idi_put_req(reqbuf, IDI_N_CONNECT, 1); + break; + case IDI_N_CONNECT_ACK|0x700: + idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1); + break; + case IDI_N_DISC|0x700: + idi_put_req(reqbuf, IDI_N_DISC, 1); + break; + case IDI_N_DISC_ACK|0x700: + idi_put_req(reqbuf, IDI_N_DISC_ACK, 1); + break; + default: + if (DebugVar & 1) + printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No); + return(-1); + } + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + return(0); +} + +int +eicon_idi_listen_req(eicon_card *card, eicon_chan *chan) +{ + if (DebugVar & 16) + printk(KERN_DEBUG"idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask); + if (!chan->e.D3Id) { + idi_do_req(card, chan, ASSIGN, 0); + } + if (chan->fsm_state == EICON_STATE_NULL) { + idi_do_req(card, chan, INDICATE_REQ, 0); + chan->fsm_state = EICON_STATE_LISTEN; + } + return(0); +} + +unsigned char +idi_si2bc(int si1, int si2, char *bc, char *hlc) +{ + hlc[0] = 0; + switch(si1) { + case 1: + bc[0] = 0x90; /* 3,1 kHz audio */ + bc[1] = 0x90; /* 64 kbit/s */ + bc[2] = 0xa3; /* G.711 A-law */ +#ifdef EICON_FULL_SERVICE_OKTETT + if (si2 == 1) { + bc[0] = 0x80; /* Speech */ + hlc[0] = 0x02; /* hlc len */ + hlc[1] = 0x91; /* first hic */ + hlc[2] = 0x81; /* Telephony */ + } +#endif + return(3); + case 2: + bc[0] = 0x90; /* 3,1 kHz audio */ + bc[1] = 0x90; /* 64 kbit/s */ + bc[2] = 0xa3; /* G.711 A-law */ +#ifdef EICON_FULL_SERVICE_OKTETT + if (si2 == 2) { + hlc[0] = 0x02; /* hlc len */ + hlc[1] = 0x91; /* first hic */ + hlc[2] = 0x84; /* Fax Gr.2/3 */ + } +#endif + return(3); + case 5: + case 7: + default: + bc[0] = 0x88; + bc[1] = 0x90; + return(2); + } + return (0); +} + +int +idi_hangup(eicon_card *card, eicon_chan *chan) +{ + if ((chan->fsm_state == EICON_STATE_ACTIVE) || + (chan->fsm_state == EICON_STATE_WMCONN)) { + if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1); + } + if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1); + idi_do_req(card, chan, HANGUP, 0); + chan->fsm_state = EICON_STATE_NULL; + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No); + return(0); +} + +int +idi_connect_res(eicon_card *card, eicon_chan *chan) +{ + chan->fsm_state = EICON_STATE_IWAIT; + idi_do_req(card, chan, CALL_RES, 0); + idi_do_req(card, chan, ASSIGN, 1); + return(0); +} + +int +idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, + char *eazmsn, int si1, int si2) +{ + int l = 0; + int i; + unsigned char tmp; + unsigned char bc[5]; + unsigned char hlc[5]; + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan_ptr *chan2; + + skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); + reqbuf->Req = CALL_REQ; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + + reqbuf->XBuffer.P[l++] = CPN; + reqbuf->XBuffer.P[l++] = strlen(phone) + 1; + reqbuf->XBuffer.P[l++] = 0xc1; + for(i=0; iXBuffer.P[l++] = phone[i]; + + reqbuf->XBuffer.P[l++] = OAD; + reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2; + reqbuf->XBuffer.P[l++] = 0x01; + reqbuf->XBuffer.P[l++] = 0x81; + for(i=0; iXBuffer.P[l++] = eazmsn[i]; + + if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) { + reqbuf->XBuffer.P[l++] = BC; + reqbuf->XBuffer.P[l++] = tmp; + for(i=0; iXBuffer.P[l++] = bc[i]; + if ((tmp=hlc[0])) { + reqbuf->XBuffer.P[l++] = HLC; + reqbuf->XBuffer.P[l++] = tmp; + for(i=1; i<=tmp;i++) + reqbuf->XBuffer.P[l++] = hlc[i]; + } + } + reqbuf->XBuffer.P[l++] = CAI; + reqbuf->XBuffer.P[l++] = 6; + reqbuf->XBuffer.P[l++] = 0x09; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = 0; + reqbuf->XBuffer.P[l++] = 32; + reqbuf->XBuffer.P[l++] = 3; + switch(chan->l2prot) { + case ISDN_PROTO_L2_X75I: + case ISDN_PROTO_L2_X75UI: + case ISDN_PROTO_L2_X75BUI: + case ISDN_PROTO_L2_HDLC: + reqbuf->XBuffer.P[l-6] = 5; + reqbuf->XBuffer.P[l-7] = 1; + l -= 5; + break; + case ISDN_PROTO_L2_V11096: + reqbuf->XBuffer.P[l-7] = 3; + reqbuf->XBuffer.P[l-6] = 0x0d; + reqbuf->XBuffer.P[l-5] = 5; + reqbuf->XBuffer.P[l-4] = 0; + l -= 3; + break; + case ISDN_PROTO_L2_V11019: + reqbuf->XBuffer.P[l-7] = 3; + reqbuf->XBuffer.P[l-6] = 0x0d; + reqbuf->XBuffer.P[l-5] = 6; + reqbuf->XBuffer.P[l-4] = 0; + l -= 3; + break; + case ISDN_PROTO_L2_V11038: + reqbuf->XBuffer.P[l-7] = 3; + reqbuf->XBuffer.P[l-6] = 0x0d; + reqbuf->XBuffer.P[l-5] = 7; + reqbuf->XBuffer.P[l-4] = 0; + l -= 3; + break; + case ISDN_PROTO_L2_MODEM: + reqbuf->XBuffer.P[l-6] = 0x11; + reqbuf->XBuffer.P[l-5] = 7; + reqbuf->XBuffer.P[l-4] = 0; + reqbuf->XBuffer.P[l-3] = 0; + reqbuf->XBuffer.P[l-2] = 128; + reqbuf->XBuffer.P[l-1] = 0; + break; + case ISDN_PROTO_L2_TRANS: + switch(chan->l3prot) { + case ISDN_PROTO_L3_TRANSDSP: + reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */ + } + break; + } + + reqbuf->XBuffer.P[l++] = 0; /* end */ + reqbuf->XBuffer.length = l; + reqbuf->Reference = 0; /* Sig Entity */ + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone); + return(0); +} + + +void +idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsigned char *buffer, int len) +{ + int i,j; + int pos = 0; + int codeset = 0; + int wlen = 0; + int lock = 0; + __u8 w; + __u16 code; + isdn_ctrl cmd; + + memset(message, 0, sizeof(idi_ind_message)); + + if ((!len) || (!buffer[pos])) return; + while(pos <= len) { + w = buffer[pos++]; + if (!w) return; + if (w & 0x80) { + wlen = 0; + } + else { + wlen = buffer[pos++]; + } + + if (pos > len) return; + + if (lock & 0x80) lock &= 0x7f; + else codeset = lock; + + if((w&0xf0) == SHIFT) { + codeset = w; + if(!(codeset & 0x08)) lock = codeset & 7; + codeset &= 7; + lock |= 0x80; + } + else { + if (w==ESC && wlen >=2) { + code = buffer[pos++]|0x800; + wlen--; + } + else code = w; + code |= (codeset<<8); + + switch(code) { + case OAD: + j = 1; + if (wlen) { + message->plan = buffer[pos++]; + if (message->plan &0x80) + message->screen = 0; + else { + message->screen = buffer[pos++]; + j = 2; + } + } + for(i=0; i < wlen-j; i++) + message->oad[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, + message->plan, message->screen, message->oad); + break; + case RDN: + j = 1; + if (wlen) { + if (!(buffer[pos++] & 0x80)) { + pos++; + j = 2; + } + } + for(i=0; i < wlen-j; i++) + message->rdn[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: RDN= %s\n", chan->No, + message->rdn); + break; + case CPN: + for(i=0; i < wlen; i++) + message->cpn[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No, + (__u8)message->cpn[0], message->cpn + 1); + break; + case DSA: + pos++; + for(i=0; i < wlen-1; i++) + message->dsa[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa); + break; + case OSA: + pos++; + for(i=0; i < wlen-1; i++) + message->osa[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa); + break; + case BC: + for(i=0; i < wlen; i++) + message->bc[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No, + message->bc[0],message->bc[1],message->bc[2]); + break; + case 0x800|BC: + for(i=0; i < wlen; i++) + message->e_bc[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]); + break; + case LLC: + for(i=0; i < wlen; i++) + message->llc[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0], + message->llc[1],message->llc[2],message->llc[3]); + break; + case HLC: + for(i=0; i < wlen; i++) + message->hlc[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No, + message->hlc[0], message->hlc[1], + message->hlc[2], message->hlc[3], message->hlc[4]); + break; + case DSP: + case 0x600|DSP: + for(i=0; i < wlen; i++) + message->display[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: Display: %s\n", chan->No, + message->display); + break; + case 0x600|KEY: + for(i=0; i < wlen; i++) + message->keypad[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: Keypad: %s\n", chan->No, + message->keypad); + break; + case NI: + case 0x600|NI: + if (wlen) { + if (DebugVar & 4) { + switch(buffer[pos] & 127) { + case 0: + printk(KERN_DEBUG"idi_inf: Ch%d: User suspended.\n", chan->No); + break; + case 1: + printk(KERN_DEBUG"idi_inf: Ch%d: User resumed.\n", chan->No); + break; + case 2: + printk(KERN_DEBUG"idi_inf: Ch%d: Bearer service change.\n", chan->No); + break; + default: + printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Notification %x.\n", + chan->No, buffer[pos] & 127); + } + } + pos += wlen; + } + break; + case PI: + case 0x600|PI: + if (wlen > 1) { + if (DebugVar & 4) { + switch(buffer[pos+1] & 127) { + case 1: + printk(KERN_DEBUG"idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No); + break; + case 2: + printk(KERN_DEBUG"idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No); + break; + case 3: + printk(KERN_DEBUG"idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No); + break; + case 4: + printk(KERN_DEBUG"idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No); + break; + case 5: + printk(KERN_DEBUG"idi_inf: Ch%d: Interworking has occurred.\n", chan->No); + break; + case 8: + printk(KERN_DEBUG"idi_inf: Ch%d: In-band information available.\n", chan->No); + break; + default: + printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Progress %x.\n", + chan->No, buffer[pos+1] & 127); + } + } + } + pos += wlen; + break; + case CAU: + for(i=0; i < wlen; i++) + message->cau[i] = buffer[pos++]; + memcpy(&chan->cause, &message->cau, 2); + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: CAU=%d %d\n", chan->No, + message->cau[0],message->cau[1]); + break; + case 0x800|CAU: + for(i=0; i < wlen; i++) + message->e_cau[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: ECAU=%d %d\n", chan->No, + message->e_cau[0],message->e_cau[1]); + break; + case 0x800|CHI: + for(i=0; i < wlen; i++) + message->e_chi[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: ESC/CHI=%d\n", chan->No, + message->e_cau[0]); + break; + case 0x800|0x7a: + pos ++; + message->e_mt=buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt); + break; + case DT: + for(i=0; i < wlen; i++) + message->dt[i] = buffer[pos++]; + if (DebugVar & 4) + printk(KERN_DEBUG"idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No, + message->dt[2], message->dt[1], message->dt[0], + message->dt[3], message->dt[4], message->dt[5]); + break; + case 0x600|SIN: + for(i=0; i < wlen; i++) + message->sin[i] = buffer[pos++]; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: SIN=%d %d\n", chan->No, + message->sin[0],message->sin[1]); + break; + case 0x600|CPS: + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: Called Party Status in ind\n", chan->No); + pos += wlen; + break; + case 0x600|CIF: + for (i = 0; i < wlen; i++) + if (buffer[pos + i] != '0') break; + memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i); + cmd.parm.num[wlen - i] = 0; + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num); + pos += wlen; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_CINF; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + break; + case 0x600|DATE: + if (DebugVar & 2) + printk(KERN_DEBUG"idi_inf: Ch%d: Date in ind\n", chan->No); + pos += wlen; + break; + case 0xe08: + case 0xe7a: + case 0xe04: + case 0xe00: + /* *** TODO *** */ + case CHA: + /* Charge advice */ + case FTY: + case 0x600|FTY: + case CHI: + case 0x800: + /* Not yet interested in this */ + pos += wlen; + break; + case 0x880: + /* Managment Information Element */ + if (!manbuf) { + if (DebugVar & 1) + printk(KERN_WARNING"idi_err: manbuf not allocated\n"); + } + else { + memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen); + manbuf->length[manbuf->count] = wlen; + manbuf->count++; + manbuf->pos += wlen; + } + pos += wlen; + break; + default: + pos += wlen; + if (DebugVar & 6) + printk(KERN_WARNING"idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", + chan->No, code, wlen); + } + } + } +} + +void +idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2) +{ + si1[0] = 0; + si2[0] = 0; + if (memcmp(bc, BC_Speech, 3) == 0) { /* Speech */ + si1[0] = 1; +#ifdef EICON_FULL_SERVICE_OKTETT + si2[0] = 1; +#endif + } + if (memcmp(bc, BC_31khz, 3) == 0) { /* 3.1kHz audio */ + si1[0] = 1; +#ifdef EICON_FULL_SERVICE_OKTETT + si2[0] = 2; + if (memcmp(hlc, HLC_faxg3, 2) == 0) { /* Fax Gr.2/3 */ + si1[0] = 2; + } +#endif + } + if (memcmp(bc, BC_64k, 2) == 0) { /* unrestricted 64 kbits */ + si1[0] = 7; + } + if (memcmp(bc, BC_video, 3) == 0) { /* video */ + si1[0] = 4; + } +} + +int +idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len) +{ + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan_ptr *chan2; + + if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) { + if (DebugVar & 1) + printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state); + return -ENODEV; + } + if (DebugVar & 8) + printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No, + UReq, buffer[0], buffer[1], buffer[2], buffer[3]); + + skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); + + reqbuf->Req = IDI_N_UDATA; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + + reqbuf->XBuffer.length = len + 1; + reqbuf->XBuffer.P[0] = UReq; + memcpy(&reqbuf->XBuffer.P[1], buffer, len); + reqbuf->Reference = 1; /* Net Entity */ + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + return (0); +} + +void +idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value) +{ + u_char buf[6]; + struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf; + + memset(buf, 0, 6); + switch(cmd) { + case ISDN_AUDIO_SETDD: + if (value[0]) { + dtmf_buf->tone = (__u16) (value[1] * 5); + dtmf_buf->gap = (__u16) (value[1] * 5); + idi_send_udata(ccard, chan, + DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER, + buf, 4); + } else { + idi_send_udata(ccard, chan, + DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER, + buf, 0); + } + break; + } +} + +void +idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len) +{ + isdn_ctrl cmd; + eicon_dsp_ind *p = (eicon_dsp_ind *) (&buffer[1]); + static char *connmsg[] = + {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34", + "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90", + "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"}; + static u_char dtmf_code[] = { + '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D' + }; + + switch (buffer[0]) { + case DSP_UDATA_INDICATION_SYNC: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time); + break; + case DSP_UDATA_INDICATION_DCD_OFF: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time); + break; + case DSP_UDATA_INDICATION_DCD_ON: + if ((chan->l2prot == ISDN_PROTO_L2_MODEM) && + (chan->fsm_state == EICON_STATE_WMCONN)) { + chan->fsm_state = EICON_STATE_ACTIVE; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BCONN; + cmd.arg = chan->No; + sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]); + ccard->interface.statcallb(&cmd); + } + if (DebugVar & 8) { + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time); + printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No, + p->norm, p->options, p->speed, p->delay); + } + break; + case DSP_UDATA_INDICATION_CTS_OFF: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time); + break; + case DSP_UDATA_INDICATION_CTS_ON: + if (DebugVar & 8) { + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time); + printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No, + p->norm, p->options, p->speed, p->delay); + } + break; + case DSP_UDATA_INDICATION_DISCONNECT: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]); + break; + case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No, + dtmf_code[buffer[1]]); + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_AUDIO; + cmd.parm.num[0] = ISDN_AUDIO_DTMF; + cmd.parm.num[1] = dtmf_code[buffer[1]]; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + break; + default: + if (DebugVar & 8) + printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]); + } +} + +void +idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) +{ + int tmp; + int free_buff; + struct sk_buff *skb2; + eicon_IND *ind = (eicon_IND *)skb->data; + eicon_chan *chan; + idi_ind_message message; + isdn_ctrl cmd; + + if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + dev_kfree_skb(skb); + return; + } + + if ((DebugVar & 128) || + ((DebugVar & 16) && (ind->Ind != 8))) { + printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No, + ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); + } + + free_buff = 1; + /* Signal Layer */ + if (chan->e.D3Id == ind->IndId) { + idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); + switch(ind->Ind) { + case HANGUP: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Hangup\n", chan->No); + while((skb2 = skb_dequeue(&chan->e.X))) { + dev_kfree_skb(skb2); + } + chan->e.busy = 0; + chan->queued = 0; + chan->waitq = 0; + chan->waitpq = 0; + chan->fsm_state = EICON_STATE_NULL; + if (message.e_cau[0] & 0x7f) { + cmd.driver = ccard->myid; + cmd.arg = chan->No; + sprintf(cmd.parm.num,"E%02x%02x", + chan->cause[0]&0x7f, message.e_cau[0]&0x7f); + cmd.command = ISDN_STAT_CAUSE; + ccard->interface.statcallb(&cmd); + } + chan->cause[0] = 0; + cmd.driver = ccard->myid; + cmd.arg = chan->No; + cmd.command = ISDN_STAT_DHUP; + ccard->interface.statcallb(&cmd); + eicon_idi_listen_req(ccard, chan); + break; + case INDICATE_IND: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Indicate_Ind\n", chan->No); + chan->fsm_state = EICON_STATE_ICALL; + idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2); + strcpy(chan->cpn, message.cpn + 1); + if (strlen(message.dsa)) { + strcat(chan->cpn, "."); + strcat(chan->cpn, message.dsa); + } + strcpy(chan->oad, message.oad); + try_stat_icall_again: + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_ICALL; + cmd.arg = chan->No; + cmd.parm.setup.si1 = chan->si1; + cmd.parm.setup.si2 = chan->si2; + strcpy(cmd.parm.setup.eazmsn, chan->cpn); + strcpy(cmd.parm.setup.phone, chan->oad); + cmd.parm.setup.plan = message.plan; + cmd.parm.setup.screen = message.screen; + tmp = ccard->interface.statcallb(&cmd); + switch(tmp) { + case 0: /* no user responding */ + idi_do_req(ccard, chan, HANGUP, 0); + break; + case 1: /* alert */ + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Call Alert\n", chan->No); + if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) { + chan->fsm_state = EICON_STATE_ICALL; + idi_do_req(ccard, chan, CALL_ALERT, 0); + } + break; + case 2: /* reject */ + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Call Reject\n", chan->No); + idi_do_req(ccard, chan, REJECT, 0); + break; + case 3: /* incomplete number */ + if (DebugVar & 8) + printk(KERN_DEBUG"idi_req: Ch%d: Incomplete Number\n", chan->No); + switch(ccard->type) { + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + /* TODO (other protocols) */ + chan->fsm_state = EICON_STATE_ICALLW; + break; + default: + idi_do_req(ccard, chan, HANGUP, 0); + } + break; + } + break; + case INFO_IND: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Info_Ind\n", chan->No); + if ((chan->fsm_state == EICON_STATE_ICALLW) && + (message.cpn[0])) { + strcat(chan->cpn, message.cpn + 1); + goto try_stat_icall_again; + } + break; + case CALL_IND: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Call_Ind\n", chan->No); + if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_IWAIT)) { + chan->fsm_state = EICON_STATE_IBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + } else + idi_hangup(ccard, chan); + break; + case CALL_CON: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Call_Con\n", chan->No); + if (chan->fsm_state == EICON_STATE_OCALL) { + chan->fsm_state = EICON_STATE_OBWAIT; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + idi_do_req(ccard, chan, ASSIGN, 1); + idi_do_req(ccard, chan, IDI_N_CONNECT, 1); + } else + idi_hangup(ccard, chan); + break; + case AOC_IND: + if (DebugVar & 8) + printk(KERN_DEBUG"idi_ind: Ch%d: Advice of Charge\n", chan->No); + break; + default: + if (DebugVar & 8) + printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind); + } + } + /* Network Layer */ + else if (chan->e.B2Id == ind->IndId) { + + if (chan->No == ccard->nchannels) { + /* Management Indication */ + idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length); + chan->fsm_state = 1; + } + else + switch(ind->Ind) { + case IDI_N_CONNECT_ACK: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect_Ack\n", chan->No); + if (chan->l2prot == ISDN_PROTO_L2_MODEM) { + chan->fsm_state = EICON_STATE_WMCONN; + break; + } + chan->fsm_state = EICON_STATE_ACTIVE; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + break; + case IDI_N_CONNECT: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No); + if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); + if (chan->l2prot == ISDN_PROTO_L2_MODEM) { + chan->fsm_state = EICON_STATE_WMCONN; + break; + } + chan->fsm_state = EICON_STATE_ACTIVE; + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BCONN; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + break; + case IDI_N_DISC: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC\n", chan->No); + if (chan->e.B2Id) { + idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1); + idi_do_req(ccard, chan, REMOVE, 1); + } + chan->queued = 0; + chan->waitq = 0; + chan->waitpq = 0; + if (chan->fsm_state == EICON_STATE_ACTIVE) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BHUP; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + } + break; + case IDI_N_DISC_ACK: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No); + break; + case IDI_N_DATA_ACK: + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + break; + case IDI_N_DATA: + skb_pull(skb, sizeof(eicon_IND) - 1); + if (DebugVar & 128) + printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len); + ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb); + free_buff = 0; + break; + case IDI_N_UDATA: + idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length); + break; + default: + if (DebugVar & 8) + printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind); + } + } + else { + if (DebugVar & 1) + printk(KERN_ERR "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No); + } + if (free_buff) dev_kfree_skb(skb); +} + +void +idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) +{ + isdn_ctrl cmd; + + if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) { + /* I dont know why this happens, just ignoring this RC */ + if (DebugVar & 16) + printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, + ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); + return; + } + + /* Management Interface */ + if (chan->No == ccard->nchannels) { + /* Managementinterface: changing state */ + if (chan->e.Req == 0x04) + chan->fsm_state = 1; + } + + /* Remove an Id */ + if (chan->e.Req == REMOVE) { + if (ack->Reference == chan->e.ref) { + ccard->IdTable[ack->RcId] = NULL; + if (DebugVar & 16) + printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No, + ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); + if (!chan->e.ReqCh) + chan->e.D3Id = 0; + else + chan->e.B2Id = 0; + } + else { + if (DebugVar & 1) + printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, + ack->Reference, chan->e.ref); + } + return; + } + + /* Signal layer */ + if (!chan->e.ReqCh) { + if (DebugVar & 16) + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + ack->RcId, ack->RcCh, ack->Reference); + } else { + /* Network layer */ + switch(chan->e.Req & 0x0f) { + case IDI_N_MDATA: + case IDI_N_DATA: + if ((chan->e.Req & 0x0f) == IDI_N_DATA) { + if (chan->queued) { + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_BSENT; + cmd.arg = chan->No; + cmd.parm.length = chan->waitpq; + ccard->interface.statcallb(&cmd); + } + chan->waitpq = 0; + } + chan->queued -= chan->waitq; + if (chan->queued < 0) chan->queued = 0; + break; + default: + if (DebugVar & 16) + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + ack->RcId, ack->RcCh, ack->Reference); + } + } +} + +void +idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) +{ + int j; + eicon_RC *ack = (eicon_RC *)skb->data; + eicon_chan *chan; + isdn_ctrl cmd; + int dCh = -1; + + if ((chan = ccard->IdTable[ack->RcId]) != NULL) + dCh = chan->No; + + + switch (ack->Rc) { + case OK_FC: + case N_FLOW_CONTROL: + case ASSIGN_RC: + if (DebugVar & 1) + printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n", + dCh, ack->Rc); + case READY_INT: + case TIMER_INT: + /* we do nothing here */ + break; + + case OK: + if (!chan) { + if (DebugVar & 1) + printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh); + break; + } + idi_handle_ack_ok(ccard, chan, ack); + break; + + case ASSIGN_OK: + if (chan) { + if (DebugVar & 1) + printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%d,%d)\n", + chan->No, chan->e.D3Id, chan->e.B2Id); + } + for(j = 0; j < ccard->nchannels + 1; j++) { + if (ccard->bch[j].e.ref == ack->Reference) { + if (!ccard->bch[j].e.ReqCh) + ccard->bch[j].e.D3Id = ack->RcId; + else + ccard->bch[j].e.B2Id = ack->RcId; + ccard->IdTable[ack->RcId] = &ccard->bch[j]; + ccard->bch[j].e.busy = 0; + ccard->bch[j].e.ref = 0; + if (DebugVar & 16) + printk(KERN_DEBUG"idi_ack: Ch%d: Id %d assigned (%s)\n", j, + ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig"); + break; + } + } + if (j > ccard->nchannels) { + if (DebugVar & 24) + printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n", + ack->Reference, ack->RcId); + } + break; + + case OUT_OF_RESOURCES: + case UNKNOWN_COMMAND: + case WRONG_COMMAND: + case WRONG_ID: + case WRONG_CH: + case UNKNOWN_IE: + case WRONG_IE: + default: + chan->e.busy = 0; + if (DebugVar & 24) + printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", dCh, + ack->Rc, ack->RcId, ack->RcCh); + if (dCh == ccard->nchannels) { /* Management */ + chan->fsm_state = 2; + } else if (dCh >= 0) { + /* any other channel */ + /* card reports error: we hangup */ + idi_hangup(ccard, chan); + cmd.driver = ccard->myid; + cmd.command = ISDN_STAT_DHUP; + cmd.arg = chan->No; + ccard->interface.statcallb(&cmd); + } + } + if (chan) + chan->e.busy = 0; + dev_kfree_skb(skb); + eicon_schedule_tx(ccard); +} + +int +idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que) +{ + struct sk_buff *xmit_skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan_ptr *chan2; + int len, plen = 0, offset = 0; + unsigned long flags; + + if (chan->fsm_state != EICON_STATE_ACTIVE) { + if (DebugVar & 1) + printk(KERN_DEBUG"idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state); + return -ENODEV; + } + + len = skb->len; + if (len > 2138) /* too much for the shared memory */ + return -1; + if (!len) + return 0; + if (chan->queued + len > ((chan->l2prot == ISDN_PROTO_L2_TRANS) ? 4000 : EICON_MAX_QUEUED)) + return 0; + if (DebugVar & 128) + printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len); + + save_flags(flags); + cli(); + while(offset < len) { + + plen = ((len - offset) > 270) ? 270 : len - offset; + + xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + restore_flags(flags); + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ)); + if (((len - offset) > 270) && + (chan->l2prot != ISDN_PROTO_L2_TRANS)) { + reqbuf->Req = IDI_N_MDATA; + } else { + reqbuf->Req = IDI_N_DATA; + if (ack) reqbuf->Req |= N_D_BIT; + } + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen); + reqbuf->XBuffer.length = plen; + reqbuf->Reference = 1; /* Net Entity */ + + skb_queue_tail(&chan->e.X, xmit_skb); + skb_queue_tail(&card->sndq, skb2); + + offset += plen; + } + if (que) + chan->queued += len; + restore_flags(flags); + eicon_schedule_tx(card); + dev_kfree_skb(skb); + return len; +} + + + +int +eicon_idi_manage_assign(eicon_card *card) +{ + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan *chan; + eicon_chan_ptr *chan2; + + chan = &(card->bch[card->nchannels]); + + skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: alloc_skb failed\n"); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); + + reqbuf->XBuffer.P[0] = 0; + reqbuf->Req = ASSIGN; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 0xe0; + reqbuf->XBuffer.length = 1; + reqbuf->Reference = 2; /* Man Entity */ + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + return(0); +} + + +int +eicon_idi_manage_remove(eicon_card *card) +{ + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan *chan; + eicon_chan_ptr *chan2; + + chan = &(card->bch[card->nchannels]); + + skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: alloc_skb failed\n"); + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); + + reqbuf->Req = REMOVE; + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.length = 0; + reqbuf->Reference = 2; /* Man Entity */ + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + eicon_schedule_tx(card); + return(0); +} + + +int +eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb) +{ + int l = 0; + int ret = 0; + int timeout; + int i; + struct sk_buff *skb; + struct sk_buff *skb2; + eicon_REQ *reqbuf; + eicon_chan *chan; + eicon_chan_ptr *chan2; + + chan = &(card->bch[card->nchannels]); + + if (chan->e.D3Id) return -EBUSY; + chan->e.D3Id = 1; + while((skb2 = skb_dequeue(&chan->e.X))) + dev_kfree_skb(skb2); + chan->e.busy = 0; + + if ((ret = eicon_idi_manage_assign(card))) { + chan->e.D3Id = 0; + return(ret); + } + + timeout = jiffies + 50; + while (timeout > jiffies) { + if (chan->e.B2Id) break; + SLEEP(10); + } + if (!chan->e.B2Id) { + chan->e.D3Id = 0; + return -EIO; + } + + chan->fsm_state = 0; + + if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: alloc_manifbuf failed\n"); + chan->e.D3Id = 0; + return -ENOMEM; + } + if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) { + chan->e.D3Id = 0; + return -EFAULT; + } + + skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC); + skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC); + + if ((!skb) || (!skb2)) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err_manif: alloc_skb failed\n"); + kfree(manbuf); + chan->e.D3Id = 0; + return -ENOMEM; + } + + chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr)); + chan2->ptr = chan; + + reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ)); + + reqbuf->XBuffer.P[l++] = ESC; + reqbuf->XBuffer.P[l++] = 6; + reqbuf->XBuffer.P[l++] = 0x80; + for (i = 0; i < manbuf->length[0]; i++) + reqbuf->XBuffer.P[l++] = manbuf->data[i]; + reqbuf->XBuffer.P[1] = manbuf->length[0] + 1; + + reqbuf->XBuffer.P[l++] = 0; + reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */ + reqbuf->ReqCh = 0; + reqbuf->ReqId = 1; + reqbuf->XBuffer.length = l; + reqbuf->Reference = 2; /* Man Entity */ + + skb_queue_tail(&chan->e.X, skb); + skb_queue_tail(&card->sndq, skb2); + + manbuf->count = 0; + manbuf->pos = 0; + + eicon_schedule_tx(card); + + timeout = jiffies + 50; + while (timeout > jiffies) { + if (chan->fsm_state) break; + SLEEP(10); + } + if ((!chan->fsm_state) || (chan->fsm_state == 2)) { + eicon_idi_manage_remove(card); + kfree(manbuf); + chan->e.D3Id = 0; + return -EIO; + } + + if ((ret = eicon_idi_manage_remove(card))) { + chan->e.D3Id = 0; + return(ret); + } + + if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) { + chan->e.D3Id = 0; + return -EFAULT; + } + + kfree(manbuf); + chan->e.D3Id = 0; + return(0); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_idi.h linux/drivers/isdn/eicon/eicon_idi.h --- v2.2.10/linux/drivers/isdn/eicon/eicon_idi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_idi.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,260 @@ +/* $Id: eicon_idi.h,v 1.5 1999/07/11 17:16:26 armin Exp $ + * + * ISDN lowlevel-module for the Eicon.Diehl active cards. + * IDI-Interface + * + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_idi.h,v $ + * Revision 1.5 1999/07/11 17:16:26 armin + * Bugfixes in queue handling. + * Added DSP-DTMF decoder functions. + * Reorganized ack_handler. + * + * Revision 1.4 1999/03/29 11:19:44 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.3 1999/03/02 12:37:45 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.2 1999/01/24 20:14:18 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.1 1999/01/01 18:09:42 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#ifndef IDI_H +#define IDI_H + + +#define ASSIGN 0x01 +#define REMOVE 0xff + +#define CALL_REQ 1 /* call request */ +#define CALL_CON 1 /* call confirmation */ +#define CALL_IND 2 /* incoming call connected */ +#define LISTEN_REQ 2 /* listen request */ +#define HANGUP 3 /* hangup request/indication */ +#define SUSPEND 4 /* call suspend request/confirm */ +#define RESUME 5 /* call resume request/confirm */ +#define SUSPEND_REJ 6 /* suspend rejected indication */ +#define USER_DATA 8 /* user data for user to user signaling */ +#define CONGESTION 9 /* network congestion indication */ +#define INDICATE_REQ 10 /* request to indicate an incoming call */ +#define INDICATE_IND 10 /* indicates that there is an incoming call */ +#define CALL_RES 11 /* accept an incoming call */ +#define CALL_ALERT 12 /* send ALERT for incoming call */ +#define INFO_REQ 13 /* INFO request */ +#define INFO_IND 13 /* INFO indication */ +#define REJECT 14 /* reject an incoming call */ +#define RESOURCES 15 /* reserve B-Channel hardware resources */ +#define TEL_CTRL 16 /* Telephone control request/indication */ +#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */ +#define FAC_REG_REQ 18 /* connection idependent fac registration */ +#define FAC_REG_ACK 19 /* fac registration acknowledge */ +#define FAC_REG_REJ 20 /* fac registration reject */ +#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */ +#define AOC_IND 26/* Advice of Charge */ + +#define IDI_N_MDATA (0x01) +#define IDI_N_CONNECT (0x02) +#define IDI_N_CONNECT_ACK (0x03) +#define IDI_N_DISC (0x04) +#define IDI_N_DISC_ACK (0x05) +#define IDI_N_RESET (0x06) +#define IDI_N_RESET_ACK (0x07) +#define IDI_N_DATA (0x08) +#define IDI_N_EDATA (0x09) +#define IDI_N_UDATA (0x0a) +#define IDI_N_BDATA (0x0b) +#define IDI_N_DATA_ACK (0x0c) +#define IDI_N_EDATA_ACK (0x0d) + +#define N_Q_BIT 0x10 /* Q-bit for req/ind */ +#define N_M_BIT 0x20 /* M-bit for req/ind */ +#define N_D_BIT 0x40 /* D-bit for req/ind */ + + +#define SHIFT 0x90 /* codeset shift */ +#define MORE 0xa0 /* more data */ +#define CL 0xb0 /* congestion level */ + + /* codeset 0 */ + +#define BC 0x04 /* Bearer Capability */ +#define CAU 0x08 /* cause */ +#define CAD 0x0c /* Connected address */ +#define CAI 0x10 /* call identity */ +#define CHI 0x18 /* channel identification */ +#define LLI 0x19 /* logical link id */ +#define CHA 0x1a /* charge advice */ +#define FTY 0x1c +#define PI 0x1e /* Progress Indicator */ +#define NI 0x27 /* Notification Indicator */ +#define DT 0x29 /* ETSI date/time */ +#define KEY 0x2c /* keypad information element */ +#define DSP 0x28 /* display */ +#define OAD 0x6c /* origination address */ +#define OSA 0x6d /* origination sub-address */ +#define CPN 0x70 /* called party number */ +#define DSA 0x71 /* destination sub-address */ +#define RDN 0x74 /* redirecting number */ +#define LLC 0x7c /* low layer compatibility */ +#define HLC 0x7d /* high layer compatibility */ +#define UUI 0x7e /* user user information */ +#define ESC 0x7f /* escape extension */ + +#define DLC 0x20 /* data link layer configuration */ +#define NLC 0x21 /* network layer configuration */ + + /* codeset 6 */ + +#define SIN 0x01 /* service indicator */ +#define CIF 0x02 /* charging information */ +#define DATE 0x03 /* date */ +#define CPS 0x07 /* called party status */ + +/*------------------------------------------------------------------*/ +/* return code coding */ +/*------------------------------------------------------------------*/ + +#define UNKNOWN_COMMAND 0x01 /* unknown command */ +#define WRONG_COMMAND 0x02 /* wrong command */ +#define WRONG_ID 0x03 /* unknown task/entity id */ +#define WRONG_CH 0x04 /* wrong task/entity id */ +#define UNKNOWN_IE 0x05 /* unknown information el. */ +#define WRONG_IE 0x06 /* wrong information el. */ +#define OUT_OF_RESOURCES 0x07 /* card out of res. */ +#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */ +#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */ +#define ASSIGN_OK 0xef /* ASSIGN OK */ +#define OK_FC 0xfc /* Flow-Control RC */ +#define READY_INT 0xfd /* Ready interrupt */ +#define TIMER_INT 0xfe /* timer interrupt */ +#define OK 0xff /* command accepted */ + +/*------------------------------------------------------------------*/ + +typedef struct { + char cpn[32]; + char oad[32]; + char dsa[32]; + char osa[32]; + __u8 plan; + __u8 screen; + __u8 sin[4]; + __u8 chi[4]; + __u8 e_chi[4]; + __u8 bc[12]; + __u8 e_bc[12]; + __u8 llc[18]; + __u8 hlc[5]; + __u8 cau[4]; + __u8 e_cau[2]; + __u8 e_mt; + __u8 dt[6]; + char display[83]; + char keypad[35]; + char rdn[32]; +} idi_ind_message; + +typedef struct { + __u16 next __attribute__ ((packed)); + __u8 Req __attribute__ ((packed)); + __u8 ReqId __attribute__ ((packed)); + __u8 ReqCh __attribute__ ((packed)); + __u8 Reserved1 __attribute__ ((packed)); + __u16 Reference __attribute__ ((packed)); + __u8 Reserved[8] __attribute__ ((packed)); + eicon_PBUFFER XBuffer; +} eicon_REQ; + +typedef struct { + __u16 next __attribute__ ((packed)); + __u8 Rc __attribute__ ((packed)); + __u8 RcId __attribute__ ((packed)); + __u8 RcCh __attribute__ ((packed)); + __u8 Reserved1 __attribute__ ((packed)); + __u16 Reference __attribute__ ((packed)); + __u8 Reserved2[8] __attribute__ ((packed)); +} eicon_RC; + +typedef struct { + __u16 next __attribute__ ((packed)); + __u8 Ind __attribute__ ((packed)); + __u8 IndId __attribute__ ((packed)); + __u8 IndCh __attribute__ ((packed)); + __u8 MInd __attribute__ ((packed)); + __u16 MLength __attribute__ ((packed)); + __u16 Reference __attribute__ ((packed)); + __u8 RNR __attribute__ ((packed)); + __u8 Reserved __attribute__ ((packed)); + __u32 Ack __attribute__ ((packed)); + eicon_PBUFFER RBuffer; +} eicon_IND; + +typedef struct { + __u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */ + __u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */ + __u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */ + __u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */ + __u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */ + __u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */ + __u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */ + __u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */ + __u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */ + __u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */ + __u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */ + __u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */ + __u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */ + __u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */ + __u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */ + __u8 B[1]; /* buffer space for Req,Ind and Rc */ +} eicon_pr_ram; + +typedef struct { + __u8 *Data; + unsigned int Size; + unsigned int Len; + __u8 *Next; +} eicon_OBJBUFFER; + +extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer); +extern int idi_hangup(eicon_card *card, eicon_chan *chan); +extern int idi_connect_res(eicon_card *card, eicon_chan *chan); +extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan); +extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone, + char *eazmsn, int si1, int si2); + +extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb); +extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb); +extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb); +extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que); +extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value); + +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c --- v2.2.10/linux/drivers/isdn/eicon/eicon_io.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_io.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,755 @@ +/* $Id: eicon_io.c,v 1.1 1999/03/29 11:19:45 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * Code for communicating with hardware. + * + * Copyright 1999 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * documents, informations and hardware. + * + * 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, 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. + * + * $Log: eicon_io.c,v $ + * Revision 1.1 1999/03/29 11:19:45 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * + */ + + +#include "eicon.h" + +void +eicon_io_rcv_dispatch(eicon_card *ccard) { + struct sk_buff *skb, *skb2, *skb_new; + eicon_IND *ind, *ind2, *ind_new; + eicon_chan *chan; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_io_rcv_dispatch: NULL card!\n"); + return; + } + + while((skb = skb_dequeue(&ccard->rcvq))) { + ind = (eicon_IND *)skb->data; + + if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + if (DebugVar & 1) { + switch(ind->Ind) { + case IDI_N_DISC_ACK: + /* doesn't matter if this happens */ + break; + default: + printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId); + printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", + ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); + } + } + dev_kfree_skb(skb); + continue; + } + + if (chan->e.complete) { /* check for rec-buffer chaining */ + if (ind->MLength == ind->RBuffer.length) { + chan->e.complete = 1; + idi_handle_ind(ccard, skb); + continue; + } + else { + chan->e.complete = 0; + ind->Ind = ind->MInd; + skb_queue_tail(&chan->e.R, skb); + continue; + } + } + else { + if (!(skb2 = skb_dequeue(&chan->e.R))) { + chan->e.complete = 1; + if (DebugVar & 1) + printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n"); + dev_kfree_skb(skb); + dev_kfree_skb(skb2); + continue; + } + ind2 = (eicon_IND *)skb2->data; + skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), + GFP_ATOMIC); + ind_new = (eicon_IND *)skb_put(skb_new, + ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length)); + ind_new->Ind = ind2->Ind; + ind_new->IndId = ind2->IndId; + ind_new->IndCh = ind2->IndCh; + ind_new->MInd = ind2->MInd; + ind_new->MLength = ind2->MLength; + ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length; + memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length); + memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length); + dev_kfree_skb(skb); + dev_kfree_skb(skb2); + if (ind->MLength == ind->RBuffer.length) { + chan->e.complete = 2; + idi_handle_ind(ccard, skb_new); + continue; + } + else { + chan->e.complete = 0; + skb_queue_tail(&chan->e.R, skb_new); + continue; + } + } + } +} + +void +eicon_io_ack_dispatch(eicon_card *ccard) { + struct sk_buff *skb; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_io_ack_dispatch: NULL card!\n"); + return; + } + while((skb = skb_dequeue(&ccard->rackq))) { + idi_handle_ack(ccard, skb); + } +} + + +/* + * IO-Functions for different card-types + */ + +u8 ram_inb(eicon_card *card, void *adr) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + return(inb((u16)pcard->PCIreg + M_DATA)); + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + return(readb(addr)); + } + return(0); +} + +u16 ram_inw(eicon_card *card, void *adr) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + return(inw((u16)pcard->PCIreg + M_DATA)); + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + return(readw(addr)); + } + return(0); +} + +void ram_outb(eicon_card *card, void *adr, u8 data) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + outb((u8)data, (u16)pcard->PCIreg + M_DATA); + break; + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + writeb(data, addr); + break; + } +} + +void ram_outw(eicon_card *card, void *adr , u16 data) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + outw((u16)data, (u16)pcard->PCIreg + M_DATA); + break; + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + writew(data, addr); + break; + } +} + +void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { + int i; + switch(card->type) { + case EICON_CTYPE_MAESTRA: + for(i = 0; i < len; i++) { + writeb(ram_inb(card, adr + i), adrto + i); + } + break; + case EICON_CTYPE_MAESTRAP: + memcpy(adrto, adr, len); + break; + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + memcpy_fromio(adrto, adr, len); + break; + } +} + +void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { + int i; + switch(card->type) { + case EICON_CTYPE_MAESTRA: + for(i = 0; i < len; i++) { + ram_outb(card, adrto + i, readb(adr + i)); + } + break; + case EICON_CTYPE_MAESTRAP: + memcpy(adrto, adr, len); + break; + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + memcpy_toio(adrto, adr, len); + break; + } +} + +/* + * Transmit-Function + */ +void +eicon_io_transmit(eicon_card *ccard) { + eicon_pci_card *pci_card; + eicon_isa_card *isa_card; + struct sk_buff *skb; + struct sk_buff *skb2; + unsigned long flags; + char *ram, *reg, *cfg; + eicon_pr_ram *prram = 0; + eicon_isa_com *com = 0; + eicon_REQ *ReqOut = 0; + eicon_REQ *reqbuf = 0; + eicon_chan *chan; + eicon_chan_ptr *chan2; + int ReqCount; + int scom = 0; + int tmp = 0; + int quloop = 1; + + pci_card = &ccard->hwif.pci; + isa_card = &ccard->hwif.isa; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_transmit: NULL card!\n"); + return; + } + + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + scom = 1; + com = (eicon_isa_com *)isa_card->shmem; + break; + case EICON_CTYPE_S2M: + scom = 0; + prram = (eicon_pr_ram *)isa_card->shmem; + break; + case EICON_CTYPE_MAESTRAP: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + prram = (eicon_pr_ram *)ram; + break; + case EICON_CTYPE_MAESTRA: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + prram = 0; + break; + default: + printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n"); + return; + } + + ReqCount = 0; + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + while(quloop) { + save_flags(flags); + cli(); + if (scom) { + if (ram_inb(ccard, &com->Req)) { + if (!ccard->ReadyInt) { + tmp = ram_inb(ccard, &com->ReadyInt) + 1; + ram_outb(ccard, &com->ReadyInt, tmp); + ccard->ReadyInt++; + } + restore_flags(flags); + skb_queue_head(&ccard->sndq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: Card not ready\n"); + return; + } + } else { + if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { + restore_flags(flags); + skb_queue_head(&ccard->sndq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: Card not ready\n"); + return; + } + } + restore_flags(flags); + chan2 = (eicon_chan_ptr *)skb2->data; + chan = chan2->ptr; + if (!chan->e.busy) { + if((skb = skb_dequeue(&chan->e.X))) { + save_flags(flags); + cli(); + reqbuf = (eicon_REQ *)skb->data; + if (scom) { + ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); + ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); + + } else { + /* get address of next available request buffer */ + ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; + ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); + ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); + ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); + ram_outb(ccard, &ReqOut->Req, reqbuf->Req); + } + + if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */ + + if (!reqbuf->Reference) { /* Signal Layer */ + if (scom) + ram_outb(ccard, &com->ReqId, chan->e.D3Id); + else + ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); + + chan->e.ReqCh = 0; + } + else { /* Net Layer */ + if (scom) + ram_outb(ccard, &com->ReqId, chan->e.B2Id); + else + ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); + + chan->e.ReqCh = 1; + if (((reqbuf->Req & 0x0f) == 0x08) || + ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ + chan->waitq = reqbuf->XBuffer.length; + chan->waitpq += reqbuf->XBuffer.length; + } + } + + } else { /* It is an ASSIGN */ + + if (scom) + ram_outb(ccard, &com->ReqId, reqbuf->ReqId); + else + ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + + if (!reqbuf->Reference) + chan->e.ReqCh = 0; + else + chan->e.ReqCh = 1; + } + if (scom) + chan->e.ref = ccard->ref_out++; + else + chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + + chan->e.Req = reqbuf->Req; + ReqCount++; + if (scom) + ram_outb(ccard, &com->Req, reqbuf->Req); + else + ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + + chan->e.busy = 1; + restore_flags(flags); + if (DebugVar & 32) + printk(KERN_DEBUG "eicon: Req=%x Id=%x Ch=%x Len=%x Ref=%d\n", + reqbuf->Req, + ram_inb(ccard, &ReqOut->ReqId), + reqbuf->ReqCh, reqbuf->XBuffer.length, + chan->e.ref); + dev_kfree_skb(skb); + } + dev_kfree_skb(skb2); + } + else { + skb_queue_tail(&ccard->sackq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: busy chan %d\n", chan->No); + } + + if (scom) + quloop = 0; + else + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + + } + if (!scom) + ram_outb(ccard, &prram->ReqInput, (__u8)(ram_inb(ccard, &prram->ReqInput) + ReqCount)); + + while((skb = skb_dequeue(&ccard->sackq))) { + skb_queue_tail(&ccard->sndq, skb); + } +} + + +/* + * IRQ handler + */ +void +eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { + eicon_card *ccard = (eicon_card *)dev_id; + eicon_pci_card *pci_card; + eicon_isa_card *isa_card; + char *ram = 0; + char *reg = 0; + char *cfg = 0; + eicon_pr_ram *prram = 0; + eicon_isa_com *com = 0; + eicon_RC *RcIn; + eicon_IND *IndIn; + struct sk_buff *skb; + int Count = 0; + int Rc = 0; + int Ind = 0; + unsigned char *irqprobe = 0; + int scom = 0; + int tmp = 0; + + + if (!ccard) { + printk(KERN_WARNING "eicon_irq: spurious interrupt %d\n", irq); + return; + } + + if (ccard->type == EICON_CTYPE_QUADRO) { + tmp = 4; + while(tmp) { + com = (eicon_isa_com *)ccard->hwif.isa.shmem; + if ((readb(ccard->hwif.isa.intack))) { /* quadro found */ + break; + } + ccard = ccard->qnext; + tmp--; + } + } + + pci_card = &ccard->hwif.pci; + isa_card = &ccard->hwif.isa; + + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + scom = 1; + com = (eicon_isa_com *)isa_card->shmem; + irqprobe = &isa_card->irqprobe; + break; + case EICON_CTYPE_S2M: + scom = 0; + prram = (eicon_pr_ram *)isa_card->shmem; + irqprobe = &isa_card->irqprobe; + break; + case EICON_CTYPE_MAESTRAP: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + irqprobe = &pci_card->irqprobe; + prram = (eicon_pr_ram *)ram; + break; + case EICON_CTYPE_MAESTRA: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + irqprobe = &pci_card->irqprobe; + prram = 0; + break; + default: + printk(KERN_WARNING "eicon_irq: unsupported card-type!\n"); + return; + } + + if (*irqprobe) { + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + if (readb(isa_card->intack)) { + writeb(0, &com->Rc); + writeb(0, isa_card->intack); + } + (*irqprobe)++; + break; + case EICON_CTYPE_S2M: + if (readb(isa_card->intack)) { + writeb(0, &prram->RcOutput); + writeb(0, isa_card->intack); + } + (*irqprobe)++; + break; + case EICON_CTYPE_MAESTRAP: + if (readb(&ram[0x3fe])) { + writeb(0, &prram->RcOutput); + writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); + writew(0, &cfg[MP_IRQ_RESET + 2]); + writeb(0, &ram[0x3fe]); + } + *irqprobe = 0; + break; + case EICON_CTYPE_MAESTRA: + outb(0x08, pci_card->PCIreg + M_RESET); + *irqprobe = 0; + break; + } + return; + } + + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_S2M: + if (!(readb(isa_card->intack))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + case EICON_CTYPE_MAESTRAP: + if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + case EICON_CTYPE_MAESTRA: + outw(0x3fe, pci_card->PCIreg + M_ADDR); + if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + } + + if (scom) { + + /* if a return code is available ... */ + if ((tmp = ram_inb(ccard, &com->Rc))) { + eicon_RC *ack; + if (tmp == READY_INT) { + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=READY_INT\n"); + if (ccard->ReadyInt) { + ccard->ReadyInt--; + ram_outb(ccard, &com->Rc, 0); + } + } else { + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = tmp; + ack->RcId = ram_inb(ccard, &com->RcId); + ack->RcCh = ram_inb(ccard, &com->RcCh); + ack->Reference = ccard->ref_in++; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n", + tmp,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + ram_outb(ccard, &com->Req, 0); + ram_outb(ccard, &com->Rc, 0); + } + + } else { + + /* if an indication is available ... */ + if ((tmp = ram_inb(ccard, &com->Ind))) { + eicon_IND *ind; + int len = ram_inw(ccard, &com->RBuffer.length); + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = tmp; + ind->IndId = ram_inb(ccard, &com->IndId); + ind->IndCh = ram_inb(ccard, &com->IndCh); + ind->MInd = ram_inb(ccard, &com->MInd); + ind->MLength = ram_inw(ccard, &com->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", + tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + ram_outb(ccard, &com->Ind, 0); + } + } + + } else { + + /* if return codes are available ... */ + if((Count = ram_inb(ccard, &prram->RcOutput))) { + eicon_RC *ack; + /* get the buffer address of the first return code */ + RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &prram->NextRc)]; + /* for all return codes do ... */ + while(Count--) { + + if((Rc=ram_inb(ccard, &RcIn->Rc))) { + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = Rc; + ack->RcId = ram_inb(ccard, &RcIn->RcId); + ack->RcCh = ram_inb(ccard, &RcIn->RcCh); + ack->Reference = ram_inw(ccard, &RcIn->Reference); + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n", + Rc,ack->RcId,ack->RcCh,ack->Reference); + ram_outb(ccard, &RcIn->Rc, 0); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } + /* get buffer address of next return code */ + RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)]; + } + /* clear all return codes (no chaining!) */ + ram_outb(ccard, &prram->RcOutput, 0); + } + + /* if indications are available ... */ + if((Count = ram_inb(ccard, &prram->IndOutput))) { + eicon_IND *ind; + /* get the buffer address of the first indication */ + IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &prram->NextInd)]; + /* for all indications do ... */ + while(Count--) { + Ind = ram_inb(ccard, &IndIn->Ind); + if(Ind) { + int len = ram_inw(ccard, &IndIn->RBuffer.length); + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = Ind; + ind->IndId = ram_inb(ccard, &IndIn->IndId); + ind->IndCh = ram_inb(ccard, &IndIn->IndCh); + ind->MInd = ram_inb(ccard, &IndIn->MInd); + ind->MLength = ram_inw(ccard, &IndIn->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", + Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + ram_outb(ccard, &IndIn->Ind, 0); + } + /* get buffer address of next indication */ + IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &IndIn->next)]; + } + ram_outb(ccard, &prram->IndOutput, 0); + } + + } + + /* clear interrupt */ + switch(ccard->type) { + case EICON_CTYPE_QUADRO: + writeb(0, isa_card->intack); + writeb(0, &com[0x401]); + break; + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_S2M: + writeb(0, isa_card->intack); + break; + case EICON_CTYPE_MAESTRAP: + writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); + writew(0, &cfg[MP_IRQ_RESET + 2]); + writeb(0, &ram[0x3fe]); + break; + case EICON_CTYPE_MAESTRA: + outb(0x08, pci_card->PCIreg + M_RESET); + outw(0x3fe, pci_card->PCIreg + M_ADDR); + outb(0, pci_card->PCIreg + M_DATA); + break; + } + + return; +} + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.2.10/linux/drivers/isdn/eicon/eicon_isa.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_isa.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,432 @@ +/* $Id: eicon_isa.c,v 1.5 1999/04/01 12:48:33 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * Hardware-specific code for old ISA cards. + * + * Copyright 1998 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_isa.c,v $ + * Revision 1.5 1999/04/01 12:48:33 armin + * Changed some log outputs. + * + * Revision 1.4 1999/03/29 11:19:46 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.3 1999/03/02 12:37:45 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.2 1999/01/24 20:14:19 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.1 1999/01/01 18:09:43 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#include "eicon.h" +#include "eicon_isa.h" + +#define check_shmem check_region +#define release_shmem release_region +#define request_shmem request_region + +char *eicon_isa_revision = "$Revision: 1.5 $"; + +/* Mask for detecting invalid IRQ parameter */ +static int eicon_isa_valid_irq[] = { + 0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/ + 0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */ + 0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */ + 0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */ + 0x1cbc /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */ +}; + +static void +eicon_isa_release_shmem(eicon_isa_card *card) { + if (card->mvalid) + release_shmem((unsigned long)card->shmem, card->ramsize); + card->mvalid = 0; +} + +static void +eicon_isa_release_irq(eicon_isa_card *card) { + if (!card->master) + return; + if (card->ivalid) + free_irq(card->irq, card); + card->ivalid = 0; +} + +void +eicon_isa_release(eicon_isa_card *card) { + eicon_isa_release_irq(card); + eicon_isa_release_shmem(card); +} + +void +eicon_isa_printpar(eicon_isa_card *card) { + switch (card->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_S2M: + printk(KERN_INFO "Eicon %s at 0x%lx, irq %d\n", + eicon_ctype_name[card->type], + (unsigned long)card->shmem, + card->irq); + } +} + +int +eicon_isa_find_card(int Mem, int Irq, char * Id) +{ + int primary = 1; + + if (!strlen(Id)) + return -1; + + /* Check for valid membase address */ + if ((Mem < 0x0c0000) || + (Mem > 0x0fc000) || + (Mem & 0xfff)) { + printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %s\n", + Mem, Id); + return -1; + } + if (check_shmem(Mem, RAMSIZE)) { + printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem); + return -1; + } + + writew(0x55aa, Mem + 0x402); + if (readw(Mem + 0x402) != 0x55aa) primary = 0; + writew(0, Mem + 0x402); + if (readw(Mem + 0x402) != 0) primary = 0; + + printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id); + if (primary) { + printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem); + writeb(0, Mem + 0x3ffe); + return EICON_CTYPE_ISAPRI; + } else { + printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem); + writeb(0, Mem + 0x400); + return EICON_CTYPE_ISABRI; + } + return -1; +} + +int +eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { + int tmp; + int timeout; + eicon_isa_codebuf cbuf; + unsigned char *code; + eicon_isa_boot *boot; + + if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf))) + return -EFAULT; + + /* Allocate code-buffer and copy code from userspace */ + if (cbuf.bootstrap_len > 1024) { + printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n", + cbuf.bootstrap_len); + return -EINVAL; + } + if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) { + printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n"); + return -ENOMEM; + } + if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) { + kfree(code); + return -EFAULT; + } + + switch(card->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_ISABRI: + card->ramsize = RAMSIZE; + card->intack = (__u8 *)card->shmem + INTACK; + card->startcpu = (__u8 *)card->shmem + STARTCPU; + card->stopcpu = (__u8 *)card->shmem + STOPCPU; + break; + case EICON_CTYPE_S2M: + case EICON_CTYPE_ISAPRI: + card->ramsize = RAMSIZE_P; + card->intack = (__u8 *)card->shmem + INTACK_P; + card->startcpu = (__u8 *)card->shmem + STARTCPU_P; + card->stopcpu = (__u8 *)card->shmem + STOPCPU_P; + break; + default: + printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type); + return -EINVAL; + } + + /* Register shmem */ + if (check_shmem((unsigned long)card->shmem, card->ramsize)) { + printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n", + (unsigned long)card->shmem); + kfree(code); + return -EBUSY; + } + request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN"); + card->mvalid = 1; + + /* clear any pending irq's */ + readb(card->intack); + /* set reset-line active */ + writeb(0, card->stopcpu); + /* clear irq-requests */ + writeb(0, card->intack); + readb(card->intack); + + /* Copy code into card */ + memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len); + + /* Check for properly loaded code */ + if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) { + printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n"); + eicon_isa_release_shmem(card); + kfree(code); + return -EIO; + } + /* if 16k-ramsize, duplicate the reset-jump-code */ + if (card->ramsize == RAMSIZE_P) + memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12); + + kfree(code); + boot = &card->shmem->boot; + + /* Delay 0.2 sec. */ + SLEEP(20); + + /* Start CPU */ + writeb(cbuf.boot_opt, &boot->ctrl); + writeb(0, card->startcpu); + + /* Delay 0.2 sec. */ + SLEEP(20); + + timeout = jiffies + (HZ * 22); + while (timeout > jiffies) { + if (readb(&boot->ctrl) == 0) + break; + SLEEP(10); + } + if (readb(&boot->ctrl) != 0) { + printk(KERN_WARNING "eicon_isa_boot: CPU test failed\n"); + eicon_isa_release_shmem(card); + return -EIO; + } + + /* Check for memory-test errors */ + if (readw(&boot->ebit)) { + printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n", + readw(&boot->ebit), readl(&boot->eloc)); + eicon_isa_release_shmem(card); + return -EIO; + } + + /* Check card type and memory size */ + tmp = readb(&boot->card); + if ((tmp < 0) || (tmp > 4)) { + printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n"); + eicon_isa_release_shmem(card); + return -EIO; + } + card->type = tmp; + ((eicon_card *)card->card)->type = tmp; + + tmp = readb(&boot->msize); + if (tmp != 8 && tmp != 16 && tmp != 24 && + tmp != 32 && tmp != 48 && tmp != 60) { + printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n"); + eicon_isa_release_shmem(card); + return -EIO; + } + printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); + if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) { + tmp = eicon_addcard(card->type, (unsigned long)card->shmem, card->irq, + ((eicon_card *)card->card)->regname); + printk(KERN_INFO "Eicon: %d adapters added\n", tmp); + } + return 0; +} + +int +eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { + eicon_isa_boot *boot; + int tmp; + int timeout; + int j; + eicon_isa_codebuf cbuf; + unsigned char *code; + unsigned char *p; + + if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf))) + return -EFAULT; + + if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) { + printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n"); + return -ENOMEM; + } + + if (copy_from_user(code, &cb->code, cbuf.firmware_len)) { + kfree(code); + return -EFAULT; + } + + boot = &card->shmem->boot; + + if ((!card->ivalid) && card->master) { + card->irqprobe = 1; + /* Check for valid IRQ */ + if ((card->irq < 0) || (card->irq > 15) || + (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) { + printk(KERN_WARNING "eicon_isa_boot: illegal irq: %d\n", card->irq); + eicon_isa_release_shmem(card); + kfree(code); + return -EINVAL; + } + /* Register irq */ + if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card)) + card->ivalid = 1; + else { + printk(KERN_WARNING "eicon_isa_boot: irq %d already in use.\n", + card->irq); + eicon_isa_release_shmem(card); + kfree(code); + return -EBUSY; + } + } + + tmp = readb(&boot->msize); + if (tmp != 8 && tmp != 16 && tmp != 24 && + tmp != 32 && tmp != 48 && tmp != 60) { + printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n"); + eicon_isa_release_shmem(card); + return -EIO; + } + + eicon_isa_printpar(card); + + /* Download firmware */ + printk(KERN_INFO "%s %dkB, loading firmware ...\n", + eicon_ctype_name[card->type], + tmp * 16); + tmp = cbuf.firmware_len >> 8; + p = code; + while (tmp--) { + memcpy_toio(&boot->b, p, 256); + writeb(1, &boot->ctrl); + timeout = jiffies + 10; + while (timeout > jiffies) { + if (readb(&boot->ctrl) == 0) + break; + SLEEP(2); + } + if (readb(&boot->ctrl)) { + printk(KERN_WARNING "eicon_isa_boot: download timeout at 0x%x\n", p-code); + eicon_isa_release(card); + kfree(code); + return -EIO; + } + p += 256; + } + kfree(code); + + /* Initialize firmware parameters */ + memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14); + memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96); + memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96); + + /* Start firmware, wait for signature */ + writeb(2, &boot->ctrl); + timeout = jiffies + (5*HZ); + while (timeout > jiffies) { + if (readw(&boot->signature) == 0x4447) + break; + SLEEP(2); + } + if (readw(&boot->signature) != 0x4447) { + printk(KERN_WARNING "eicon_isa_boot: firmware selftest failed %04x\n", + readw(&boot->signature)); + eicon_isa_release(card); + return -EIO; + } + + card->channels = readb(&card->shmem->c[0x3f6]); + + /* clear irq-requests, reset irq-count */ + readb(card->intack); + writeb(0, card->intack); + + if (card->master) { + card->irqprobe = 1; + /* Trigger an interrupt and check if it is delivered */ + tmp = readb(&card->shmem->com.ReadyInt); + tmp ++; + writeb(tmp, &card->shmem->com.ReadyInt); + timeout = jiffies + 20; + while (timeout > jiffies) { + if (card->irqprobe > 1) + break; + SLEEP(2); + } + if (card->irqprobe == 1) { + printk(KERN_WARNING "eicon_isa_boot: IRQ test failed\n"); + eicon_isa_release(card); + return -EIO; + } + } + writeb(card->irq, &card->shmem->com.Int); + + /* initializing some variables */ + ((eicon_card *)card->card)->ReadyInt = 0; + ((eicon_card *)card->card)->ref_in = 1; + ((eicon_card *)card->card)->ref_out = 1; + for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; + for(j=0; j< (card->channels + 1); j++) { + ((eicon_card *)card->card)->bch[j].e.busy = 0; + ((eicon_card *)card->card)->bch[j].e.D3Id = 0; + ((eicon_card *)card->card)->bch[j].e.B2Id = 0; + ((eicon_card *)card->card)->bch[j].e.ref = 0; + ((eicon_card *)card->card)->bch[j].e.Req = 0; + ((eicon_card *)card->card)->bch[j].e.complete = 1; + ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; + } + + printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels); + printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]); + + /* Enable normal IRQ processing */ + card->irqprobe = 0; + return 0; +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_isa.h linux/drivers/isdn/eicon/eicon_isa.h --- v2.2.10/linux/drivers/isdn/eicon/eicon_isa.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_isa.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,144 @@ +/* $Id: eicon_isa.h,v 1.3 1999/03/29 11:19:47 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * + * Copyright 1998 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_isa.h,v $ + * Revision 1.3 1999/03/29 11:19:47 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.2 1999/03/02 12:37:46 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.1 1999/01/01 18:09:44 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#ifndef eicon_isa_h +#define eicon_isa_h + +#ifdef __KERNEL__ + +/* Factory defaults for ISA-Cards */ +#define EICON_ISA_MEMBASE 0xd0000 +#define EICON_ISA_IRQ 3 +/* shmem offset for Quadro parts */ +#define EICON_ISA_QOFFSET 0x0800 + +typedef struct { + __u16 length __attribute__ ((packed)); /* length of data/parameter field */ + __u8 P[270]; /* data/parameter field */ +} eicon_scom_PBUFFER; + +/* General communication buffer */ +typedef struct { + __u8 Req; /* request register */ + __u8 ReqId; /* request task/entity identification */ + __u8 Rc; /* return code register */ + __u8 RcId; /* return code task/entity identification */ + __u8 Ind; /* Indication register */ + __u8 IndId; /* Indication task/entity identification */ + __u8 IMask; /* Interrupt Mask Flag */ + __u8 RNR; /* Receiver Not Ready (set by PC) */ + __u8 XLock; /* XBuffer locked Flag */ + __u8 Int; /* ISDN interrupt */ + __u8 ReqCh; /* Channel field for layer-3 Requests */ + __u8 RcCh; /* Channel field for layer-3 Returncodes */ + __u8 IndCh; /* Channel field for layer-3 Indications */ + __u8 MInd; /* more data indication field */ + __u16 MLength; /* more data total packet length */ + __u8 ReadyInt; /* request field for ready interrupt */ + __u8 Reserved[12]; /* reserved space */ + __u8 IfType; /* 1 = 16k-Interface */ + __u16 Signature __attribute__ ((packed)); /* ISDN adapter Signature */ + eicon_scom_PBUFFER XBuffer; /* Transmit Buffer */ + eicon_scom_PBUFFER RBuffer; /* Receive Buffer */ +} eicon_isa_com; + +/* struct for downloading firmware */ +typedef struct { + __u8 ctrl; + __u8 card; + __u8 msize; + __u8 fill0; + __u16 ebit __attribute__ ((packed)); + __u32 eloc __attribute__ ((packed)); + __u8 reserved[20]; + __u16 signature __attribute__ ((packed)); + __u8 fill[224]; + __u8 b[256]; +} eicon_isa_boot; + +/* Shared memory */ +typedef union { + unsigned char c[0x400]; + eicon_isa_com com; + eicon_isa_boot boot; +} eicon_isa_shmem; + +/* + * card's description + */ +typedef struct { + int ramsize; + int irq; /* IRQ */ + void* card; + eicon_isa_shmem* shmem; /* Shared-memory area */ + unsigned char* intack; /* Int-Acknowledge */ + unsigned char* stopcpu; /* Writing here stops CPU */ + unsigned char* startcpu; /* Writing here starts CPU */ + unsigned char type; /* card type */ + int channels; /* No. of channels */ + unsigned char irqprobe; /* Flag: IRQ-probing */ + unsigned char mvalid; /* Flag: Memory is valid */ + unsigned char ivalid; /* Flag: IRQ is valid */ + unsigned char master; /* Flag: Card ist Quadro 1/4 */ + void* generic; /* Ptr to generic card struct */ +} eicon_isa_card; + +/* Offsets for special locations on standard cards */ +#define INTACK 0x03fe +#define STOPCPU 0x0400 +#define STARTCPU 0x0401 +#define RAMSIZE 0x0400 +/* Offsets for special location on PRI card */ +#define INTACK_P 0x3ffc +#define STOPCPU_P 0x3ffe +#define STARTCPU_P 0x3fff +#define RAMSIZE_P 0x4000 + + +extern int eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb); +extern int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb); +extern void eicon_isa_release(eicon_isa_card *card); +extern void eicon_isa_printpar(eicon_isa_card *card); +extern void eicon_isa_transmit(eicon_isa_card *card); +extern int eicon_isa_find_card(int Mem, int Irq, char * Id); + +#endif /* __KERNEL__ */ + +#endif /* eicon_isa_h */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.2.10/linux/drivers/isdn/eicon/eicon_mod.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_mod.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1460 @@ +/* $Id: eicon_mod.c,v 1.7 1999/07/11 17:16:27 armin Exp $ + * + * ISDN lowlevel-module for Eicon.Diehl active cards. + * + * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * documents, informations and hardware. + * + * Deutsche Telekom AG for S2M support. + * + * 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, 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. + * + * $Log: eicon_mod.c,v $ + * Revision 1.7 1999/07/11 17:16:27 armin + * Bugfixes in queue handling. + * Added DSP-DTMF decoder functions. + * Reorganized ack_handler. + * + * Revision 1.6 1999/06/09 19:31:26 armin + * Wrong PLX size for request_region() corrected. + * Added first MCA code from Erik Weber. + * + * Revision 1.5 1999/04/01 12:48:35 armin + * Changed some log outputs. + * + * Revision 1.4 1999/03/29 11:19:47 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.3 1999/03/02 12:37:47 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.2 1999/01/24 20:14:21 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.1 1999/01/01 18:09:44 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#include +#include +#include +#ifdef CONFIG_MCA +#include +#endif + +#include "eicon.h" + +#define INCLUDE_INLINE_FUNCS + +static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains + start of card-list */ + +static char *eicon_revision = "$Revision: 1.7 $"; + +extern char *eicon_pci_revision; +extern char *eicon_isa_revision; +extern char *eicon_idi_revision; + +#ifdef MODULE +#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) +#endif + +#define EICON_CTRL_VERSION 1 + +ulong DebugVar; + +/* Parameters to be set by insmod */ +static int membase = -1; +static int irq = -1; +static char *id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + +MODULE_DESCRIPTION( "Driver for Eicon.Diehl active ISDN cards"); +MODULE_AUTHOR( "Armin Schindler"); +MODULE_SUPPORTED_DEVICE( "ISDN subsystem"); +MODULE_PARM_DESC(membase, "Base address of first ISA card"); +MODULE_PARM_DESC(irq, "IRQ of first card"); +MODULE_PARM_DESC(id, "ID-String of first card"); +MODULE_PARM(membase, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(id, "s"); + +char *eicon_ctype_name[] = { + "ISDN-S", + "ISDN-SX", + "ISDN-SCOM", + "ISDN-QUADRO", + "ISDN-S2M", + "DIVA Server BRI/PCI", + "DIVA Server 4BRI/PCI", + "DIVA Server 4BRI/PCI", + "DIVA Server PRI/PCI" +}; + +static int +getrel(char *p) +{ + int v = 0; + char *tmp = 0; + + if ((tmp = strchr(p, '.'))) + p = tmp + 1; + while (p[0] >= '0' && p[0] <= '9') { + v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0'); + p++; + } + return v; + + +} + +static char * +eicon_getrev(const char *revision) +{ + char *rev; + char *p; + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else rev = "?.??"; + return rev; + +} + +static eicon_chan * +find_channel(eicon_card *card, int channel) +{ + if ((channel >= 0) && (channel < card->nchannels)) + return &(card->bch[channel]); + if (DebugVar & 1) + printk(KERN_WARNING "eicon: Invalid channel %d\n", channel); + return NULL; +} + +/* + * Free MSN list + */ +static void +eicon_clear_msn(eicon_card *card) +{ + struct msn_entry *p = card->msn_list; + struct msn_entry *q; + unsigned long flags; + + save_flags(flags); + cli(); + card->msn_list = NULL; + restore_flags(flags); + while (p) { + q = p->next; + kfree(p); + p = q; + } +} + +/* + * Find an MSN entry in the list. + * If ia5 != 0, return IA5-encoded EAZ, else + * return a bitmask with corresponding bit set. + */ +static __u16 +eicon_find_msn(eicon_card *card, char *msn, int ia5) +{ + struct msn_entry *p = card->msn_list; + __u8 eaz = '0'; + + while (p) { + if (!strcmp(p->msn, msn)) { + eaz = p->eaz; + break; + } + p = p->next; + } + if (!ia5) + return (1 << (eaz - '0')); + else + return eaz; +} + +/* + * Find an EAZ entry in the list. + * return a string with corresponding msn. + */ +char * +eicon_find_eaz(eicon_card *card, char eaz) +{ + struct msn_entry *p = card->msn_list; + + while (p) { + if (p->eaz == eaz) + return(p->msn); + p = p->next; + } + return("\0"); +} + +#if 0 +/* + * Add or delete an MSN to the MSN list + * + * First character of msneaz is EAZ, rest is MSN. + * If length of eazmsn is 1, delete that entry. + */ +static int +eicon_set_msn(eicon_card *card, char *eazmsn) +{ + struct msn_entry *p = card->msn_list; + struct msn_entry *q = NULL; + unsigned long flags; + int i; + + if (!strlen(eazmsn)) + return 0; + if (strlen(eazmsn) > 16) + return -EINVAL; + for (i = 0; i < strlen(eazmsn); i++) + if (!isdigit(eazmsn[i])) + return -EINVAL; + if (strlen(eazmsn) == 1) { + /* Delete a single MSN */ + while (p) { + if (p->eaz == eazmsn[0]) { + save_flags(flags); + cli(); + if (q) + q->next = p->next; + else + card->msn_list = p->next; + restore_flags(flags); + kfree(p); + if (DebugVar & 8) + printk(KERN_DEBUG + "Mapping for EAZ %c deleted\n", + eazmsn[0]); + return 0; + } + q = p; + p = p->next; + } + return 0; + } + /* Add a single MSN */ + while (p) { + /* Found in list, replace MSN */ + if (p->eaz == eazmsn[0]) { + save_flags(flags); + cli(); + strcpy(p->msn, &eazmsn[1]); + restore_flags(flags); + if (DebugVar & 8) + printk(KERN_DEBUG + "Mapping for EAZ %c changed to %s\n", + eazmsn[0], + &eazmsn[1]); + return 0; + } + p = p->next; + } + /* Not found in list, add new entry */ + p = kmalloc(sizeof(msn_entry), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->eaz = eazmsn[0]; + strcpy(p->msn, &eazmsn[1]); + p->next = card->msn_list; + save_flags(flags); + cli(); + card->msn_list = p; + restore_flags(flags); + if (DebugVar & 8) + printk(KERN_DEBUG + "Mapping %c -> %s added\n", + eazmsn[0], + &eazmsn[1]); + return 0; +} +#endif + +static void +eicon_rcv_dispatch(struct eicon_card *card) +{ + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + case EICON_BUS_PCI: + eicon_io_rcv_dispatch(card); + break; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon_ack_dispatch: Illegal bustype %d\n", card->bus); + } +} + +static void +eicon_ack_dispatch(struct eicon_card *card) +{ + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + case EICON_BUS_PCI: + eicon_io_ack_dispatch(card); + break; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon_ack_dispatch: Illegal bustype %d\n", card->bus); + } +} + +static void +eicon_transmit(struct eicon_card *card) +{ + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + case EICON_BUS_PCI: + eicon_io_transmit(card); + break; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon_transmit: Illegal bustype %d\n", card->bus); + } +} + +static int +eicon_command(eicon_card * card, isdn_ctrl * c) +{ + ulong a; + eicon_chan *chan; + eicon_cdef cdef; + isdn_ctrl cmd; + char tmp[17]; + int ret = 0; + unsigned long flags; + + switch (c->command) { + case ISDN_CMD_IOCTL: + memcpy(&a, c->parm.num, sizeof(ulong)); + switch (c->arg) { + case EICON_IOCTL_GETVER: + return(EICON_CTRL_VERSION); + case EICON_IOCTL_GETTYPE: + return(card->type); + case EICON_IOCTL_GETMMIO: + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + return (int)card->hwif.isa.shmem; +#if CONFIG_PCI + case EICON_BUS_PCI: + return card->hwif.pci.PCIram; +#endif + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + case EICON_IOCTL_SETMMIO: + if (card->flags & EICON_FLAGS_LOADED) + return -EBUSY; + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + if (eicon_isa_find_card(a, + card->hwif.isa.irq, + card->regname) < 0) + return -EFAULT; + card->hwif.isa.shmem = (eicon_isa_shmem *)a; + return 0; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + case EICON_IOCTL_GETIRQ: + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + return card->hwif.isa.irq; +#if CONFIG_PCI + case EICON_BUS_PCI: + return card->hwif.pci.irq; +#endif + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + case EICON_IOCTL_SETIRQ: + if (card->flags & EICON_FLAGS_LOADED) + return -EBUSY; + if ((a < 2) || (a > 15)) + return -EFAULT; + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + card->hwif.isa.irq = a; + return 0; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + case EICON_IOCTL_LOADBOOT: + if (card->flags & EICON_FLAGS_RUNNING) + return -EBUSY; + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + ret = eicon_isa_bootload( + &(card->hwif.isa), + &(((eicon_codebuf *)a)->isa)); + break; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + return ret; + case EICON_IOCTL_LOADISA: + if (card->flags & EICON_FLAGS_RUNNING) + return -EBUSY; + switch (card->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + ret = eicon_isa_load( + &(card->hwif.isa), + &(((eicon_codebuf *)a)->isa)); + if (!ret) { + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + if (card->hwif.isa.channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->hwif.isa.channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + break; + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Illegal BUS type %d\n", + card->bus); + ret = -ENODEV; + } + return ret; + + case EICON_IOCTL_MANIF: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!card->Feature & PROTCAP_MANIF) + return -ENODEV; + ret = eicon_idi_manage( + card, + (eicon_manifbuf *)a); + return ret; +#if CONFIG_PCI + case EICON_IOCTL_LOADPCI: + if (card->flags & EICON_FLAGS_RUNNING) + return -EBUSY; + if (card->bus == EICON_BUS_PCI) { + switch(card->type) { + case EICON_CTYPE_MAESTRA: + ret = eicon_pci_load_bri( + &(card->hwif.pci), + &(((eicon_codebuf *)a)->pci)); + break; + + case EICON_CTYPE_MAESTRAP: + ret = eicon_pci_load_pri( + &(card->hwif.pci), + &(((eicon_codebuf *)a)->pci)); + break; + } + if (!ret) { + card->flags |= EICON_FLAGS_LOADED; + card->flags |= EICON_FLAGS_RUNNING; + if (card->hwif.pci.channels > 1) { + cmd.command = ISDN_STAT_ADDCH; + cmd.driver = card->myid; + cmd.arg = card->hwif.pci.channels - 1; + card->interface.statcallb(&cmd); + } + cmd.command = ISDN_STAT_RUN; + cmd.driver = card->myid; + cmd.arg = 0; + card->interface.statcallb(&cmd); + } + return ret; + } else return -ENODEV; +#endif +#if 0 + case EICON_IOCTL_SETMSN: + if ((ret = copy_from_user(tmp, (char *)a, sizeof(tmp)))) + return -EFAULT; + if ((ret = eicon_set_msn(card, tmp))) + return ret; +#if 0 + if (card->flags & EICON_FLAGS_RUNNING) + return(eicon_capi_manufacturer_req_msn(card)); +#endif + return 0; +#endif + case EICON_IOCTL_ADDCARD: + if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef)))) + return -EFAULT; + if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id))) + return -EIO; + return 0; + case EICON_IOCTL_DEBUGVAR: + DebugVar = a; + printk(KERN_DEBUG"Eicon: Debug Value set to %ld\n", DebugVar); + return 0; +#ifdef MODULE + case EICON_IOCTL_FREEIT: + while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; + MOD_INC_USE_COUNT; + return 0; +#endif + default: + return -EINVAL; + } + break; + case ISDN_CMD_DIAL: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + save_flags(flags); + cli(); + if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) { + restore_flags(flags); + if (DebugVar & 1) + printk(KERN_WARNING "Dial on channel %d with state %d\n", + chan->No, chan->fsm_state); + return -EBUSY; + } + if (card->ptype == ISDN_PTYPE_EURO) + tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1); + else + tmp[0] = c->parm.setup.eazmsn[0]; + chan->fsm_state = EICON_STATE_OCALL; + chan->callref = 0xffff; + restore_flags(flags); + + ret = idi_connect_req(card, chan, c->parm.setup.phone, + c->parm.setup.eazmsn, + c->parm.setup.si1, + c->parm.setup.si2); + if (ret) { + cmd.driver = card->myid; + cmd.command = ISDN_STAT_DHUP; + cmd.arg &= 0x1f; + card->interface.statcallb(&cmd); + } + return ret; + case ISDN_CMD_ACCEPTD: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (chan->fsm_state == EICON_STATE_ICALL) { + idi_connect_res(card, chan); + } + return 0; + case ISDN_CMD_ACCEPTB: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + return 0; + case ISDN_CMD_HANGUP: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + idi_hangup(card, chan); + return 0; + case ISDN_CMD_SETEAZ: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (strlen(c->parm.num)) { + if (card->ptype == ISDN_PTYPE_EURO) { + chan->eazmask = eicon_find_msn(card, c->parm.num, 0); + } + if (card->ptype == ISDN_PTYPE_1TR6) { + int i; + chan->eazmask = 0; + for (i = 0; i < strlen(c->parm.num); i++) + if (isdigit(c->parm.num[i])) + chan->eazmask |= (1 << (c->parm.num[i] - '0')); + } + } else + chan->eazmask = 0x3ff; + eicon_idi_listen_req(card, chan); + return 0; + case ISDN_CMD_CLREAZ: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + chan->eazmask = 0; + eicon_idi_listen_req(card, chan); + return 0; + case ISDN_CMD_SETL2: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + chan->l2prot = (c->arg >> 8); + return 0; + case ISDN_CMD_GETL2: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + return chan->l2prot; + case ISDN_CMD_SETL3: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + chan->l3prot = (c->arg >> 8); + return 0; + case ISDN_CMD_GETL3: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + return chan->l3prot; + case ISDN_CMD_GETEAZ: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (DebugVar & 1) + printk(KERN_DEBUG "eicon CMD_GETEAZ not implemented\n"); + return 0; + case ISDN_CMD_SETSIL: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (DebugVar & 1) + printk(KERN_DEBUG "eicon CMD_SETSIL not implemented\n"); + return 0; + case ISDN_CMD_GETSIL: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (DebugVar & 1) + printk(KERN_DEBUG "eicon CMD_GETSIL not implemented\n"); + return 0; + case ISDN_CMD_LOCK: + MOD_INC_USE_COUNT; + return 0; + case ISDN_CMD_UNLOCK: + MOD_DEC_USE_COUNT; + return 0; + case ISDN_CMD_AUDIO: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num); + return 0; + } + + return -EINVAL; +} + +/* + * Find card with given driverId + */ +static inline eicon_card * +eicon_findcard(int driverid) +{ + eicon_card *p = cards; + + while (p) { + if (p->myid == driverid) + return p; + p = p->next; + } + return (eicon_card *) 0; +} + +/* + * Wrapper functions for interface to linklevel + */ +static int +if_command(isdn_ctrl * c) +{ + eicon_card *card = eicon_findcard(c->driver); + + if (card) + return (eicon_command(card, c)); + printk(KERN_ERR + "eicon: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); + return -ENODEV; +} + +static int +if_writecmd(const u_char * buf, int len, int user, int id, int channel) +{ + eicon_card *card = eicon_findcard(id); + + if (card) { + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + return (len); + } + printk(KERN_ERR + "eicon: if_writecmd called with invalid driverId!\n"); + return -ENODEV; +} + +static int +if_readstatus(u_char * buf, int len, int user, int id, int channel) +{ +#if 0 + /* Not yet used */ + eicon_card *card = eicon_findcard(id); + + if (card) { + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + return (eicon_readstatus(buf, len, user, card)); + } + printk(KERN_ERR + "eicon: if_readstatus called with invalid driverId!\n"); +#endif + return -ENODEV; +} + +static int +if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) +{ + eicon_card *card = eicon_findcard(id); + eicon_chan *chan; + int ret = 0; + int len; + + len = skb->len; + + if (card) { + if (!card->flags & EICON_FLAGS_RUNNING) { + dev_kfree_skb(skb); + return -ENODEV; + } + if (!(chan = find_channel(card, channel))) { + dev_kfree_skb(skb); + return -ENODEV; + } + if (chan->fsm_state == EICON_STATE_ACTIVE) { + ret = idi_send_data(card, chan, ack, skb, 1); + return (ret); + } else { + dev_kfree_skb(skb); + return -ENODEV; + } + } + printk(KERN_ERR + "eicon: if_sendbuf called with invalid driverId!\n"); + dev_kfree_skb(skb); + return -ENODEV; +} + + +/* + * Allocate a new card-struct, initialize it + * link it into cards-list. + */ +static void +eicon_alloccard(int Type, int membase, int irq, char *id) +{ + int i; + int j; + int qloop; + char qid[5]; + eicon_card *card; +#if CONFIG_PCI + eicon_pci_card *pcic; +#endif + + qloop = (Type == EICON_CTYPE_QUADRO)?2:0; + for (i = 0; i <= qloop; i++) { + if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) { + printk(KERN_WARNING + "eicon: (%s) Could not allocate card-struct.\n", id); + return; + } + memset((char *) card, 0, sizeof(eicon_card)); + skb_queue_head_init(&card->sndq); + skb_queue_head_init(&card->rcvq); + skb_queue_head_init(&card->rackq); + skb_queue_head_init(&card->sackq); + card->snd_tq.routine = (void *) (void *) eicon_transmit; + card->snd_tq.data = card; + card->rcv_tq.routine = (void *) (void *) eicon_rcv_dispatch; + card->rcv_tq.data = card; + card->ack_tq.routine = (void *) (void *) eicon_ack_dispatch; + card->ack_tq.data = card; + card->interface.maxbufsize = 4000; + card->interface.command = if_command; + card->interface.writebuf_skb = if_sendbuf; + card->interface.writecmd = if_writecmd; + card->interface.readstat = if_readstatus; + card->interface.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_P_UNKNOWN; + card->interface.hl_hdrlen = 20; + card->ptype = ISDN_PTYPE_UNKNOWN; + strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); + card->myid = -1; + card->type = Type; + switch (Type) { +#if CONFIG_MCA /* only needed for MCA */ + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + if (membase == -1) + membase = EICON_ISA_MEMBASE; + if (irq == -1) + irq = EICON_ISA_IRQ; + card->bus = EICON_BUS_MCA; + card->hwif.isa.card = (void *)card; + card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.master = 1; + + card->hwif.isa.irq = irq; + card->hwif.isa.type = Type; + card->nchannels = 2; + card->interface.channels = 1; + break; +#endif /* CONFIG_MCA */ + case EICON_CTYPE_QUADRO: + if (membase == -1) + membase = EICON_ISA_MEMBASE; + if (irq == -1) + irq = EICON_ISA_IRQ; + card->bus = EICON_BUS_ISA; + card->hwif.isa.card = (void *)card; + card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET); + card->hwif.isa.master = 0; + strcpy(card->interface.id, id); + if (id[strlen(id) - 1] == 'a') { + card->interface.id[strlen(id) - 1] = 'a' + i + 1; + } else { + sprintf(qid, "_%c",'2' + i); + strcat(card->interface.id, qid); + } + printk(KERN_INFO "Eicon: Quadro: Driver-Id %s added.\n", + card->interface.id); + if (i == 0) { + eicon_card *p = cards; + while(p) { + if ((p->hwif.isa.master) && (p->hwif.isa.irq == irq)) { + p->qnext = card; + break; + } + p = p->next; + } + if (!p) { + printk(KERN_WARNING "eicon_alloccard: Quadro Master not found.\n"); + kfree(card); + return; + } + } else { + cards->qnext = card; + } + card->hwif.isa.irq = irq; + card->hwif.isa.type = Type; + card->nchannels = 2; + card->interface.channels = 1; + break; +#if CONFIG_PCI + case EICON_CTYPE_MAESTRA: + (eicon_pci_card *)pcic = (eicon_pci_card *)membase; + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FAX; + card->hwif.pci.card = (void *)card; + card->hwif.pci.PCIreg = pcic->PCIreg; + card->hwif.pci.PCIcfg = pcic->PCIcfg; + card->hwif.pci.master = 1; + card->hwif.pci.mvalid = pcic->mvalid; + card->hwif.pci.ivalid = 0; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 2; + card->interface.channels = 1; + break; + + case EICON_CTYPE_MAESTRAP: + (eicon_pci_card *)pcic = (eicon_pci_card *)membase; + card->bus = EICON_BUS_PCI; + card->interface.features |= + ISDN_FEATURE_L2_V11096 | + ISDN_FEATURE_L2_V11019 | + ISDN_FEATURE_L2_V11038 | + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_FAX | + ISDN_FEATURE_L3_TRANSDSP | + ISDN_FEATURE_L3_FAX; + card->hwif.pci.card = (void *)card; + card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem; + card->hwif.pci.PCIreg = pcic->PCIreg; + card->hwif.pci.PCIram = pcic->PCIram; + card->hwif.pci.PCIcfg = pcic->PCIcfg; + card->hwif.pci.master = 1; + card->hwif.pci.mvalid = pcic->mvalid; + card->hwif.pci.ivalid = 0; + card->hwif.pci.irq = irq; + card->hwif.pci.type = Type; + card->flags = 0; + card->nchannels = 30; + card->interface.channels = 1; + break; +#endif + case EICON_CTYPE_ISABRI: + if (membase == -1) + membase = EICON_ISA_MEMBASE; + if (irq == -1) + irq = EICON_ISA_IRQ; + card->bus = EICON_BUS_ISA; + card->hwif.isa.card = (void *)card; + card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.master = 1; + card->hwif.isa.irq = irq; + card->hwif.isa.type = Type; + card->nchannels = 2; + card->interface.channels = 1; + break; + case EICON_CTYPE_ISAPRI: + if (membase == -1) + membase = EICON_ISA_MEMBASE; + if (irq == -1) + irq = EICON_ISA_IRQ; + card->bus = EICON_BUS_ISA; + card->hwif.isa.card = (void *)card; + card->hwif.isa.shmem = (eicon_isa_shmem *)membase; + card->hwif.isa.master = 1; + card->hwif.isa.irq = irq; + card->hwif.isa.type = Type; + card->nchannels = 30; + card->interface.channels = 1; + break; + default: + printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type); + kfree(card); + return; + } + if (!(card->bch = (eicon_chan *) kmalloc(sizeof(eicon_chan) * (card->nchannels + 1) + , GFP_KERNEL))) { + printk(KERN_WARNING + "eicon: (%s) Could not allocate bch-struct.\n", id); + kfree(card); + return; + } + for (j=0; j< (card->nchannels + 1); j++) { + memset((char *)&card->bch[j], 0, sizeof(eicon_chan)); + card->bch[j].plci = 0x8000; + card->bch[j].ncci = 0x8000; + card->bch[j].l2prot = ISDN_PROTO_L2_X75I; + card->bch[j].l3prot = ISDN_PROTO_L3_TRANS; + card->bch[j].e.D3Id = 0; + card->bch[j].e.B2Id = 0; + card->bch[j].e.Req = 0; + card->bch[j].No = j; + skb_queue_head_init(&card->bch[j].e.X); + skb_queue_head_init(&card->bch[j].e.R); + } + card->next = cards; + cards = card; + } +} + +/* + * register card at linklevel + */ +static int +eicon_registercard(eicon_card * card) +{ + switch (card->bus) { + case EICON_BUS_ISA: + /* TODO something to print */ + break; +#ifdef CONFIG_MCA + case EICON_BUS_MCA: + eicon_isa_printpar(&card->hwif.isa); + break; +#endif + case EICON_BUS_PCI: +#if CONFIG_PCI + eicon_pci_printpar(&card->hwif.pci); + break; +#endif + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon_registercard: Illegal BUS type %d\n", + card->bus); + return -1; + } + if (!register_isdn(&card->interface)) { + printk(KERN_WARNING + "eicon_registercard: Unable to register %s\n", + card->interface.id); + return -1; + } + card->myid = card->interface.channels; + sprintf(card->regname, "%s", card->interface.id); + return 0; +} + +#ifdef MODULE +static void +unregister_card(eicon_card * card) +{ + isdn_ctrl cmd; + + cmd.command = ISDN_STAT_UNLOAD; + cmd.driver = card->myid; + card->interface.statcallb(&cmd); + switch (card->bus) { + case EICON_BUS_ISA: +#ifdef CONFIG_MCA + case EICON_BUS_MCA: +#endif + eicon_isa_release(&card->hwif.isa); + break; + case EICON_BUS_PCI: +#if CONFIG_PCI + eicon_pci_release(&card->hwif.pci); + break; +#endif + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: Invalid BUS type %d\n", + card->bus); + break; + } +} +#endif /* MODULE */ + +static void +eicon_freecard(eicon_card *card) { + eicon_clear_msn(card); + kfree(card->bch); + kfree(card); +} + +int +eicon_addcard(int Type, int membase, int irq, char *id) +{ + eicon_card *p; + eicon_card *q = NULL; + int registered; + int added = 0; + int failed = 0; + + if (!Type) /* ISA */ + if ((Type = eicon_isa_find_card(membase, irq, id)) < 0) + return 0; + eicon_alloccard(Type, membase, irq, id); + p = cards; + while (p) { + registered = 0; + if (!p->interface.statcallb) { + /* Not yet registered. + * Try to register and activate it. + */ + added++; + switch (p->bus) { + case EICON_BUS_ISA: + case EICON_BUS_MCA: + if (eicon_registercard(p)) + break; + registered = 1; + break; + case EICON_BUS_PCI: +#if CONFIG_PCI + if (eicon_registercard(p)) + break; + registered = 1; + break; +#endif + default: + if (DebugVar & 1) + printk(KERN_WARNING + "eicon: addcard: Invalid BUS type %d\n", + p->bus); + } + } else + /* Card already registered */ + registered = 1; + if (registered) { + /* Init OK, next card ... */ + q = p; + p = p->next; + } else { + /* registering failed, remove card from list, free memory */ + printk(KERN_WARNING + "eicon: Initialization of %s failed\n", + p->interface.id); + if (q) { + q->next = p->next; + eicon_freecard(p); + p = q->next; + } else { + cards = p->next; + eicon_freecard(p); + p = cards; + } + failed++; + } + } + return (added - failed); +} + +#define DRIVERNAME "Eicon active ISDN driver" +#define DRIVERRELEASE "1" + +#ifdef MODULE +#define eicon_init init_module +#endif + +__initfunc(int +eicon_init(void)) +{ + int card_count = 0; + int release = 0; + char tmprev[50]; + + DebugVar = 1; + + printk(KERN_INFO "%s Rev: ", DRIVERNAME); + strcpy(tmprev, eicon_revision); + printk("%s/", eicon_getrev(tmprev)); + release += getrel(tmprev); + strcpy(tmprev, eicon_pci_revision); + printk("%s/", eicon_getrev(tmprev)); + release += getrel(tmprev); + strcpy(tmprev, eicon_isa_revision); + printk("%s/", eicon_getrev(tmprev)); + release += getrel(tmprev); + strcpy(tmprev, eicon_idi_revision); + printk("%s\n", eicon_getrev(tmprev)); + release += getrel(tmprev); + sprintf(tmprev,"%d", release); + printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME, + DRIVERRELEASE, tmprev); + +#ifdef CONFIG_MCA + /* Check if we have MCA-bus */ + if (!MCA_bus) + { + printk(KERN_INFO + "eicon: No MCA bus, ISDN-interfaces not probed.\n"); + } else { + if (DebugVar & 8) + printk(KERN_DEBUG + "eicon_mca_find_card, irq=%d.\n", + irq); + if (!eicon_mca_find_card(0, membase, irq, id)) + card_count++; + }; +#else + card_count = eicon_addcard(0, membase, irq, id); +#endif /* CONFIG_MCA */ + +#if CONFIG_PCI + card_count += eicon_pci_find_card(id); +#endif + if (!cards) { +#ifdef MODULE + printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n"); +#endif + return -ENODEV; + + } else + printk(KERN_INFO "Eicon: %d card%s added\n", card_count, + (card_count>1)?"s":""); + /* No symbols to export, hide all symbols */ + EXPORT_NO_SYMBOLS; + return 0; +} + +#ifdef MODULE +void +cleanup_module(void) +{ + eicon_card *card = cards; + eicon_card *last; + while (card) { +#ifdef CONFIG_MCA + if (MCA_bus) + { + mca_mark_as_unused (card->mca_slot); + mca_set_adapter_procfn(card->mca_slot, NULL, NULL); + }; +#endif + unregister_card(card); + card = card->next; + } + card = cards; + while (card) { + last = card; + card = card->next; + eicon_freecard(last); + } + printk(KERN_INFO "%s unloaded\n", DRIVERNAME); +} + +#else /* no module */ +__initfunc(void +eicon_setup(char *str, int *ints)) +{ + int i, argc; + + argc = ints[0]; + i = 1; + if (argc) { + membase = irq = -1; + if (argc) { + membase = ints[i]; + i++; + argc--; + } + if (argc) { + irq = ints[i]; + i++; + argc--; + } + if (strlen(str)) { + strcpy(id, str); + } else { + strcpy(id, "eicon"); + } + /* eicon_addcard(0, membase, irq, id); */ + printk(KERN_INFO "eicon: membase=0x%x irq=%d id=%s\n", membase, irq, id); + } +} +#endif /* MODULE */ + + +#ifdef CONFIG_MCA + +struct eicon_mca_adapters_struct { + char * name; + int adf_id; +}; +/* possible MCA-brands of eicon cards */ +struct eicon_mca_adapters_struct eicon_mca_adapters[] = { + { "ISDN-P/2 Adapter", 0x6abb }, + { "ISDN-[S|SX|SCOM]/2 Adapter", 0x6a93 }, + { "DIVA /MCA", 0x6336 }, + { NULL, 0 }, +}; + +int eicon_mca_find_card(int type, /* type-idx of eicon-card */ + int membase, + int irq, + char * id) /* name of eicon-isdn-dev */ +{ + int j, curr_slot = 0; + + if (DebugVar & 8) + printk(KERN_DEBUG + "eicon_mca_find_card type: %d, membase: %#x, irq %d \n", + type, membase, irq); + /* find a no-driver-assigned eicon card */ + for (j=0; eicon_mca_adapters[j].adf_id != 0; j++) + { + for ( curr_slot=0; curr_slot<=MCA_MAX_SLOT_NR; curr_slot++) + { + curr_slot = mca_find_unused_adapter( + eicon_mca_adapters[j].adf_id, curr_slot); + if (curr_slot != MCA_NOTFOUND) + { + /* check if pre-set parameters match + these of the card, check cards memory */ + if (!(int) eicon_mca_probe(curr_slot, + j, + membase, + irq, + id)) + { + return 0; + /* means: adapter parms did match */ + }; + }; + break; + /* MCA_NOTFOUND-branch: no matching adapter of + THIS flavor found, next flavor */ + + }; + }; + /* all adapter flavors checked without match, finito with: */ + return ENODEV; +}; + + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * stolen from 3c523.c/elmc_getinfo, ewe, 10.5.1999 + */ +int eicon_info(char * buf, int slot, void *d) +{ + int len = 0; + struct eicon_card *dev; + + dev = (struct eicon_card *) d; + + if (dev == NULL) + return len; + len += sprintf(buf+len, "eicon ISDN adapter, type %d.\n",dev->type); + len += sprintf(buf+len, "IRQ: %d\n", dev->hwif.isa.irq); + len += sprintf(buf+len, "MEMBASE: %#lx\n", (unsigned long)dev->hwif.isa.shmem); + + return len; +}; + +int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ + int a_idx, /* idx-nr of probed card in eicon_mca_adapters */ + int membase, + int irq, + char * id) /* name of eicon-isdn-dev */ +{ + unsigned char adf_pos0; + int cards_irq, cards_membase, cards_io; + int type = EICON_CTYPE_S; + int irq_array[]={0,3,4,2}; + int irq_array1[]={3,4,0,0,2,10,11,12}; + + adf_pos0 = mca_read_stored_pos(slot,2); + if (DebugVar & 8) + printk(KERN_DEBUG + "eicon_mca_probe irq=%d, membase=%d\n", + irq, + membase); + switch (a_idx) { + case 0: /* P/2-Adapter (== PRI/S2M ? ) */ + cards_membase= 0xC0000+((adf_pos0>>4)*0x4000); + if (membase == -1) { + membase = cards_membase; + } else { + if (membase != cards_membase) + return ENODEV; + }; + cards_irq=irq_array[((adf_pos0 & 0xC)>>2)]; + if (irq == -1) { + irq = cards_irq; + } else { + if (irq != irq) + return ENODEV; + }; + cards_io= 0xC00 + ((adf_pos0>>4)*0x10); + type = EICON_CTYPE_ISAPRI; + break; + + case 1: /* [S|SX|SCOM]/2 */ + cards_membase= 0xC0000+((adf_pos0>>4)*0x2000); + if (membase == -1) { + membase = cards_membase; + } else { + if (membase != cards_membase) + return ENODEV; + }; + cards_irq=irq_array[((adf_pos0 & 0xC)>>2)]; + if (irq == -1) { + irq = cards_irq; + } else { + if (irq != cards_irq) + return ENODEV; + }; + + cards_io= 0xC00 + ((adf_pos0>>4)*0x10); + type = EICON_CTYPE_SCOM; + break; + + case 2: /* DIVA/MCA */ + cards_io = 0x200+ ((adf_pos0>>4)* 0x20); + cards_irq = irq_array1[(adf_pos0 & 0x7)]; + if (irq == -1) { + irq = cards_irq; + } else { + if (irq != irq) + return ENODEV; + }; + type = 0; + break; + default: + return ENODEV; + }; + /* Uebereinstimmung vorgegebener membase & irq */ + if ( 1 == eicon_addcard(type, membase, irq, id)) { + mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name); + mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards); + + mca_mark_as_used(slot); + cards->mca_slot = slot; + /* card->io noch setzen oder ?? */ + if (DebugVar & 8) + printk("eicon_addcard: erfolgreich fuer slot: %d.\n", + cards->mca_slot+1); + return 0 ; /* eicon_addcard hat eine Karte zugefuegt */ + } else { + return ENODEV; + }; +}; +#endif /* CONFIG_MCA */ + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.2.10/linux/drivers/isdn/eicon/eicon_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_pci.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,956 @@ +/* $Id: eicon_pci.c,v 1.7 1999/06/09 19:31:29 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * Hardware-specific code for PCI cards. + * + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * Thanks to Eicon Technology Diehl GmbH & Co. oHG for + * documents, informations and hardware. + * + * Deutsche Telekom AG for S2M support. + * + * 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, 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. + * + * $Log: eicon_pci.c,v $ + * Revision 1.7 1999/06/09 19:31:29 armin + * Wrong PLX size for request_region() corrected. + * Added first MCA code from Erik Weber. + * + * Revision 1.6 1999/04/01 12:48:37 armin + * Changed some log outputs. + * + * Revision 1.5 1999/03/29 11:19:49 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.4 1999/03/02 12:37:48 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.3 1999/01/24 20:14:24 armin + * Changed and added debug stuff. + * Better data sending. (still problems with tty's flip buffer) + * + * Revision 1.2 1999/01/10 18:46:06 armin + * Bug with wrong values in HLC fixed. + * Bytes to send are counted and limited now. + * + * Revision 1.1 1999/01/01 18:09:45 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#include + +#include "eicon.h" +#include "eicon_pci.h" + + +char *eicon_pci_revision = "$Revision: 1.7 $"; + +#if CONFIG_PCI /* intire stuff is only for PCI */ + +#undef EICON_PCI_DEBUG + +int eicon_pci_find_card(char *ID) +{ + if (pci_present()) { + struct pci_dev *pdev = NULL; + int pci_nextindex=0, pci_cards=0, pci_akt=0; + int pci_type = PCI_MAESTRA; + int NoMorePCICards = FALSE; + char *ram, *reg, *cfg; + unsigned int pram=0, preg=0, pcfg=0; + char did[12]; + eicon_pci_card *aparms; + + if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) { + printk(KERN_WARNING + "eicon_pci: Could not allocate card-struct.\n"); + return 0; + } + + for (pci_cards = 0; pci_cards < 0x0f; pci_cards++) + { + do { + if ((pdev = pci_find_device(PCI_VENDOR_EICON, + pci_type, + pdev))) + { + pci_nextindex++; + break; + } + else { + pci_nextindex = 0; + switch (pci_type) /* switch to next card type */ + { + case PCI_MAESTRA: + pci_type = PCI_MAESTRAQ; break; + case PCI_MAESTRAQ: + pci_type = PCI_MAESTRAQ_U; break; + case PCI_MAESTRAQ_U: + pci_type = PCI_MAESTRAP; break; + default: + case PCI_MAESTRAP: + NoMorePCICards = TRUE; + } + } + } + while (!NoMorePCICards); + if (NoMorePCICards) + { + if (pci_cards < 1) { + printk(KERN_INFO "Eicon: No supported PCI cards found.\n"); + kfree(aparms); + return 0; + } + else + { + printk(KERN_INFO "Eicon: %d PCI card%s registered.\n", + pci_cards, (pci_cards > 1) ? "s":""); + kfree(aparms); + return (pci_cards); + } + } + + pci_akt = 0; + switch(pci_type) + { + case PCI_MAESTRA: + printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n"); + aparms->type = EICON_CTYPE_MAESTRA; + + aparms->irq = pdev->irq; + preg = pdev->base_address[2] & 0xfffffffc; + pcfg = pdev->base_address[1] & 0xffffff80; + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); + printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg); + printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg); +#endif + pci_akt = 1; + break; + + case PCI_MAESTRAQ: + case PCI_MAESTRAQ_U: + printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n"); + pci_cards--; + pci_akt = 0; + break; + + case PCI_MAESTRAP: + printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n"); + aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/ + aparms->irq = pdev->irq; + pram = pdev->base_address[0] & 0xfffff000; + preg = pdev->base_address[2] & 0xfffff000; + pcfg = pdev->base_address[4] & 0xfffff000; + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq); + printk(KERN_DEBUG "eicon_pci: ram=0x%x\n", + (pram)); + printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", + (preg)); + printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", + (pcfg)); +#endif + pci_akt = 1; + break; + default: + printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n"); + pci_cards--; + pci_akt = 0; + break; + } + + if (pci_akt) { + /* remapping memory */ + switch(pci_type) + { + case PCI_MAESTRA: + aparms->PCIreg = (unsigned int) preg; + aparms->PCIcfg = (unsigned int) pcfg; + if (check_region((aparms->PCIreg), 0x20)) { + printk(KERN_WARNING "eicon_pci: reg port already in use !\n"); + aparms->PCIreg = 0; + break; + } else { + request_region(aparms->PCIreg, 0x20, "eicon reg"); + } + if (check_region((aparms->PCIcfg), 0x80)) { + printk(KERN_WARNING "eicon_pci: cfg port already in use !\n"); + aparms->PCIcfg = 0; + release_region(aparms->PCIreg, 0x20); + break; + } else { + request_region(aparms->PCIcfg, 0x80, "eicon cfg"); + } + break; + case PCI_MAESTRAQ: + case PCI_MAESTRAQ_U: + case PCI_MAESTRAP: + aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000); + ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET); + reg = ioremap(preg, 0x4000); + cfg = ioremap(pcfg, 0x1000); + aparms->PCIram = (unsigned int) ram; + aparms->PCIreg = (unsigned int) reg; + aparms->PCIcfg = (unsigned int) cfg; + break; + } + if ((!aparms->PCIreg) || (!aparms->PCIcfg)) { + printk(KERN_ERR "eicon_pci: Card could not be added !\n"); + pci_cards--; + } else { + aparms->mvalid = 1; + + sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards); + + printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did); + + if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) { + printk(KERN_ERR "eicon_pci: Card could not be added !\n"); + pci_cards--; + } + } + } + + } + } else + printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n"); + return 0; +} + +/* + * Checks protocol file id for "F#xxxx" string fragment to + * extract the features, supported by this protocol version. + * binary representation of the feature string value is returned + * in *value. The function returns 0 if feature string was not + * found or has a wrong format, else 1. + */ +static int GetProtFeatureValue(char *sw_id, int *value) +{ + __u8 i, offset; + + while (*sw_id) + { + if ((sw_id[0] == 'F') && (sw_id[1] == '#')) + { + sw_id = &sw_id[2]; + for (i=0, *value=0; i<4; i++, sw_id++) + { + if ((*sw_id >= '0') && (*sw_id <= '9')) + { + offset = '0'; + } + else if ((*sw_id >= 'A') && (*sw_id <= 'F')) + { + offset = 'A' + 10; + } + else if ((*sw_id >= 'a') && (*sw_id <= 'f')) + { + offset = 'a' + 10; + } + else + { + return 0; + } + *value |= (*sw_id - offset) << (4*(3-i)); + } + return 1; + } + else + { + sw_id++; + } + } + return 0; +} + + +void +eicon_pci_printpar(eicon_pci_card *card) { + switch (card->type) { + case EICON_CTYPE_MAESTRA: + printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n", + eicon_ctype_name[card->type], + (unsigned int)card->PCIreg, + (unsigned int)card->PCIcfg, + card->irq); + break; + case EICON_CTYPE_MAESTRAQ: + case EICON_CTYPE_MAESTRAQ_U: + case EICON_CTYPE_MAESTRAP: + printk(KERN_INFO "%s at 0x%x, irq %d\n", + eicon_ctype_name[card->type], + (unsigned int)card->shmem, + card->irq); +#ifdef EICON_PCI_DEBUG + printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram); + printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg); + printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); +#endif + break; + } +} + + +static void +eicon_pci_release_shmem(eicon_pci_card *card) { + if (!card->master) + return; + if (card->mvalid) { + switch (card->type) { + case EICON_CTYPE_MAESTRA: + /* reset board */ + outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */ + outb(0, card->PCIreg + M_RESET); + SLEEP(20); + outb(0, card->PCIreg + M_ADDRH); + outw(0, card->PCIreg + M_ADDR); + outw(0, card->PCIreg + M_DATA); + + release_region(card->PCIreg, 0x20); + release_region(card->PCIcfg, 0x80); + break; + case EICON_CTYPE_MAESTRAQ: + case EICON_CTYPE_MAESTRAQ_U: + case EICON_CTYPE_MAESTRAP: + /* reset board */ + writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); + SLEEP(20); + writeb(0, card->PCIreg + MP_RESET); + SLEEP(20); + + iounmap((void *)card->shmem); + iounmap((void *)card->PCIreg); + iounmap((void *)card->PCIcfg); + break; + } + } + card->mvalid = 0; +} + +static void +eicon_pci_release_irq(eicon_pci_card *card) { + if (!card->master) + return; + if (card->ivalid) + free_irq(card->irq, card); + card->ivalid = 0; +} + +void +eicon_pci_release(eicon_pci_card *card) { + eicon_pci_release_irq(card); + eicon_pci_release_shmem(card); +} + +/* + * Upload buffer content to adapters shared memory + * on verify error, 1 is returned and a message is printed on screen + * else 0 is returned + * Can serve IO-Type and Memory type adapters + */ +int eicon_upload(t_dsp_download_space *p_para, + __u16 length, /* byte count */ + __u8 *buffer, + int verify) +{ + __u32 i, dwdata = 0, val = 0, timeout; + __u16 data; + eicon_pci_boot *boot = 0; + + switch (p_para->type) /* actions depend on type of union */ + { + case DL_PARA_IO_TYPE: + for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); + outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); + /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */ + outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); + } + if (verify) /* check written block */ + { + for (i=0; idat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH); + outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); + data = inw(p_para->dat.io.ioDATA); + if (data != *(u16 *)&buffer[i]) + { + p_para->dat.io.r3addr += i; + p_para->dat.io.BadData = data; + p_para->dat.io.GoodData = *(u16 *)&buffer[i]; + return 1; + } + } + } + break; + + case DL_PARA_MEM_TYPE: + boot = p_para->dat.mem.boot; + writel(p_para->dat.mem.r3addr, &boot->addr); + for (i=0; i> 2], &boot->data[i]); + } + if (verify) /* check written block */ + { + for (i=0; idata[i]); + if (((u32 *)buffer)[i >> 2] != dwdata) + { + p_para->dat.mem.r3addr += i; + p_para->dat.mem.BadData = dwdata; + p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2]; + return 1; + } + } + } + writel(((length + 3) / 4), &boot->len); /* len in dwords */ + writel(2, &boot->cmd); + + timeout = jiffies + 20; + while (timeout > jiffies) { + val = readl(&boot->cmd); + if (!val) break; + SLEEP(2); + } + if (val) + { + p_para->dat.mem.timeout = 1; + return 1; + } + break; + } + return 0; +} + + +/* show header information of code file */ +static +int eicon_pci_print_hdr(unsigned char *code, int offset) +{ + unsigned char hdr[80]; + int i, fvalue = 0; + + i = 0; + while ((i < (sizeof(hdr) -1)) + && (code[offset + i] != '\0') + && (code[offset + i] != '\r') + && (code[offset + i] != '\n')) + { + hdr[i] = code[offset + i]; + i++; + } + hdr[i] = '\0'; + printk(KERN_DEBUG "Eicon: loading %s\n", hdr); + if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue); + else return(0); +} + + +/* + * Configure a card, download code into BRI card, + * check if we get interrupts and return 0 on succes. + * Return -ERRNO on failure. + */ +int +eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) { + int i,j; + int timeout; + unsigned int offset, offp=0, size, length; + int signature = 0; + int FeatureValue = 0; + eicon_pci_codebuf cbuf; + t_dsp_download_space dl_para; + t_dsp_download_desc dsp_download_table; + unsigned char *code; + unsigned int reg; + unsigned int cfg; + + if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) + return -EFAULT; + + reg = card->PCIreg; + cfg = card->PCIcfg; + + /* reset board */ + outb(0, reg + M_RESET); + SLEEP(10); + outb(0, reg + M_ADDRH); + outw(0, reg + M_ADDR); + outw(0, reg + M_DATA); + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: reset card\n"); +#endif + + /* clear shared memory */ + outb(0xff, reg + M_ADDRH); + outw(0, reg + M_ADDR); + for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA); + SLEEP(10); + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: clear shared memory\n"); +#endif + + /* download protocol and dsp file */ + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); +#endif + + /* Allocate code-buffer */ + if (!(code = kmalloc(400, GFP_KERNEL))) { + printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); + return -ENOMEM; + } + + /* prepare protocol upload */ + dl_para.type = DL_PARA_IO_TYPE; + dl_para.dat.io.ioADDR = reg + M_ADDR; + dl_para.dat.io.ioADDRH = reg + M_ADDRH; + dl_para.dat.io.ioDATA = reg + M_DATA; + + for (j = 0; j <= cbuf.dsp_code_num; j++) + { + if (j == 0) size = cbuf.protocol_len; + else size = cbuf.dsp_code_len[j]; + + offset = 0; + + if (j == 0) dl_para.dat.io.r3addr = 0; + if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + + ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); + if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE; + if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32); + + do /* download block of up to 400 bytes */ + { + length = ((size - offset) >= 400) ? 400 : (size - offset); + + if (copy_from_user(code, (&cb->code) + offp + offset, length)) { + kfree(code); + return -EFAULT; + } + + if ((offset == 0) && (j < 2)) { + FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); +#ifdef EICON_PCI_DEBUG + if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue); +#endif + if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { + printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); + kfree(code); + return -EFAULT; + } + ((eicon_card *)card->card)->Feature = FeatureValue; + } + + if (eicon_upload(&dl_para, length, code, 1)) + { + printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); + kfree(code); + return -EIO; + } + /* move onto next block */ + offset += length; + dl_para.dat.io.r3addr += length; + } while (offset < size); + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset); +#endif + offp += size; + } + kfree(code); + + /* clear signature */ + outb(0xff, reg + M_ADDRH); + outw(0x1e, reg + M_ADDR); + outw(0, reg + M_DATA); + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); +#endif + /* copy configuration data into shared memory */ + outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA); + outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA); + outw(10,reg + M_ADDR); outb(0, reg + M_DATA); + outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA); + outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA); + outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */ + outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA); + outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA); + outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */ + outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */ + outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA); + outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA); + outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA); + outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA); + + for (i=0;i<32;i++) + { + outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA); + outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA); + outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA); + outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA); + outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA); + outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA); + } + +#ifdef EICON_PCI_DEBUG + printk(KERN_ERR "eicon_pci: starting CPU...\n"); +#endif + /* let the CPU run */ + outw(0x08, reg + M_RESET); + + timeout = jiffies + (5*HZ); + while (timeout > jiffies) { + outw(0x1e, reg + M_ADDR); + signature = inw(reg + M_DATA); + if (signature == DIVAS_SIGNATURE) break; + SLEEP(2); + } + if (signature != DIVAS_SIGNATURE) + { +#ifdef EICON_PCI_DEBUG + printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE); +#endif + printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n"); + return -EIO; + } +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); +#endif + + /* get serial number and number of channels supported by card */ + outb(0xff, reg + M_ADDRH); + outw(0x3f6, reg + M_ADDR); + card->channels = inw(reg + M_DATA); + card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26); + printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); + printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); + + /* test interrupt */ + card->irqprobe = 1; + + if (!card->ivalid) { + if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) + { + printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); + return -EIO; + } + } + card->ivalid = 1; + +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); +#endif + /* Trigger an interrupt and check if it is delivered */ + outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */ + outb(0x89, reg + M_RESET); /* place int request */ + + timeout = jiffies + 20; + while (timeout > jiffies) { + if (card->irqprobe != 1) break; + SLEEP(5); + } + if (card->irqprobe == 1) { + free_irq(card->irq, card); + card->ivalid = 0; + printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); + return -EIO; + } + + /* initializing some variables */ + ((eicon_card *)card->card)->ReadyInt = 0; + for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; + for(j=0; j< (card->channels + 1); j++) { + ((eicon_card *)card->card)->bch[j].e.busy = 0; + ((eicon_card *)card->card)->bch[j].e.D3Id = 0; + ((eicon_card *)card->card)->bch[j].e.B2Id = 0; + ((eicon_card *)card->card)->bch[j].e.ref = 0; + ((eicon_card *)card->card)->bch[j].e.Req = 0; + ((eicon_card *)card->card)->bch[j].e.complete = 1; + ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; + } + + printk(KERN_INFO "Eicon: Card successfully started\n"); + + return 0; +} + + +/* + * Configure a card, download code into PRI card, + * check if we get interrupts and return 0 on succes. + * Return -ERRNO on failure. + */ +int +eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) { + eicon_pci_boot *boot; + eicon_pr_ram *prram; + int i,j; + int timeout; + int FeatureValue = 0; + unsigned int offset, offp=0, size, length; + unsigned long int signature = 0; + t_dsp_download_space dl_para; + t_dsp_download_desc dsp_download_table; + eicon_pci_codebuf cbuf; + unsigned char *code; + unsigned char req_int; + char *ram, *reg, *cfg; + + if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf))) + return -EFAULT; + + boot = &card->shmem->boot; + ram = (char *)card->PCIram; + reg = (char *)card->PCIreg; + cfg = (char *)card->PCIcfg; + prram = (eicon_pr_ram *)ram; + + /* reset board */ + writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET); + SLEEP(20); + writeb(0, card->PCIreg + MP_RESET); + SLEEP(20); + + /* set command count to 0 */ + writel(0, &boot->reserved); + + /* check if CPU increments the life word */ + i = readw(&boot->live); + SLEEP(20); + if (i == readw(&boot->live)) { + printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n"); + return -EIO; + } +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n"); +#endif + + /* download firmware : DSP and Protocol */ +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: downloading firmware...\n"); +#endif + + /* Allocate code-buffer */ + if (!(code = kmalloc(400, GFP_KERNEL))) { + printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n"); + return -ENOMEM; + } + + /* prepare protocol upload */ + dl_para.type = DL_PARA_MEM_TYPE; + dl_para.dat.mem.boot = boot; + + for (j = 0; j <= cbuf.dsp_code_num; j++) + { + if (j==0) size = cbuf.protocol_len; + else size = cbuf.dsp_code_len[j]; + + if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */ + + if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR; + if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + + ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc); + if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE; + if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32); + + offset = 0; + do /* download block of up to 400 bytes */ + { + length = ((size - offset) >= 400) ? 400 : (size - offset); + + if (copy_from_user(code, (&cb->code) + offp + offset, length)) { + kfree(code); + return -EFAULT; + } + + if ((offset == 0) && (j < 2)) { + FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); +#ifdef EICON_PCI_DEBUG + if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue); +#endif + if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) { + printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n"); + kfree(code); + return -EFAULT; + } + ((eicon_card *)card->card)->Feature = FeatureValue; + } + + if (eicon_upload(&dl_para, length, code, 1)) + { + if (dl_para.dat.mem.timeout == 0) + printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr); + else + printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n"); + kfree(code); + return -EIO; + } + + /* move onto next block */ + offset += length; + dl_para.dat.mem.r3addr += length; + } while (offset < size); +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset); +#endif + offp += size; + } + kfree(code); + + /* initialize the adapter data structure */ +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n"); +#endif + /* clear out config space */ + for (i = 0; i < 256; i++) writeb(0, &ram[i]); + + /* copy configuration down to the card */ + writeb(cbuf.tei, &ram[8]); + writeb(cbuf.nt2, &ram[9]); + writeb(0, &ram[10]); + writeb(cbuf.WatchDog, &ram[11]); + writeb(cbuf.Permanent, &ram[12]); + writeb(cbuf.XInterface, &ram[13]); + writeb(cbuf.StableL2, &ram[14]); + writeb(cbuf.NoOrderCheck, &ram[15]); + writeb(cbuf.HandsetType, &ram[16]); + writeb(0, &ram[17]); + writeb(cbuf.LowChannel, &ram[18]); + writeb(cbuf.ProtVersion, &ram[19]); + writeb(cbuf.Crc4, &ram[20]); + for (i = 0; i < 32; i++) + { + writeb(cbuf.l[0].oad[i], &ram[32 + i]); + writeb(cbuf.l[0].osa[i], &ram[64 + i]); + writeb(cbuf.l[0].spid[i], &ram[96 + i]); + writeb(cbuf.l[1].oad[i], &ram[128 + i]); + writeb(cbuf.l[1].osa[i], &ram[160 + i]); + writeb(cbuf.l[1].spid[i], &ram[192 + i]); + } +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: configured card OK\n"); +#endif + + /* start adapter */ +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: tell card to start...\n"); +#endif + writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */ + writel(3, &boot->cmd); /* DIVAS_START_CMD */ + + /* wait till card ACKs */ + timeout = jiffies + (5*HZ); + while (timeout > jiffies) { + signature = readl(&boot->signature); + if ((signature >> 16) == DIVAS_SIGNATURE) break; + SLEEP(2); + } + if ((signature >> 16) != DIVAS_SIGNATURE) + { +#ifdef EICON_PCI_DEBUG + printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE); +#endif + printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n"); + return -EIO; + } +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n"); +#endif + + /* get serial number and number of channels supported by card */ + card->channels = readb(&ram[0x3f6]); + card->serial = readl(&ram[0x3f0]); + printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels); + printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial); + + /* test interrupt */ + readb(&ram[0x3fe]); + writeb(0, &ram[0x3fe]); /* reset any pending interrupt */ + readb(&ram[0x3fe]); + + writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); + writew(0, &cfg[MP_IRQ_RESET + 2]); + + card->irqprobe = 1; + + if (!card->ivalid) { + if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) + { + printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq); + return -EIO; + } + } + card->ivalid = 1; + + req_int = readb(&prram->ReadyInt); +#ifdef EICON_PCI_DEBUG + printk(KERN_DEBUG "eicon_pci: testing interrupt\n"); +#endif + req_int++; + /* Trigger an interrupt and check if it is delivered */ + writeb(req_int, &prram->ReadyInt); + + timeout = jiffies + 20; + while (timeout > jiffies) { + if (card->irqprobe != 1) break; + SLEEP(2); + } + if (card->irqprobe == 1) { + free_irq(card->irq, card); + card->ivalid = 0; + printk(KERN_ERR "eicon_pci: Getting no interrupts !\n"); + return -EIO; + } + + /* initializing some variables */ + ((eicon_card *)card->card)->ReadyInt = 0; + for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL; + for(j=0; j< (card->channels + 1); j++) { + ((eicon_card *)card->card)->bch[j].e.busy = 0; + ((eicon_card *)card->card)->bch[j].e.D3Id = 0; + ((eicon_card *)card->card)->bch[j].e.B2Id = 0; + ((eicon_card *)card->card)->bch[j].e.ref = 0; + ((eicon_card *)card->card)->bch[j].e.Req = 0; + ((eicon_card *)card->card)->bch[j].e.complete = 1; + ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL; + } + + printk(KERN_INFO "Eicon: Card successfully started\n"); + + return 0; +} + +#endif /* CONFIG_PCI */ + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/eicon/eicon_pci.h linux/drivers/isdn/eicon/eicon_pci.h --- v2.2.10/linux/drivers/isdn/eicon/eicon_pci.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/eicon/eicon_pci.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,188 @@ +/* $Id: eicon_pci.h,v 1.3 1999/03/29 11:19:51 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards (PCI part). + * + * Copyright 1998,99 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * 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, 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. + * + * $Log: eicon_pci.h,v $ + * Revision 1.3 1999/03/29 11:19:51 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * Revision 1.2 1999/03/02 12:37:50 armin + * Added some important checks. + * Analog Modem with DSP. + * Channels will be added to Link-Level after loading firmware. + * + * Revision 1.1 1999/01/01 18:09:46 armin + * First checkin of new eicon driver. + * DIVA-Server BRI/PCI and PRI/PCI are supported. + * Old diehl code is obsolete. + * + * + */ + +#ifndef eicon_pci_h +#define eicon_pci_h + +#ifdef __KERNEL__ + + +#define PCI_VENDOR_EICON 0x1133 +#define PCI_DIVA_PRO20 0xe001 /* Not supported */ +#define PCI_DIVA20 0xe002 /* Not supported */ +#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */ +#define PCI_DIVA20_U 0xe004 /* Not supported */ +#define PCI_MAESTRA 0xe010 +#define PCI_MAESTRAQ 0xe012 +#define PCI_MAESTRAQ_U 0xe013 +#define PCI_MAESTRAP 0xe014 + +#define DIVA_PRO20 1 +#define DIVA20 2 +#define DIVA_PRO20_U 3 +#define DIVA20_U 4 +#define MAESTRA 5 +#define MAESTRAQ 6 +#define MAESTRAQ_U 7 +#define MAESTRAP 8 + +#define TRUE 1 +#define FALSE 0 + +#define DIVAS_SIGNATURE 0x4447 + + +/* MAESTRA BRI PCI */ + +#define M_RESET 0x10 /* offset of reset register */ +#define M_DATA 0x00 /* offset of data register */ +#define M_ADDR 0x04 /* offset of address register */ +#define M_ADDRH 0x0c /* offset of high address register */ + +#define M_DSP_CODE_LEN 0xbf7d0000 +#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */ +#define M_DSP_CODE_BASE 0xbf7a0000 +#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */ + + + +/* MAESTRA PRI PCI */ + +#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */ + +#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */ +#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */ + +#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */ +#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */ +#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */ +#define MP_DSP_CODE_BASE 0xa03a0000 +#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */ + +#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */ + +/* RESET register bits */ +#define _MP_S2M_RESET 0x10 /* active lo */ +#define _MP_LED2 0x08 /* 1 = on */ +#define _MP_LED1 0x04 /* 1 = on */ +#define _MP_DSP_RESET 0x02 /* active lo */ +#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */ + +/* boot interface structure */ +typedef struct { + __u32 cmd __attribute__ ((packed)); + __u32 addr __attribute__ ((packed)); + __u32 len __attribute__ ((packed)); + __u32 err __attribute__ ((packed)); + __u32 live __attribute__ ((packed)); + __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed)); + __u32 signature __attribute__ ((packed)); + __u8 data[1]; /* real interface description */ +} eicon_pci_boot; + + +#define DL_PARA_IO_TYPE 0 +#define DL_PARA_MEM_TYPE 1 + +typedef struct tag_dsp_download_space +{ + __u16 type; /* see definitions above to differ union elements */ + union + { + struct + { + __u32 r3addr; + __u16 ioADDR; + __u16 ioADDRH; + __u16 ioDATA; + __u16 BadData; /* in case of verify error */ + __u16 GoodData; + } io; /* for io based adapters */ + struct + { + __u32 r3addr; + eicon_pci_boot *boot; + __u32 BadData; /* in case of verify error */ + __u32 GoodData; + __u16 timeout; + } mem; /* for memory based adapters */ + } dat; +} t_dsp_download_space; + + +/* Shared memory */ +typedef union { + eicon_pci_boot boot; +} eicon_pci_shmem; + +/* + * card's description + */ +typedef struct { + int ramsize; + int irq; /* IRQ */ + unsigned int PCIram; + unsigned int PCIreg; + unsigned int PCIcfg; + long int serial; /* Serial No. */ + int channels; /* No. of supported channels */ + void* card; + eicon_pci_shmem* shmem; /* Shared-memory area */ + unsigned char* intack; /* Int-Acknowledge */ + unsigned char* stopcpu; /* Writing here stops CPU */ + unsigned char* startcpu; /* Writing here starts CPU */ + unsigned char type; /* card type */ + unsigned char irqprobe; /* Flag: IRQ-probing */ + unsigned char mvalid; /* Flag: Memory is valid */ + unsigned char ivalid; /* Flag: IRQ is valid */ + unsigned char master; /* Flag: Card is Quadro 1/4 */ + void* generic; /* Ptr to generic card struct */ +} eicon_pci_card; + + + +extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb); +extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb); +extern void eicon_pci_release(eicon_pci_card *card); +extern void eicon_pci_printpar(eicon_pci_card *card); +extern int eicon_pci_find_card(char *ID); + +#endif /* __KERNEL__ */ + +#endif /* eicon_pci_h */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.2.10/linux/drivers/isdn/hisax/Makefile Mon Mar 15 16:11:29 1999 +++ linux/drivers/isdn/hisax/Makefile Mon Aug 9 12:04:39 1999 @@ -8,7 +8,7 @@ O_TARGET := O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o + lmgr.o q931.o callc.o fsm.o cert.o # EXTRA_CFLAGS += -S @@ -25,12 +25,11 @@ endif ISAC_OBJ := -ARCOFI_OBJ := HSCX_OBJ := +ISAR_OBJ := HFC_OBJ := HFC_2BDS0 := -RAWHDLC_OBJ := - +JADE_OBJ := ifeq ($(CONFIG_HISAX_16_0),y) O_OBJS += teles0.o ISAC_OBJ := isac.o @@ -43,17 +42,40 @@ HSCX_OBJ := hscx.o endif +ifeq ($(CONFIG_HISAX_TELESPCI),y) + O_OBJS += telespci.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_S0BOX),y) + O_OBJS += s0box.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + ifeq ($(CONFIG_HISAX_AVM_A1),y) O_OBJS += avm_a1.o ISAC_OBJ := isac.o HSCX_OBJ := hscx.o endif +ifeq ($(CONFIG_HISAX_AVM_A1_PCMCIA),y) + O_OBJS += avm_a1p.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_FRITZPCI),y) + O_OBJS += avm_pci.o + ISAC_OBJ := isac.o +endif + + ifeq ($(CONFIG_HISAX_ELSA),y) O_OBJS += elsa.o ISAC_OBJ := isac.o HSCX_OBJ := hscx.o - ARCOFI_OBJ := arcofi.o endif ifeq ($(CONFIG_HISAX_IX1MICROR2),y) @@ -84,6 +106,7 @@ O_OBJS += sedlbauer.o ISAC_OBJ := isac.o HSCX_OBJ := hscx.o + ISAR_OBJ := isar.o endif ifeq ($(CONFIG_HISAX_SPORTSTER),y) @@ -103,15 +126,13 @@ ISAC_OBJ := isac.o endif -ifeq ($(CONFIG_HISAX_TELES3C),y) - O_OBJS += teles3c.o +ifeq ($(CONFIG_HISAX_HFCS),y) + O_OBJS += hfcscard.o HFC_2BDS0 := hfc_2bds0.o endif -ifeq ($(CONFIG_HISAX_AMD7930),y) - RAWHDLC_OBJ := foreign.o rawhdlc.o -endif -ifeq ($(CONFIG_HISAX_DBRI),y) - RAWHDLC_OBJ := foreign.o rawhdlc.o + +ifeq ($(CONFIG_HISAX_HFC_PCI),y) + HFC_2BDS0 += hfc_pci.o endif ifeq ($(CONFIG_HISAX_NICCY),y) @@ -120,7 +141,45 @@ HSCX_OBJ := hscx.o endif -O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(ARCOFI_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ) +ifeq ($(CONFIG_HISAX_ISURF),y) + O_OBJS += isurf.o + ISAC_OBJ := isac.o + ISAR_OBJ := isar.o +endif + +ifeq ($(CONFIG_HISAX_HSTSAPHIR),y) + O_OBJS += saphir.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_BKM_A4T),y) + O_OBJS += bkm_a4t.o + ISAC_OBJ := isac.o + JADE_OBJ := jade.o +endif +ifeq ($(CONFIG_HISAX_SCT_QUADRO),y) + O_OBJS += bkm_a8.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +ifeq ($(CONFIG_HISAX_GAZEL),y) + O_OBJS += gazel.o + ISAC_OBJ := isac.o + HSCX_OBJ := hscx.o +endif + +# ifeq ($(CONFIG_HISAX_TESTEMU),y) +# O_OBJS += testemu.o +# endif + +ifeq ($(ISAC_OBJ), isac.o) + ISAC_OBJ += arcofi.o +endif + +O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ) +O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) OX_OBJS += config.o O_TARGET := @@ -134,4 +193,14 @@ endif endif + include $(TOPDIR)/Rules.make + +MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \ + tei.c callc.c cert.c l3dss1.c l3_1tr6.c elsa.c + +CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?) + +cert.o: $(MD5FILES) md5sums.asc + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c --- v2.2.10/linux/drivers/isdn/hisax/amd7930.c Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/hisax/amd7930.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: amd7930.c,v 1.2 1998/02/12 23:07:10 keil Exp $ +/* $Id: amd7930.c,v 1.3 1999/07/12 21:04:52 keil Exp $ * * HiSax ISDN driver - chip specific routines for AMD 7930 * @@ -7,6 +7,10 @@ * * * $Log: amd7930.c,v $ + * Revision 1.3 1999/07/12 21:04:52 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * * Revision 1.2 1998/02/12 23:07:10 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -105,7 +109,7 @@ #include "rawhdlc.h" #include -static const char *amd7930_revision = "$Revision: 1.2 $"; +static const char *amd7930_revision = "$Revision: 1.3 $"; #define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */ #define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into @@ -733,8 +737,6 @@ return(0); case CARD_RELEASE: release_amd7930(cs); - return(0); - case CARD_SETIRQ: return(0); case CARD_INIT: cs->l1cmd = amd7930_l1cmd; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c --- v2.2.10/linux/drivers/isdn/hisax/arcofi.c Thu Nov 5 09:58:43 1998 +++ linux/drivers/isdn/hisax/arcofi.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,31 @@ -/* $Id: arcofi.c,v 1.1 1997/10/29 18:51:20 keil Exp $ +/* $Id: arcofi.c,v 1.7 1999/07/01 08:11:17 keil Exp $ - * arcofi.h Ansteuerung ARCOFI 2165 + * arcofi.c Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@temic-ech.spacenet.de) * * * * $Log: arcofi.c,v $ + * Revision 1.7 1999/07/01 08:11:17 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.6 1998/09/30 22:21:56 keil + * cosmetics + * + * Revision 1.5 1998/09/27 12:52:57 keil + * cosmetics + * + * Revision 1.4 1998/08/20 13:50:24 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.3 1998/05/25 12:57:38 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.2 1998/04/15 16:47:16 keil + * new interface + * * Revision 1.1 1997/10/29 18:51:20 keil * New files * @@ -16,35 +35,120 @@ #include "hisax.h" #include "isdnl1.h" #include "isac.h" +#include "arcofi.h" -int -send_arcofi(struct IsdnCardState *cs, const u_char *msg) { +#define ARCOFI_TIMER_VALUE 20 + +static void +add_arcofi_timer(struct IsdnCardState *cs) { + if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { + del_timer(&cs->dc.isac.arcofitimer); + } + init_timer(&cs->dc.isac.arcofitimer); + cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000); + add_timer(&cs->dc.isac.arcofitimer); +} + +static void +send_arcofi(struct IsdnCardState *cs) { u_char val; - char tmp[32]; - long flags; - int cnt=2; - cs->mon_txp = 0; - cs->mon_txc = msg[0]; - memcpy(cs->mon_tx, &msg[1], cs->mon_txc); - cs->mocr &= 0x0f; - cs->mocr |= 0xa0; - test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags); - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + add_arcofi_timer(cs); + cs->dc.isac.mon_txp = 0; + cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len; + memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc); + switch(cs->dc.isac.arcofi_bc) { + case 0: break; + case 1: cs->dc.isac.mon_tx[1] |= 0x40; + break; + default: break; + } + cs->dc.isac.mocr &= 0x0f; + cs->dc.isac.mocr |= 0xa0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); val = cs->readisac(cs, ISAC_MOSR); - cs->writeisac(cs, ISAC_MOX1, cs->mon_tx[cs->mon_txp++]); - cs->mocr |= 0x10; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); - save_flags(flags); - sti(); - while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) { - cnt--; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); + cs->dc.isac.mocr |= 0x10; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); +} + +int +arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { + if (cs->debug & L1_DEB_MONITOR) { + debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event); } - restore_flags(flags); - sprintf(tmp, "arcofi tout %d", cnt); - debugl1(cs, tmp); - return(cnt); + if (event == ARCOFI_TIMEOUT) { + cs->dc.isac.arcofi_state = ARCOFI_NOP; + test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags); + wake_up_interruptible(&cs->dc.isac.arcofi_wait); + return(1); + } + switch (cs->dc.isac.arcofi_state) { + case ARCOFI_NOP: + if (event == ARCOFI_START) { + cs->dc.isac.arcofi_list = data; + cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; + send_arcofi(cs); + } + break; + case ARCOFI_TRANSMIT: + if (event == ARCOFI_TX_END) { + if (cs->dc.isac.arcofi_list->receive) { + add_arcofi_timer(cs); + cs->dc.isac.arcofi_state = ARCOFI_RECEIVE; + } else { + if (cs->dc.isac.arcofi_list->next) { + cs->dc.isac.arcofi_list = + cs->dc.isac.arcofi_list->next; + send_arcofi(cs); + } else { + if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { + del_timer(&cs->dc.isac.arcofitimer); + } + cs->dc.isac.arcofi_state = ARCOFI_NOP; + wake_up_interruptible(&cs->dc.isac.arcofi_wait); + } + } + } + break; + case ARCOFI_RECEIVE: + if (event == ARCOFI_RX_END) { + if (cs->dc.isac.arcofi_list->next) { + cs->dc.isac.arcofi_list = + cs->dc.isac.arcofi_list->next; + cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; + send_arcofi(cs); + } else { + if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { + del_timer(&cs->dc.isac.arcofitimer); + } + cs->dc.isac.arcofi_state = ARCOFI_NOP; + wake_up_interruptible(&cs->dc.isac.arcofi_wait); + } + } + break; + default: + debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state); + return(2); + } + return(0); } +static void +arcofi_timer(struct IsdnCardState *cs) { + arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL); +} + +void +clear_arcofi(struct IsdnCardState *cs) { + if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { + del_timer(&cs->dc.isac.arcofitimer); + } +} + +void +init_arcofi(struct IsdnCardState *cs) { + cs->dc.isac.arcofitimer.function = (void *) arcofi_timer; + cs->dc.isac.arcofitimer.data = (long) cs; + init_timer(&cs->dc.isac.arcofitimer); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/arcofi.h linux/drivers/isdn/hisax/arcofi.h --- v2.2.10/linux/drivers/isdn/hisax/arcofi.h Wed Apr 1 16:20:57 1998 +++ linux/drivers/isdn/hisax/arcofi.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: arcofi.h,v 1.1 1997/10/29 18:51:20 keil Exp $ +/* $Id: arcofi.h,v 1.4 1999/07/01 08:11:18 keil Exp $ * arcofi.h Ansteuerung ARCOFI 2165 * @@ -7,6 +7,16 @@ * * * $Log: arcofi.h,v $ + * Revision 1.4 1999/07/01 08:11:18 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.3 1998/05/25 12:57:39 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.2 1998/04/15 16:47:17 keil + * new interface + * * Revision 1.1 1997/10/29 18:51:20 keil * New files * @@ -14,4 +24,16 @@ #define ARCOFI_USE 1 -extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg); +/* states */ +#define ARCOFI_NOP 0 +#define ARCOFI_TRANSMIT 1 +#define ARCOFI_RECEIVE 2 +/* events */ +#define ARCOFI_START 1 +#define ARCOFI_TX_END 2 +#define ARCOFI_RX_END 3 +#define ARCOFI_TIMEOUT 4 + +extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data); +extern void init_arcofi(struct IsdnCardState *cs); +extern void clear_arcofi(struct IsdnCardState *cs); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.2.10/linux/drivers/isdn/hisax/asuscom.c Thu Nov 5 09:58:43 1998 +++ linux/drivers/isdn/hisax/asuscom.c Mon Aug 9 12:04:39 1999 @@ -1,13 +1,29 @@ -/* $Id: asuscom.c,v 1.2 1998/02/02 13:27:06 keil Exp $ +/* $Id: asuscom.c,v 1.7 1999/07/12 21:04:53 keil Exp $ * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for informations * * * $Log: asuscom.c,v $ + * Revision 1.7 1999/07/12 21:04:53 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.6 1999/07/01 08:11:18 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.5 1998/11/15 23:54:19 keil + * changes from 2.0 + * + * Revision 1.4 1998/06/18 23:18:20 keil + * Support for new IPAC card + * + * Revision 1.3 1998/04/15 16:46:53 keil + * new init code + * * Revision 1.2 1998/02/02 13:27:06 keil * New * @@ -17,12 +33,13 @@ #define __NO_VERSION__ #include "hisax.h" #include "isac.h" +#include "ipac.h" #include "hscx.h" #include "isdnl1.h" extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.2 $"; +const char *Asuscom_revision = "$Revision: 1.7 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -33,6 +50,12 @@ #define ASUS_CTRL_U7 3 #define ASUS_CTRL_POTS 5 +#define ASUS_IPAC_ALE 0 +#define ASUS_IPAC_DATA 1 + +#define ASUS_ISACHSCX 1 +#define ASUS_IPAC 2 + /* CARD_ADR (Write) */ #define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */ @@ -107,6 +130,30 @@ } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80)); +} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return (readreg(cs->hw.asus.adr, @@ -141,7 +188,7 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n"); @@ -149,16 +196,12 @@ } val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) @@ -171,16 +214,58 @@ debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0); - } - if (stat & 2) { - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0); +} + +static void +asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + + if (!cs) { + printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; } + if (!icnt) + printk(KERN_WARNING "ASUS IRQ LOOP\n"); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0); } void @@ -197,14 +282,27 @@ { long flags; - byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20); + else + byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - byteout(cs->hw.asus.adr, 0); /* Reset Off */ + schedule_timeout((10*HZ)/1000); + if (cs->subtyp == ASUS_IPAC) + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); + else + byteout(cs->hw.asus.adr, 0); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout((10*HZ)/1000); + if (cs->subtyp == ASUS_IPAC) { + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12); + } restore_flags(flags); } @@ -218,14 +316,9 @@ case CARD_RELEASE: release_io_asuscom(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &asuscom_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + cs->debug |= L1_DEB_IPAC; + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -238,6 +331,7 @@ { int bytecnt; struct IsdnCardState *cs = card->cs; + u_char val; char tmp[64]; strcpy(tmp, Asuscom_revision); @@ -248,12 +342,6 @@ bytecnt = 8; cs->hw.asus.cfg_reg = card->para[1]; cs->irq = card->para[0]; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; - cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; - cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; - if (check_region((cs->hw.asus.cfg_reg), bytecnt)) { printk(KERN_WARNING "HiSax: %s config port %x-%x already in use\n", @@ -264,27 +352,47 @@ } else { request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn"); } - - printk(KERN_INFO - "ISDNLink: defined at 0x%x IRQ %d\n", - cs->hw.asus.cfg_reg, - cs->irq); - printk(KERN_INFO "ISDNLink: resetting card\n"); - reset_asuscom(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; + printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", + cs->hw.asus.cfg_reg, cs->irq); cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Asus_card_msg; - ISACVersion(cs, "ISDNLink:"); - if (HscxVersion(cs, "ISDNLink:")) { - printk(KERN_WARNING - "ISDNLink: wrong HSCX versions check IO address\n"); - release_io_asuscom(cs); - return (0); + val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, + cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); + if (val == 1) { + cs->subtyp = ASUS_IPAC; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &asuscom_interrupt_ipac; + printk(KERN_INFO "Asus: IPAC version %x\n", val); + } else { + cs->subtyp = ASUS_ISACHSCX; + cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; + cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; + cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; + cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; + cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &asuscom_interrupt; + ISACVersion(cs, "ISDNLink:"); + if (HscxVersion(cs, "ISDNLink:")) { + printk(KERN_WARNING + "ISDNLink: wrong HSCX versions check IO address\n"); + release_io_asuscom(cs); + return (0); + } } + printk(KERN_INFO "ISDNLink: resetting card\n"); + reset_asuscom(cs); return (1); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.2.10/linux/drivers/isdn/hisax/avm_a1.c Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/avm_a1.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,24 @@ -/* $Id: avm_a1.c,v 2.7 1998/02/02 13:29:37 keil Exp $ +/* $Id: avm_a1.c,v 2.11 1999/07/12 21:04:54 keil Exp $ * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: avm_a1.c,v $ + * Revision 2.11 1999/07/12 21:04:54 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.10 1998/11/15 23:54:21 keil + * changes from 2.0 + * + * Revision 2.9 1998/08/13 23:36:12 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.8 1998/04/15 16:44:27 keil + * new init code + * * Revision 2.7 1998/02/02 13:29:37 keil * fast io * @@ -57,7 +70,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *avm_revision = "$Revision: 2.7 $"; +static const char *avm_revision = "$Revision: 2.11 $"; #define AVM_A1_STAT_ISAC 0x01 #define AVM_A1_STAT_HSCX 0x02 @@ -144,8 +157,7 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, sval, stat = 0; - char tmp[32]; + u_char val, sval; if (!cs) { printk(KERN_WARNING "AVM A1: Spurious interrupt!\n"); @@ -155,35 +167,25 @@ if (!(sval & AVM_A1_STAT_TIMER)) { byteout(cs->hw.avm.cfg_reg, 0x1E); sval = bytein(cs->hw.avm.cfg_reg); - } else if (cs->debug & L1_DEB_INTSTAT) { - sprintf(tmp, "avm IntStatus %x", sval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_INTSTAT) + debugl1(cs, "avm IntStatus %x", sval); if (!(sval & AVM_A1_STAT_HSCX)) { val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } } if (!(sval & AVM_A1_STAT_ISAC)) { val = readreg(cs->hw.avm.isac, ISAC_ISTA); - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } } } - if (stat & 1) { - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); - } - if (stat & 2) { - writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); - } + writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); + writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); } inline static void @@ -213,14 +215,11 @@ case CARD_RELEASE: release_ioregs(cs, 0x3f); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &avm_a1_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 1); + byteout(cs->hw.avm.cfg_reg, 0x16); + byteout(cs->hw.avm.cfg_reg, 0x1E); + inithscxisac(cs, 2); return(0); case CARD_TEST: return(0); @@ -348,7 +347,6 @@ val = bytein(cs->hw.avm.cfg_reg + 2); printk(KERN_INFO "AVM A1: Byte at %x is %x\n", cs->hw.avm.cfg_reg + 2, val); - byteout(cs->hw.avm.cfg_reg, 0x1E); val = bytein(cs->hw.avm.cfg_reg); printk(KERN_INFO "AVM A1: Byte at %x is %x\n", cs->hw.avm.cfg_reg, val); @@ -373,6 +371,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &AVM_card_msg; + cs->irq_func = &avm_a1_interrupt; ISACVersion(cs, "AVM A1:"); if (HscxVersion(cs, "AVM A1:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c --- v2.2.10/linux/drivers/isdn/hisax/avm_a1p.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/avm_a1p.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,321 @@ +/* $Id: avm_a1p.c,v 2.4 1999/07/12 21:04:55 keil Exp $ + * + * avm_a1p.c low level stuff for the following AVM cards: + * A1 PCMCIA + * FRITZ!Card PCMCIA + * FRITZ!Card PCMCIA 2.0 + * + * Author Carsten Paeth (calle@calle.in-berlin.de) + * + * $Log: avm_a1p.c,v $ + * Revision 2.4 1999/07/12 21:04:55 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.3 1998/11/15 23:54:22 keil + * changes from 2.0 + * + * Revision 2.2 1998/08/13 23:36:13 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.1 1998/07/15 15:01:23 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 1.1.2.1 1998/07/15 14:43:26 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "isdnl1.h" + +/* register offsets */ +#define ADDRREG_OFFSET 0x02 +#define DATAREG_OFFSET 0x03 +#define ASL0_OFFSET 0x04 +#define ASL1_OFFSET 0x05 +#define MODREG_OFFSET 0x06 +#define VERREG_OFFSET 0x07 + +/* address offsets */ +#define ISAC_FIFO_OFFSET 0x00 +#define ISAC_REG_OFFSET 0x20 +#define HSCX_CH_DIFF 0x40 +#define HSCX_FIFO_OFFSET 0x80 +#define HSCX_REG_OFFSET 0xa0 + +/* read bits ASL0 */ +#define ASL0_R_TIMER 0x10 /* active low */ +#define ASL0_R_ISAC 0x20 /* active low */ +#define ASL0_R_HSCX 0x40 /* active low */ +#define ASL0_R_TESTBIT 0x80 +#define ASL0_R_IRQPENDING (ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER) + +/* write bits ASL0 */ +#define ASL0_W_RESET 0x01 +#define ASL0_W_TDISABLE 0x02 +#define ASL0_W_TRESET 0x04 +#define ASL0_W_IRQENABLE 0x08 +#define ASL0_W_TESTBIT 0x80 + +/* write bits ASL1 */ +#define ASL1_W_LED0 0x10 +#define ASL1_W_LED1 0x20 +#define ASL1_W_ENABLE_S0 0xC0 + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +static const char *avm_revision = "$Revision: 2.4 $"; + +static inline u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + long flags; + u_char ret; + + offset -= 0x20; + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset); + ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET); + restore_flags(flags); + return ret; +} + +static inline void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + long flags; + + offset -= 0x20; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset); + byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value); + restore_flags(flags); +} + +static inline void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + long flags; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET); + insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); + restore_flags(flags); +} + +static inline void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + long flags; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET); + outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); + restore_flags(flags); +} + +static inline u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + u_char ret; + long flags; + + offset -= 0x20; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset); + ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET); + restore_flags(flags); + return ret; +} + +static inline void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + long flags; + + offset -= 0x20; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset); + byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value); + restore_flags(flags); +} + +static inline void +ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) +{ + long flags; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF); + insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); + restore_flags(flags); +} + +static inline void +WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) +{ + long flags; + + save_flags(flags); + cli(); + byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET, + HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF); + outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size); + restore_flags(flags); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) + +#include "hscx_irq.c" + +static void +avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, sval; + + if (!cs) { + printk(KERN_WARNING "AVM A1 PCMCIA: Spurious interrupt!\n"); + return; + } + while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) { + if (cs->debug & L1_DEB_INTSTAT) + debugl1(cs, "avm IntStatus %x", sval); + if (sval & ASL0_R_HSCX) { + val = ReadHSCX(cs, 1, HSCX_ISTA); + if (val) + hscx_int_main(cs, val); + } + if (sval & ASL0_R_ISAC) { + val = ReadISAC(cs, ISAC_ISTA); + if (val) + isac_interrupt(cs, val); + } + } + WriteHSCX(cs, 0, HSCX_MASK, 0xff); + WriteHSCX(cs, 1, HSCX_MASK, 0xff); + WriteISAC(cs, ISAC_MASK, 0xff); + WriteISAC(cs, ISAC_MASK, 0x00); + WriteHSCX(cs, 0, HSCX_MASK, 0x00); + WriteHSCX(cs, 1, HSCX_MASK, 0x00); +} + +static int +AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + return 0; + + case CARD_RELEASE: + /* free_irq is done in HiSax_closecard(). */ + /* free_irq(cs->irq, cs); */ + return 0; + + case CARD_INIT: + clear_pending_isac_ints(cs); + clear_pending_hscx_ints(cs); + inithscxisac(cs, 1); + inithscxisac(cs, 2); + return 0; + + case CARD_TEST: + /* we really don't need it for the PCMCIA Version */ + return 0; + + default: + /* all card drivers ignore others, so we do the same */ + return 0; + } + return 0; +} + +__initfunc(int +setup_avm_a1_pcmcia(struct IsdnCard *card)) +{ + u_char model, vers; + struct IsdnCardState *cs = card->cs; + long flags; + char tmp[64]; + + + strcpy(tmp, avm_revision); + printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n", + HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_A1_PCMCIA) + return (0); + + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + + + save_flags(flags); + outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0); + sti(); + + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET); + HZDELAY(HZ / 5 + 1); + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00); + + byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET); + + restore_flags(flags); + + model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET); + vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET); + + printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n", + cs->hw.avm.cfg_reg, cs->irq, model, vers); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &AVM_card_msg; + cs->irq_func = &avm_a1p_interrupt; + + ISACVersion(cs, "AVM A1 PCMCIA:"); + if (HscxVersion(cs, "AVM A1 PCMCIA:")) { + printk(KERN_WARNING + "AVM A1 PCMCIA: wrong HSCX versions check IO address\n"); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.2.10/linux/drivers/isdn/hisax/avm_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/avm_pci.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,898 @@ +/* $Id: avm_pci.c,v 1.9 1999/07/12 21:04:57 keil Exp $ + + * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards + * Thanks to AVM, Berlin for informations + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * + * $Log: avm_pci.c,v $ + * Revision 1.9 1999/07/12 21:04:57 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.8 1999/07/01 08:11:19 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.7 1999/02/22 18:26:30 keil + * Argh ! ISAC address was only set with PCI + * + * Revision 1.6 1998/11/27 19:59:28 keil + * set subtype for Fritz!PCI + * + * Revision 1.5 1998/11/27 12:56:45 keil + * forgot to update setup function name + * + * Revision 1.4 1998/11/15 23:53:19 keil + * Fritz!PnP; changes from 2.0 + * + * Revision 1.3 1998/09/27 23:53:39 keil + * Fix error handling + * + * Revision 1.2 1998/09/27 12:54:55 keil + * bcs assign was lost in setstack, very bad results + * + * Revision 1.1 1998/08/20 13:47:30 keil + * first version + * + * + * + */ +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "isac.h" +#include "isdnl1.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif +#include + +extern const char *CardType[]; +static const char *avm_pci_rev = "$Revision: 1.9 $"; + +#define AVM_FRITZ_PCI 1 +#define AVM_FRITZ_PNP 2 + +#define PCI_VENDOR_AVM 0x1244 +#define PCI_FRITZPCI_ID 0xa00 + +#define HDLC_FIFO 0x0 +#define HDLC_STATUS 0x4 + +#define AVM_HDLC_1 0x00 +#define AVM_HDLC_2 0x01 +#define AVM_ISAC_FIFO 0x02 +#define AVM_ISAC_REG_LOW 0x04 +#define AVM_ISAC_REG_HIGH 0x06 + +#define AVM_STATUS0_IRQ_ISAC 0x01 +#define AVM_STATUS0_IRQ_HDLC 0x02 +#define AVM_STATUS0_IRQ_TIMER 0x04 +#define AVM_STATUS0_IRQ_MASK 0x07 + +#define AVM_STATUS0_RESET 0x01 +#define AVM_STATUS0_DIS_TIMER 0x02 +#define AVM_STATUS0_RES_TIMER 0x04 +#define AVM_STATUS0_ENA_IRQ 0x08 +#define AVM_STATUS0_TESTBIT 0x10 + +#define AVM_STATUS1_INT_SEL 0x0f +#define AVM_STATUS1_ENA_IOM 0x80 + +#define HDLC_MODE_ITF_FLG 0x01 +#define HDLC_MODE_TRANS 0x02 +#define HDLC_MODE_CCR_7 0x04 +#define HDLC_MODE_CCR_16 0x08 +#define HDLC_MODE_TESTLOOP 0x80 + +#define HDLC_INT_XPR 0x80 +#define HDLC_INT_XDU 0x40 +#define HDLC_INT_RPR 0x20 +#define HDLC_INT_MASK 0xE0 + +#define HDLC_STAT_RME 0x01 +#define HDLC_STAT_RDO 0x10 +#define HDLC_STAT_CRCVFRRAB 0x0E +#define HDLC_STAT_CRCVFR 0x06 +#define HDLC_STAT_RML_MASK 0x3f00 + +#define HDLC_CMD_XRS 0x80 +#define HDLC_CMD_XME 0x01 +#define HDLC_CMD_RRS 0x20 +#define HDLC_CMD_XML_MASK 0x3f00 + + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + register u_char val; + register long flags; + + save_flags(flags); + cli(); + outb(idx, cs->hw.avm.cfg_reg + 4); + val = inb(cs->hw.avm.isac + (offset & 0xf)); + restore_flags(flags); + return (val); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; + register long flags; + + save_flags(flags); + cli(); + outb(idx, cs->hw.avm.cfg_reg + 4); + outb(value, cs->hw.avm.isac + (offset & 0xf)); + restore_flags(flags); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); + insb(cs->hw.avm.isac, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); + outsb(cs->hw.avm.isac, data, size); +} + +static inline u_int +ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset) +{ + register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register u_int val; + register long flags; + + save_flags(flags); + cli(); + outl(idx, cs->hw.avm.cfg_reg + 4); + val = inl(cs->hw.avm.isac + offset); + restore_flags(flags); + return (val); +} + +static inline void +WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value) +{ + register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register long flags; + + save_flags(flags); + cli(); + outl(idx, cs->hw.avm.cfg_reg + 4); + outl(value, cs->hw.avm.isac + offset); + restore_flags(flags); +} + +static inline u_char +ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset) +{ + register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register u_char val; + register long flags; + + save_flags(flags); + cli(); + outb(idx, cs->hw.avm.cfg_reg + 4); + val = inb(cs->hw.avm.isac + offset); + restore_flags(flags); + return (val); +} + +static inline void +WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value) +{ + register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; + register long flags; + + save_flags(flags); + cli(); + outb(idx, cs->hw.avm.cfg_reg + 4); + outb(value, cs->hw.avm.isac + offset); + restore_flags(flags); +} + +static u_char +ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset) +{ + return(0xff & ReadHDLCPCI(cs, chan, offset)); +} + +static void +WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value) +{ + WriteHDLCPCI(cs, chan, offset, value); +} + +static inline +struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) +{ + if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) + return(&cs->bcs[0]); + else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) + return(&cs->bcs[1]); + else + return(NULL); +} + +void inline +hdlc_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + queue_task(&bcs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void +write_ctrl(struct BCState *bcs, int which) { + + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "hdlc %c wr%x ctrl %x", + 'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl); + if (bcs->cs->subtyp == AVM_FRITZ_PCI) { + WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl); + } else { + if (which & 4) + WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2, + bcs->hw.hdlc.ctrl.sr.mode); + if (which & 2) + WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1, + bcs->hw.hdlc.ctrl.sr.xml); + if (which & 1) + WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS, + bcs->hw.hdlc.ctrl.sr.cmd); + } +} + +void +modehdlc(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int hdlc = bcs->channel; + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hdlc %c mode %d ichan %d", + 'A' + hdlc, mode, bc); + bcs->mode = mode; + bcs->channel = bc; + bcs->hw.hdlc.ctrl.ctrl = 0; + switch (mode) { + case (L1_MODE_NULL): + bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bcs, 5); + break; + case (L1_MODE_TRANS): + bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; + write_ctrl(bcs, 5); + bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.ctrl.sr.cmd = 0; + hdlc_sched_event(bcs, B_XMTBUFREADY); + break; + case (L1_MODE_HDLC): + bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; + bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG; + write_ctrl(bcs, 5); + bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.ctrl.sr.cmd = 0; + hdlc_sched_event(bcs, B_XMTBUFREADY); + break; + } +} + +static inline void +hdlc_empty_fifo(struct BCState *bcs, int count) +{ + register u_int *ptr; + u_char *p; + u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1; + int cnt=0; + struct IsdnCardState *cs = bcs->cs; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_empty_fifo %d", count); + if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); + return; + } + ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; + bcs->hw.hdlc.rcvidx += count; + if (cs->subtyp == AVM_FRITZ_PCI) { + outl(idx, cs->hw.avm.cfg_reg + 4); + while (cnt < count) { + *ptr++ = inl(cs->hw.avm.isac); + cnt += 4; + } + } else { + outb(idx, cs->hw.avm.cfg_reg + 4); + while (cnt < count) { + *p++ = inb(cs->hw.avm.isac); + cnt++; + } + } + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + if (cs->subtyp == AVM_FRITZ_PNP) + p = (u_char *) ptr; + t += sprintf(t, "hdlc_empty_fifo %c cnt %d", + bcs->channel ? 'B' : 'A', count); + QuickHex(t, p, count); + debugl1(cs, bcs->blog); + } +} + +static inline void +hdlc_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int count, cnt =0; + int fifo_size = 32; + u_char *p; + u_int *ptr; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_fill_fifo"); + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; + if (bcs->tx_skb->len > fifo_size) { + count = fifo_size; + } else { + count = bcs->tx_skb->len; + if (bcs->mode != L1_MODE_TRANS) + bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; + } + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len); + ptr = (u_int *) p = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hdlc.count += count; + bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count); + write_ctrl(bcs, 3); /* sets the correct index too */ + if (cs->subtyp == AVM_FRITZ_PCI) { + while (cnthw.avm.isac); + cnt += 4; + } + } else { + while (cnthw.avm.isac); + cnt++; + } + } + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + if (cs->subtyp == AVM_FRITZ_PNP) + p = (u_char *) ptr; + t += sprintf(t, "hdlc_fill_fifo %c cnt %d", + bcs->channel ? 'B' : 'A', count); + QuickHex(t, p, count); + debugl1(cs, bcs->blog); + } +} + +static void +fill_hdlc(struct BCState *bcs) +{ + long flags; + save_flags(flags); + cli(); + hdlc_fill_fifo(bcs); + restore_flags(flags); +} + +static inline void +HDLC_irq(struct BCState *bcs, u_int stat) { + int len; + struct sk_buff *skb; + + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); + if (stat & HDLC_INT_RPR) { + if (stat & HDLC_STAT_RDO) { + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "RDO"); + else + debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); + bcs->hw.hdlc.ctrl.sr.xml = 0; + bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.rcvidx = 0; + } else { + if (!(len = (stat & HDLC_STAT_RML_MASK)>>8)) + len = 32; + hdlc_empty_fifo(bcs, len); + if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { + if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) || + (bcs->mode == L1_MODE_TRANS)) { + if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) + printk(KERN_WARNING "HDLC: receive out of memory\n"); + else { + memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx), + bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hdlc.rcvidx = 0; + hdlc_sched_event(bcs, B_RCVBUFREADY); + } else { + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "invalid frame"); + else + debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat); + bcs->hw.hdlc.rcvidx = 0; + } + } + } + } + if (stat & HDLC_INT_XDU) { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hdlc.count); + bcs->tx_cnt += bcs->hw.hdlc.count; + bcs->hw.hdlc.count = 0; +// hdlc_sched_event(bcs, B_XMTBUFREADY); + if (bcs->cs->debug & L1_DEB_WARN) + debugl1(bcs->cs, "ch%d XDU", bcs->channel); + } else if (bcs->cs->debug & L1_DEB_WARN) + debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel); + bcs->hw.hdlc.ctrl.sr.xml = 0; + bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; + write_ctrl(bcs, 1); + bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; + write_ctrl(bcs, 1); + hdlc_fill_fifo(bcs); + } else if (stat & HDLC_INT_XPR) { + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + hdlc_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->hw.hdlc.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hdlc.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + hdlc_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + hdlc_sched_event(bcs, B_XMTBUFREADY); + } + } +} + +inline void +HDLC_irq_main(struct IsdnCardState *cs) +{ + u_int stat; + long flags; + struct BCState *bcs; + + save_flags(flags); + cli(); + if (cs->subtyp == AVM_FRITZ_PCI) { + stat = ReadHDLCPCI(cs, 0, HDLC_STATUS); + } else { + stat = ReadHDLCPnP(cs, 0, HDLC_STATUS); + if (stat & HDLC_INT_RPR) + stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS+1))<<8; + } + if (stat & HDLC_INT_MASK) { + if (!(bcs = Sel_BCS(cs, 0))) { + if (cs->debug) + debugl1(cs, "hdlc spurious channel 0 IRQ"); + } else + HDLC_irq(bcs, stat); + } + if (cs->subtyp == AVM_FRITZ_PCI) { + stat = ReadHDLCPCI(cs, 1, HDLC_STATUS); + } else { + stat = ReadHDLCPnP(cs, 1, HDLC_STATUS); + if (stat & HDLC_INT_RPR) + stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS+1))<<8; + } + if (stat & HDLC_INT_MASK) { + if (!(bcs = Sel_BCS(cs, 1))) { + if (cs->debug) + debugl1(cs, "hdlc spurious channel 1 IRQ"); + } else + HDLC_irq(bcs, stat); + } + restore_flags(flags); +} + +void +hdlc_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->hw.hdlc.count = 0; + restore_flags(flags); + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n"); + break; + } + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->tx_skb = skb; + st->l1.bcs->hw.hdlc.count = 0; + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + modehdlc(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + modehdlc(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +void +close_hdlcstate(struct BCState *bcs) +{ + modehdlc(bcs, 0, 0); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hdlc.rcvbuf) { + kfree(bcs->hw.hdlc.rcvbuf); + bcs->hw.hdlc.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +int +open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hdlc.rcvbuf\n"); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hdlc.rcvbuf); + bcs->hw.hdlc.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hdlc.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); +} + +int +setstack_hdlc(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (open_hdlcstate(st->l1.hardware, bcs)) + return (-1); + st->l1.bcs = bcs; + st->l2.l2l1 = hdlc_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +HISAX_INITFUNC(void +clear_pending_hdlc_ints(struct IsdnCardState *cs)) +{ + u_int val; + + if (cs->subtyp == AVM_FRITZ_PCI) { + val = ReadHDLCPCI(cs, 0, HDLC_STATUS); + debugl1(cs, "HDLC 1 STA %x", val); + val = ReadHDLCPCI(cs, 1, HDLC_STATUS); + debugl1(cs, "HDLC 2 STA %x", val); + } else { + val = ReadHDLCPnP(cs, 0, HDLC_STATUS); + debugl1(cs, "HDLC 1 STA %x", val); + val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1); + debugl1(cs, "HDLC 1 RML %x", val); + val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2); + debugl1(cs, "HDLC 1 MODE %x", val); + val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3); + debugl1(cs, "HDLC 1 VIN %x", val); + val = ReadHDLCPnP(cs, 1, HDLC_STATUS); + debugl1(cs, "HDLC 2 STA %x", val); + val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1); + debugl1(cs, "HDLC 2 RML %x", val); + val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2); + debugl1(cs, "HDLC 2 MODE %x", val); + val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3); + debugl1(cs, "HDLC 2 VIN %x", val); + } +} + +HISAX_INITFUNC(void +inithdlc(struct IsdnCardState *cs)) +{ + cs->bcs[0].BC_SetStack = setstack_hdlc; + cs->bcs[1].BC_SetStack = setstack_hdlc; + cs->bcs[0].BC_Close = close_hdlcstate; + cs->bcs[1].BC_Close = close_hdlcstate; + modehdlc(cs->bcs, 0, 0); + modehdlc(cs->bcs + 1, 0, 0); +} + +static void +avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + u_char sval; + + if (!cs) { + printk(KERN_WARNING "AVM PCI: Spurious interrupt!\n"); + return; + } + sval = inb(cs->hw.avm.cfg_reg + 2); + if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) + /* possible a shared IRQ reqest */ + return; + if (!(sval & AVM_STATUS0_IRQ_ISAC)) { + val = ReadISAC(cs, ISAC_ISTA); + isac_interrupt(cs, val); + } + if (!(sval & AVM_STATUS0_IRQ_HDLC)) { + HDLC_irq_main(cs); + } + WriteISAC(cs, ISAC_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0x0); +} + +static void +reset_avmpcipnp(struct IsdnCardState *cs) +{ + long flags; + + printk(KERN_INFO "AVM PCI/PnP: reset\n"); + save_flags(flags); + sti(); + outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); + outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); +} + +static int +AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_avmpcipnp(cs); + return(0); + case CARD_RELEASE: + outb(0, cs->hw.avm.cfg_reg + 2); + release_region(cs->hw.avm.cfg_reg, 32); + return(0); + case CARD_INIT: + clear_pending_isac_ints(cs); + initisac(cs); + clear_pending_hdlc_ints(cs); + inithdlc(cs); + outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, + cs->hw.avm.cfg_reg + 2); + WriteISAC(cs, ISAC_MASK, 0); + outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | + AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); + /* RESET Receiver and Transmitter */ + WriteISAC(cs, ISAC_CMDR, 0x41); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_avm __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +__initfunc(int +setup_avm_pcipnp(struct IsdnCard *card)) +{ + u_int val, ver; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, avm_pci_rev); + printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_FRITZPCI) + return (0); + if (card->para[1]) { + cs->hw.avm.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + cs->subtyp = AVM_FRITZ_PNP; + } else { +#if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "FritzPCI: no PCI bus present\n"); + return(0); + } + if ((dev_avm = pci_find_device(PCI_VENDOR_AVM, + PCI_FRITZPCI_ID, dev_avm))) { + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.avm.cfg_reg = dev_avm->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.avm.cfg_reg) { + printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } +#else + for (; pci_index < 255; pci_index++) { + unsigned char pci_bus, pci_device_fn; + unsigned int ioaddr; + unsigned char irq; + + if (pcibios_find_device (PCI_VENDOR_AVM, + PCI_FRITZPCI_ID, pci_index, + &pci_bus, &pci_device_fn) != 0) { + continue; + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &ioaddr); + cs->irq = irq; + cs->hw.avm.cfg_reg = ioaddr & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.avm.cfg_reg) { + printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PCI; + break; + } + if (pci_index == 255) { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + pci_index++; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->irq_flags |= SA_SHIRQ; +#else + printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); + return (0); +#endif /* CONFIG_PCI */ + } + cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; + if (check_region((cs->hw.avm.cfg_reg), 32)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.avm.cfg_reg, + cs->hw.avm.cfg_reg + 31); + return (0); + } else { + request_region(cs->hw.avm.cfg_reg, 32, + (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP"); + } + switch (cs->subtyp) { + case AVM_FRITZ_PCI: + val = inl(cs->hw.avm.cfg_reg); + printk(KERN_INFO "AVM PCI: stat %#x\n", val); + printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", + val & 0xff, (val>>8) & 0xff); + cs->BC_Read_Reg = &ReadHDLC_s; + cs->BC_Write_Reg = &WriteHDLC_s; + break; + case AVM_FRITZ_PNP: + val = inb(cs->hw.avm.cfg_reg); + ver = inb(cs->hw.avm.cfg_reg + 1); + printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); + reset_avmpcipnp(cs); + cs->BC_Read_Reg = &ReadHDLCPnP; + cs->BC_Write_Reg = &WriteHDLCPnP; + break; + default: + printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp); + return(0); + } + printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n", + (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP", + cs->irq, cs->hw.avm.cfg_reg); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Send_Data = &fill_hdlc; + cs->cardmsg = &AVM_card_msg; + cs->irq_func = &avm_pcipnp_interrupt; + ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.2.10/linux/drivers/isdn/hisax/bkm_a4t.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/bkm_a4t.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,397 @@ +/* $Id: bkm_a4t.c,v 1.4 1999/07/14 11:43:14 keil Exp $ + * bkm_a4t.c low level stuff for T-Berkom A4T + * derived from the original file sedlbauer.c + * derived from the original file niccy.c + * derived from the original file netjet.c + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * $Log: bkm_a4t.c,v $ + * Revision 1.4 1999/07/14 11:43:14 keil + * correct PCI_SUBSYSTEM_VENDOR_ID + * + * Revision 1.3 1999/07/12 21:04:58 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.2 1999/07/01 08:07:53 keil + * Initial version + * + * + */ + +#define __NO_VERSION__ + +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "jade.h" +#include "isdnl1.h" +#include "bkm_ax.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif + +extern const char *CardType[]; + +const char *bkm_a4t_revision = "$Revision: 1.4 $"; + + +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) +{ + register u_int ret; + long flags; + unsigned int *po = (unsigned int *) adr; /* Postoffice */ + save_flags(flags); + cli(); + *po = (GCS_2 | PO_WRITE | off); + __WAITI20__(po); + *po = (ale | PO_READ); + __WAITI20__(po); + ret = *po; + restore_flags(flags); + return ((unsigned char) ret); +} + + +static inline void +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo read without cli because it's allready done */ + int i; + for (i = 0; i < size; i++) + *data++ = readreg(ale, adr, off); +} + + +static inline void +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +{ + long flags; + unsigned int *po = (unsigned int *) adr; /* Postoffice */ + save_flags(flags); + cli(); + *po = (GCS_2 | PO_WRITE | off); + __WAITI20__(po); + *po = (ale | PO_WRITE | data); + __WAITI20__(po); + restore_flags(flags); +} + + +static inline void +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo write without cli because it's allready done */ + int i; + + for (i = 0; i < size; i++) + writereg(ale, adr, off, *data++); +} + + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); +} + +static u_char +ReadJADE(struct IsdnCardState *cs, int jade, u_char offset) +{ + return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)))); +} + +static void +WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) +{ + writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value); +} + +/* + * fast interrupt JADE stuff goes here + */ + +#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80))) +#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data) + +#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) +#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\ + cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) + +#include "jade_irq.c" + +static void +bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val = 0; + I20_REGISTER_FILE *pI20_Regs; + + if (!cs) { + printk(KERN_WARNING "HiSax: Telekom A4T: Spurious interrupt!\n"); + return; + } + pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + + /* ISDN interrupt pending? */ + if (pI20_Regs->i20IntStatus & intISDN) { + /* Reset the ISDN interrupt */ + pI20_Regs->i20IntStatus = intISDN; + /* Disable ISDN interrupt */ + pI20_Regs->i20IntCtrl &= ~intISDN; + /* Channel A first */ + val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80); + if (val) { + jade_int_main(cs, val, 0); + } + /* Channel B */ + val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0); + if (val) { + jade_int_main(cs, val, 1); + } + /* D-Channel */ + val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA); + if (val) { + isac_interrupt(cs, val); + } + /* Reenable ISDN interrupt */ + pI20_Regs->i20IntCtrl |= intISDN; + } +} + +void +release_io_bkm(struct IsdnCardState *cs) +{ + if (cs->hw.ax.base) { + iounmap((void *) cs->hw.ax.base); + cs->hw.ax.base = 0; + } +} + +static void +enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) +{ + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + if (bEnable) + pI20_Regs->i20IntCtrl |= (intISDN | intPCI); + else + /* CAUTION: This disables the video capture driver too */ + pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); + } +} + +static void +reset_bkm(struct IsdnCardState *cs) +{ + long flags; + + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + save_flags(flags); + sti(); + /* Issue the I20 soft reset */ + pI20_Regs->i20SysControl = 0xFF; /* all in */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + /* Remove the soft reset */ + pI20_Regs->i20SysControl = sysRESET | 0xFF; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + /* Set our configuration */ + pI20_Regs->i20SysControl = sysRESET | sysCFG; + /* Issue ISDN reset */ + pI20_Regs->i20GuestControl = guestWAIT_CFG | + g_A4T_JADE_RES | + g_A4T_ISAR_RES | + g_A4T_ISAC_RES | + g_A4T_JADE_BOOTR | + g_A4T_ISAR_BOOTR; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + + /* Remove RESET state from ISDN */ + pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | + g_A4T_JADE_RES | + g_A4T_ISAR_RES); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); + } +} + +static int +BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + /* Disable ints */ + enable_bkm_int(cs, 0); + reset_bkm(cs); + return (0); + case CARD_RELEASE: + /* Sanity */ + enable_bkm_int(cs, 0); + reset_bkm(cs); + release_io_bkm(cs); + return (0); + case CARD_INIT: + clear_pending_isac_ints(cs); + clear_pending_jade_ints(cs); + initisac(cs); + initjade(cs); + /* Enable ints */ + enable_bkm_int(cs, 1); + return (0); + case CARD_TEST: + return (0); + } + return (0); +} + +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_a4t __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +__initfunc(int + setup_bkm_a4t(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + u_int pci_memaddr = 0, found = 0; + I20_REGISTER_FILE *pI20_Regs; +#if CONFIG_PCI +#ifndef COMPAT_HAS_NEW_PCI + u_char pci_bus, pci_device_fn, pci_irq = 0; +#endif +#endif + + strcpy(tmp, bkm_a4t_revision); + printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_BKM_A4T) { + cs->subtyp = BKM_A4T; + } else + return (0); + +#if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) { + u_int sub_sys_id = 0; + + pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, + &sub_sys_id); + if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + found = 1; + pci_memaddr = dev_a4t->base_address[0]; + cs->irq = dev_a4t->irq; + } + } +#else + for (; pci_index < 0xff; pci_index++) { + if (pcibios_find_device(I20_VENDOR_ID, + I20_DEVICE_ID, + pci_index, + &pci_bus, + &pci_device_fn) == PCIBIOS_SUCCESSFUL) { + u_int sub_sys_id = 0; + + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_SUBSYSTEM_VENDOR_ID, &sub_sys_id); + if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) { + found = 1; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq); + cs->irq = pci_irq; + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_memaddr); + break; + } + } + } +#endif /* COMPAT_HAS_NEW_PCI */ + if (!found) { + printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]); + return (0); + } +#ifndef COMPAT_HAS_NEW_PCI + pci_index++; +#endif + if (!cs->irq) { /* IRQ range check ?? */ + printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]); + return (0); + } + if (!pci_memaddr) { + printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]); + return (0); + } + pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK; + cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096); + /* Check suspecious address */ + pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); + if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { + printk(KERN_WARNING "HiSax: %s address %x-%x suspecious\n", + CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096); + iounmap((void *) cs->hw.ax.base); + cs->hw.ax.base = 0; + return (0); + } + cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; + cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; + cs->hw.ax.isac_ale = GCS_1; + cs->hw.ax.jade_ale = GCS_3; +#else + printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]); + printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]); + return (0); +#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s: Card configured at 0x%X IRQ %d\n", + CardType[card->typ], cs->hw.ax.base, cs->irq); + + reset_bkm(cs); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadJADE; + cs->BC_Write_Reg = &WriteJADE; + cs->BC_Send_Data = &jade_fill_fifo; + cs->cardmsg = &BKM_card_msg; + cs->irq_func = &bkm_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "Telekom A4T:"); + /* Jade version */ + JadeVersion(cs, "Telekom A4T:"); + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.2.10/linux/drivers/isdn/hisax/bkm_a8.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/bkm_a8.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,523 @@ +/* $Id: bkm_a8.c,v 1.4 1999/07/14 11:43:15 keil Exp $ + * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) + * derived from the original file sedlbauer.c + * derived from the original file niccy.c + * derived from the original file netjet.c + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * $Log: bkm_a8.c,v $ + * Revision 1.4 1999/07/14 11:43:15 keil + * correct PCI_SUBSYSTEM_VENDOR_ID + * + * Revision 1.3 1999/07/12 21:04:59 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.2 1999/07/01 08:07:54 keil + * Initial version + * + * + */ +#define __NO_VERSION__ + +#include "hisax.h" +#include "isac.h" +#include "ipac.h" +#include "hscx.h" +#include "isdnl1.h" +#include "bkm_ax.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif + +#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ + +extern const char *CardType[]; + +const char sct_quadro_revision[] = "$Revision: 1.4 $"; + +/* To survive the startup phase */ +typedef struct { + u_int active; /* true/false */ + u_int base; /* ipac base address */ +} IPAC_STATE; + +static IPAC_STATE ipac_state[4 + 1] __initdata = +{ + {0, 0}, /* dummy */ + {0, 0}, /* SCT_1 */ + {0, 0}, /* SCT_2 */ + {0, 0}, /* SCT_3 */ + {0, 0} /* SCT_4 */ +}; + +static const char *sct_quadro_subtypes[] = +{ + "", + "#1", + "#2", + "#3", + "#4" +}; + + +#define wordout(addr,val) outw(val,addr) +#define wordin(addr) inw(addr) + +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) +{ + register u_char ret; + long flags; + save_flags(flags); + cli(); + wordout(ale, off); + ret = wordin(adr) & 0xFF; + restore_flags(flags); + return (ret); +} + +static inline void +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo read without cli because it's allready done */ + int i; + wordout(ale, off); + for (i = 0; i < size; i++) + data[i] = wordin(adr) & 0xFF; +} + + +static inline void +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +{ + long flags; + save_flags(flags); + cli(); + wordout(ale, off); + wordout(adr, data); + restore_flags(flags); +} + +static inline void +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo write without cli because it's allready done */ + int i; + wordout(ale, off); + for (i = 0; i < size; i++) + wordout(adr, data[i]); +} + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); +} + + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0))); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); +} + +/* Check whether the specified ipac is already active or not */ +static int +is_ipac_active(u_int ipac_nr) +{ + return (ipac_state[ipac_nr].active); +} + +/* Set the specific ipac to active */ +static void +set_ipac_active(u_int ipac_nr, u_int active) +{ + /* set activation state */ + ipac_state[ipac_nr].active = active; +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \ + cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \ + cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data) +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \ + cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \ + cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static void +bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + int i; + if (!cs) { + printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); + + Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) { + hscx_int_main(cs, val); + } + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n", + CardType[cs->typ], + sct_quadro_subtypes[cs->subtyp]); + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); + writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); + + /* Read out all interrupt sources from currently not active ipacs */ + /* "Handle" all interrupts from currently not active ipac by reading the regs */ + for (i = SCT_1; i <= SCT_4; i++) + if (!is_ipac_active(i)) { + u_int base = ipac_state[i].base; + if (readreg(base, base + 4, 0xC1)) { + readreg(base, base + 4, 0xA0); + readreg(base, base + 4, 0xA4); + readreg(base, base + 4, 0x20); + readreg(base, base + 4, 0x24); + readreg(base, base + 4, 0x60); + readreg(base, base + 4, 0x64); + readreg(base, base + 4, 0xC1); + readreg(base, base + 4, ISAC_CIR0 + 0x80); + } + } +} + + +void +release_io_sct_quadro(struct IsdnCardState *cs) +{ + /* ?? */ +} + +static void +enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) +{ + if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { + if (bEnable) + wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); + else + /* Issue general di only if no ipac is active */ + if (!is_ipac_active(SCT_1) && + !is_ipac_active(SCT_2) && + !is_ipac_active(SCT_3) && + !is_ipac_active(SCT_4)) + wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); + } +} + +static void +reset_bkm(struct IsdnCardState *cs) +{ + long flags; + + if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { + if (!is_ipac_active(SCT_1) && + !is_ipac_active(SCT_2) && + !is_ipac_active(SCT_3) && + !is_ipac_active(SCT_4)) { + /* Issue total reset only if no ipac is active */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); + + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + + /* Remove the soft reset */ + wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10 * HZ) / 1000); + restore_flags(flags); + } + } +} + +static int +BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + /* Disable ints */ + set_ipac_active(cs->subtyp, 0); + enable_bkm_int(cs, 0); + reset_bkm(cs); + return (0); + case CARD_RELEASE: + /* Sanity */ + set_ipac_active(cs->subtyp, 0); + enable_bkm_int(cs, 0); + reset_bkm(cs); + release_io_sct_quadro(cs); + return (0); + case CARD_INIT: + cs->debug |= L1_DEB_IPAC; + set_ipac_active(cs->subtyp, 1); + inithscxisac(cs, 3); + /* Enable ints */ + enable_bkm_int(cs, 1); + return (0); + case CARD_TEST: + return (0); + } + return (0); +} + +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_a8 __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +__initfunc(int + setup_sct_quadro(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; +#if CONFIG_PCI + u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id; + u_int found = 0; + u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; +#endif + + strcpy(tmp, sct_quadro_revision); + printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { + cs->subtyp = SCT_1; /* Preset */ + } else + return (0); + + /* Identify subtype by para[0] */ + if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) + cs->subtyp = card->para[0]; + else + printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n", + CardType[card->typ]); +#if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "bkm_a4t: no PCI bus present\n"); + return (0); + } + if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) { + u_int sub_sys_id = 0; + + pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, + &sub_sys_id); + if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { + found = 1; + pci_ioaddr1 = dev_a8->base_address[1]; + pci_irq = dev_a8->irq; + pci_bus = dev_a8->bus->number; + pci_device_fn = dev_a8->devfn; + } + } +#else + for (; pci_index < 0xff; pci_index++) { + if (pcibios_find_device( + PLX_VENDOR_ID, + PLX_DEVICE_ID, + pci_index, + &pci_bus, + &pci_device_fn) == PCIBIOS_SUCCESSFUL) { + + u_int sub_sys_id = 0; + + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_SUBSYSTEM_VENDOR_ID, &sub_sys_id); + if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) { + found = 1; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &pci_ioaddr1); + cs->irq = pci_irq; + break; + } + } + } +#endif /* COMPAT_HAS_NEW_PCI */ + if (!found) { + printk(KERN_WARNING "HiSax: %s (%s): Card not found\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifndef COMPAT_HAS_NEW_PCI + pci_index++; /* need for more as one card */ +#endif + if (!pci_irq) { /* IRQ range check ?? */ + printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } +#ifdef ATTEMPT_PCI_REMAPPING +/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ + pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id); + if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { + printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + /* Restart PCI negotiation */ + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, (u_int) - 1); + /* Move up by 0x80 byte */ + pci_ioaddr1 += 0x80; + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pcibios_write_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, pci_ioaddr1); +#ifdef COMPAT_HAS_NEW_PCI + dev_a8->base_address[1] = pci_ioaddr1; +#endif /* COMPAT_HAS_NEW_PCI */ + } +/* End HACK */ +#endif + pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); + pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); + pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); + pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_ioaddr4); + pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_ioaddr5); + if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) { + printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); + } + pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK; + pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK; + /* Take over */ + cs->irq = pci_irq; + cs->irq_flags |= SA_SHIRQ; + /* pci_ioaddr1 is unique to all subdevices */ + /* pci_ioaddr2 is for the fourth subdevice only */ + /* pci_ioaddr3 is for the third subdevice only */ + /* pci_ioaddr4 is for the second subdevice only */ + /* pci_ioaddr5 is for the first subdevice only */ + cs->hw.ax.plx_adr = pci_ioaddr1; + /* Enter all ipac_base addresses */ + ipac_state[SCT_1].base = pci_ioaddr5 + 0x00; + ipac_state[SCT_2].base = pci_ioaddr4 + 0x08; + ipac_state[SCT_3].base = pci_ioaddr3 + 0x10; + ipac_state[SCT_4].base = pci_ioaddr2 + 0x20; + /* For isac and hscx control path */ + cs->hw.ax.base = ipac_state[cs->subtyp].base; + /* For isac and hscx data path */ + cs->hw.ax.data_adr = cs->hw.ax.base + 4; +#else + printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp]); + return (0); +#endif /* CONFIG_PCI */ + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp], + cs->hw.ax.plx_adr, + cs->hw.ax.base, + cs->hw.ax.data_adr, + cs->irq); + + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + + /* Disable all currently not active ipacs */ + if (!is_ipac_active(SCT_1)) + set_ipac_active(SCT_1, 0); + if (!is_ipac_active(SCT_2)) + set_ipac_active(SCT_2, 0); + if (!is_ipac_active(SCT_3)) + set_ipac_active(SCT_3, 0); + if (!is_ipac_active(SCT_4)) + set_ipac_active(SCT_4, 0); + + /* Perfom general reset (if possible) */ + reset_bkm(cs); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &BKM_card_msg; + cs->irq_func = &bkm_interrupt_ipac; + + printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n", + CardType[card->typ], + sct_quadro_subtypes[cs->subtyp], + readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h --- v2.2.10/linux/drivers/isdn/hisax/bkm_ax.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/bkm_ax.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,133 @@ +/* $Id: bkm_ax.h,v 1.2 1999/07/01 08:07:55 keil Exp $ + * bkm_ax.h low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive) + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * $Log: bkm_ax.h,v $ + * Revision 1.2 1999/07/01 08:07:55 keil + * Initial version + * + * + * + */ + +#ifndef __BKM_AX_H__ +#define __BKM_AX_H__ + +/* Supported boards (subtypes) */ +#define SCT_1 1 +#define SCT_2 2 +#define SCT_3 3 +#define SCT_4 4 +#define BKM_A4T 5 + + +/* A4T */ +#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */ +#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */ +#define A4T_SUBVEN_ID 0x0871 +#define A4T_SUBSYS_ID 0xFFA4 +/* Scitel Quadro */ +#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */ +#define PLX_VENDOR_ID 0x10B5 +#define SCT_SUBVEN_ID 0x0871 +#define SCT_SUBSYS_ID 0xFFA8 + + +#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */ +#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */ +#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */ +#define PLX_ADDR_ALE 0x20 /* Addr ALE */ +#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */ + +#define PLX_SUBVEN 0x2C /* Offset SubVendor */ +#define PLX_SUBSYS 0x2E /* Offset SubSystem */ + + +/* Application specific registers I20 (Siemens SZB6120H) */ +typedef struct { + /* Video front end horizontal configuration register */ + volatile u_int i20VFEHorzCfg; /* Offset 00 */ + /* Video front end vertical configuration register */ + volatile u_int i20VFEVertCfg; /* Offset 04 */ + /* Video front end scaler and pixel format register */ + volatile u_int i20VFEScaler; /* Offset 08 */ + /* Video display top register */ + volatile u_int i20VDispTop; /* Offset 0C */ + /* Video display bottom register */ + volatile u_int i20VDispBottom; /* Offset 10 */ + /* Video stride, status and frame grab register */ + volatile u_int i20VidFrameGrab;/* Offset 14 */ + /* Video display configuration register */ + volatile u_int i20VDispCfg; /* Offset 18 */ + /* Video masking map top */ + volatile u_int i20VMaskTop; /* Offset 1C */ + /* Video masking map bottom */ + volatile u_int i20VMaskBottom; /* Offset 20 */ + /* Overlay control register */ + volatile u_int i20OvlyControl; /* Offset 24 */ + /* System, PCI and general purpose pins control register */ + volatile u_int i20SysControl; /* Offset 28 */ +#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */ + /* GPIO 4...0: Output fixed for our cfg! */ +#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */ + /* General purpose pins and guest bus control register */ + volatile u_int i20GuestControl;/* Offset 2C */ +#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */ +#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */ +#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */ +#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */ +#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */ +#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */ +#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */ +#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */ +#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */ + +#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */ +#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */ +#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */ +#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */ +#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */ +#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */ +#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */ +#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */ + + volatile u_int i20CodeSource; /* Offset 30 */ + volatile u_int i20CodeXferCtrl;/* Offset 34 */ + volatile u_int i20CodeMemPtr; /* Offset 38 */ + + volatile u_int i20IntStatus; /* Offset 3C */ + volatile u_int i20IntCtrl; /* Offset 40 */ +#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */ +#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */ +#define intCOD 0x10000000 /* CodRepIrqEn (High) */ +#define intPCI 0x01000000 /* PCI IntA enable (High) */ + + volatile u_int i20I2CCtrl; /* Offset 44 */ +} I20_REGISTER_FILE, *PI20_REGISTER_FILE; + +/* + * Postoffice structure for A4T + * + */ +#define PO_OFFSET 0x00000200 /* Postoffice offset from base */ + +#define GCS_0 0x00000000 /* Guest bus chip selects */ +#define GCS_1 0x00100000 +#define GCS_2 0x00200000 +#define GCS_3 0x00300000 + +#define PO_READ 0x00000000 /* R/W from/to guest bus */ +#define PO_WRITE 0x00800000 + +#define PO_PEND 0x02000000 + +#define POSTOFFICE(postoffice) *(volatile unsigned int*)(postoffice) + +/* Wait unlimited (don't worry) */ +#define __WAITI20__(postoffice) \ +do { \ + while ((POSTOFFICE(postoffice) & PO_PEND)) ; \ +} while (0) + +#endif /* __BKM_AX_H__ */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.2.10/linux/drivers/isdn/hisax/callc.c Sun Dec 27 10:44:45 1998 +++ linux/drivers/isdn/hisax/callc.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,74 @@ -/* $Id: callc.c,v 2.13 1998/02/12 23:07:16 keil Exp $ +/* $Id: callc.c,v 2.29 1999/07/13 21:05:41 werner Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.29 1999/07/13 21:05:41 werner + * Modified set_channel_limit to use new callback ISDN_STAT_DISCH. + * + * Revision 2.28 1999/07/09 08:30:02 keil + * cosmetics + * + * Revision 2.27 1999/07/05 23:51:38 werner + * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl + * hisaxctrl id 10 + * + * Revision 2.26 1999/07/01 08:11:21 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.25 1999/01/02 11:17:20 keil + * Changes for 2.2 + * + * Revision 2.24 1998/11/15 23:54:24 keil + * changes from 2.0 + * + * Revision 2.23 1998/09/30 22:21:57 keil + * cosmetics + * + * Revision 2.22 1998/08/20 13:50:29 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.21 1998/08/13 23:36:15 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.20 1998/06/26 15:13:05 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 2.19 1998/05/25 14:08:06 keil + * HiSax 3.0 + * fixed X.75 and leased line to work again + * Point2Point and fixed TEI are runtime options now: + * hisaxctrl 7 1 set PTP + * hisaxctrl 8 + * set fixed TEI to TEIVALUE (0-63) + * + * Revision 2.18 1998/05/25 12:57:40 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.17 1998/04/15 16:46:06 keil + * RESUME support + * + * Revision 2.16 1998/04/10 10:35:17 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.15 1998/03/19 13:18:37 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 2.14 1998/03/07 22:56:54 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.13 1998/02/12 23:07:16 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -60,12 +122,18 @@ #define __NO_VERSION__ #include "hisax.h" +#include "../avmb1/capicmd.h" /* this should be moved in a common place */ #ifdef MODULE +#ifdef COMPAT_HAS_NEW_SYMTAB #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) -#endif /* MODULE */ +#else +extern long mod_use_count_; +#define MOD_USE_COUNT mod_use_count_ +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* MODULE */ -const char *lli_revision = "$Revision: 2.13 $"; +const char *lli_revision = "$Revision: 2.29 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -77,20 +145,18 @@ static struct Fsm callcfsm = {NULL, 0, 0, NULL, NULL}; -static struct Fsm lcfsm = -{NULL, 0, 0, NULL, NULL}; static int chancount = 0; -/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ -#define ALERT_REJECT 1 +/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ +#define ALERT_REJECT 0 /* Value to delay the sending of the first B-channel paket after CONNECT * here is no value given by ITU, but experience shows that 300 ms will * work on many networks, if you or your other side is behind local exchanges * a greater value may be recommented. If the delay is to short the first paket * will be lost and autodetect on many comercial routers goes wrong ! - * You can adjust this value on runtime with + * You can adjust this value on runtime with * hisaxctrl 2 * value is in milliseconds */ @@ -98,27 +164,7 @@ /* Flags for remembering action done in lli */ -#define FLG_START_D 0 -#define FLG_ESTAB_D 1 -#define FLG_CALL_SEND 2 -#define FLG_CALL_REC 3 -#define FLG_CALL_ALERT 4 -#define FLG_START_B 5 -#define FLG_CONNECT_B 6 -#define FLG_LL_DCONN 7 -#define FLG_LL_BCONN 8 -#define FLG_DISC_SEND 9 -#define FLG_DISC_REC 10 -#define FLG_REL_REC 11 -#define FLG_DO_ALERT 12 -#define FLG_DO_HANGUP 13 -#define FLG_DO_CONNECT 14 -#define FLG_DO_ESTAB 15 - -/* - * Because of callback it's a good idea to delay the shutdown of the d-channel - */ -#define DREL_TIMER_VALUE 10000 +#define FLG_START_B 0 /* * Find card with given driverId @@ -136,55 +182,66 @@ return (struct IsdnCardState *) 0; } -static void -link_debug(struct Channel *chanp, char *s, int direction) +int +discard_queue(struct sk_buff_head *q) { - char tmp[100], tm[32]; + struct sk_buff *skb; + int ret=0; - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan, - direction ? "LL->HL" : "HL->LL", s); - HiSax_putstatus(chanp->cs, tmp); + while ((skb = skb_dequeue(q))) { + idev_kfree_skb(skb, FREE_READ); + ret++; + } + return(ret); } +static void +link_debug(struct Channel *chanp, int direction, char *fmt, ...) +{ + va_list args; + char tmp[16]; + + va_start(args, fmt); + sprintf(tmp, "Ch%d %s ", chanp->chan, + direction ? "LL->HL" : "HL->LL"); + VHiSax_putstatus(chanp->cs, tmp, fmt, args); + va_end(args); +} enum { - ST_NULL, /* 0 inactive */ - ST_OUT_WAIT_D, /* 1 outgoing, awaiting d-channel establishment */ - ST_IN_WAIT_D, /* 2 incoming, awaiting d-channel establishment */ - ST_OUT_DIAL, /* 3 outgoing, SETUP send; awaiting confirm */ - ST_IN_WAIT_LL, /* 4 incoming call received; wait for LL confirm */ - ST_IN_ALERT_SEND, /* 5 incoming call received; ALERT send */ - ST_IN_WAIT_CONN_ACK, /* 6 incoming CONNECT send; awaiting CONN_ACK */ - ST_WAIT_BCONN, /* 7 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ - ST_ACTIVE, /* 8 active, b channel prot. established */ - ST_WAIT_BRELEASE, /* 9 call clear. (initiator), awaiting b channel prot. rel. */ - ST_WAIT_BREL_DISC, /* 10 call clear. (receiver), DISCONNECT req. received */ - ST_WAIT_DCOMMAND, /* 11 call clear. (receiver), awaiting DCHANNEL message */ - ST_WAIT_DRELEASE, /* 12 DISCONNECT sent, awaiting RELEASE */ - ST_WAIT_D_REL_CNF, /* 13 RELEASE sent, awaiting RELEASE confirm */ - ST_WAIT_DSHUTDOWN, /* 14 awaiting d-channel shutdown */ + ST_NULL, /* 0 inactive */ + ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ + ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ + ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ + ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ + ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ + ST_ACTIVE, /* 6 active, b channel prot. established */ + ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ + ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ + ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ + ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ + ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ + ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ }; + -#define STATE_COUNT (ST_WAIT_DSHUTDOWN +1) +#define STATE_COUNT (ST_IN_PROCEED_SEND + 1) -static char *strState[] = -{ - "ST_NULL", - "ST_OUT_WAIT_D", - "ST_IN_WAIT_D", - "ST_OUT_DIAL", - "ST_IN_WAIT_LL", - "ST_IN_ALERT_SEND", - "ST_IN_WAIT_CONN_ACK", - "ST_WAIT_BCONN", - "ST_ACTIVE", + static char *strState[] = + { + "ST_NULL", + "ST_OUT_DIAL", + "ST_IN_WAIT_LL", + "ST_IN_ALERT_SENT", + "ST_IN_WAIT_CONN_ACK", + "ST_WAIT_BCONN", + "ST_ACTIVE", "ST_WAIT_BRELEASE", "ST_WAIT_BREL_DISC", "ST_WAIT_DCOMMAND", "ST_WAIT_DRELEASE", "ST_WAIT_D_REL_CNF", - "ST_WAIT_DSHUTDOWN", + "ST_IN_PROCEED_SEND", }; enum { @@ -192,29 +249,28 @@ EV_SETUP_CNF, /* 1 */ EV_ACCEPTB, /* 2 */ EV_DISCONNECT_IND, /* 3 */ - EV_RELEASE_CNF, /* 4 */ - EV_DLEST, /* 5 */ - EV_DLRL, /* 6 */ + EV_RELEASE, /* 4 */ + EV_LEASED, /* 5 */ + EV_LEASED_REL, /* 6 */ EV_SETUP_IND, /* 7 */ - EV_RELEASE_IND, /* 8 */ - EV_ACCEPTD, /* 9 */ - EV_SETUP_CMPL_IND, /* 10 */ - EV_BC_EST, /* 11 */ - EV_WRITEBUF, /* 12 */ - EV_ESTABLISH, /* 13 */ - EV_HANGUP, /* 14 */ - EV_BC_REL, /* 15 */ - EV_CINF, /* 16 */ - EV_SUSPEND, /* 17 */ - EV_RESUME, /* 18 */ - EV_SHUTDOWN_D, /* 19 */ - EV_NOSETUP_RSP, /* 20 */ - EV_SETUP_ERR, /* 21 */ - EV_CONNECT_ERR, /* 22 */ - EV_RELEASE_ERR, /* 23 */ + EV_ACCEPTD, /* 8 */ + EV_SETUP_CMPL_IND, /* 9 */ + EV_BC_EST, /* 10 */ + EV_WRITEBUF, /* 11 */ + EV_HANGUP, /* 12 */ + EV_BC_REL, /* 13 */ + EV_CINF, /* 14 */ + EV_SUSPEND, /* 15 */ + EV_RESUME, /* 16 */ + EV_NOSETUP_RSP, /* 17 */ + EV_SETUP_ERR, /* 18 */ + EV_CONNECT_ERR, /* 19 */ + EV_PROCEED, /* 20 */ + EV_ALERT, /* 21 */ + EV_REDIR, /* 22 */ }; -#define EVENT_COUNT (EV_RELEASE_ERR +1) +#define EVENT_COUNT (EV_REDIR + 1) static char *strEvent[] = { @@ -222,83 +278,45 @@ "EV_SETUP_CNF", "EV_ACCEPTB", "EV_DISCONNECT_IND", - "EV_RELEASE_CNF", - "EV_DLEST", - "EV_DLRL", + "EV_RELEASE", + "EV_LEASED", + "EV_LEASED_REL", "EV_SETUP_IND", - "EV_RELEASE_IND", "EV_ACCEPTD", "EV_SETUP_CMPL_IND", "EV_BC_EST", "EV_WRITEBUF", - "EV_ESTABLISH", "EV_HANGUP", "EV_BC_REL", "EV_CINF", "EV_SUSPEND", "EV_RESUME", - "EV_SHUTDOWN_D", "EV_NOSETUP_RSP", "EV_SETUP_ERR", "EV_CONNECT_ERR", - "EV_RELEASE_ERR", -}; - -enum { - ST_LC_NULL, - ST_LC_ACTIVATE_WAIT, - ST_LC_DELAY, - ST_LC_ESTABLISH_WAIT, - ST_LC_CONNECTED, - ST_LC_FLUSH_WAIT, - ST_LC_RELEASE_WAIT, -}; - -#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1) - -static char *strLcState[] = -{ - "ST_LC_NULL", - "ST_LC_ACTIVATE_WAIT", - "ST_LC_DELAY", - "ST_LC_ESTABLISH_WAIT", - "ST_LC_CONNECTED", - "ST_LC_FLUSH_WAIT", - "ST_LC_RELEASE_WAIT", -}; - -enum { - EV_LC_ESTABLISH, - EV_LC_PH_ACTIVATE, - EV_LC_PH_DEACTIVATE, - EV_LC_DL_ESTABLISH, - EV_LC_TIMER, - EV_LC_DL_RELEASE, - EV_LC_RELEASE, + "EV_PROCEED", + "EV_ALERT", + "EV_REDIR", }; -#define LC_EVENT_COUNT (EV_LC_RELEASE+1) -static char *strLcEvent[] = +static inline void +HL_LL(struct Channel *chanp, int command) { - "EV_LC_ESTABLISH", - "EV_LC_PH_ACTIVATE", - "EV_LC_PH_DEACTIVATE", - "EV_LC_DL_ESTABLISH", - "EV_LC_TIMER", - "EV_LC_DL_RELEASE", - "EV_LC_RELEASE", -}; - -#define LC_D 0 -#define LC_B 1 + isdn_ctrl ic; + + ic.driver = chanp->cs->myid; + ic.command = command; + ic.arg = chanp->chan; + chanp->cs->iif.statcallb(&ic); +} static inline void lli_deliver_cause(struct Channel *chanp) { - isdn_ctrl ic; - - if (chanp->proc->para.cause < 0) + isdn_ctrl ic; + + if (chanp->proc->para.cause == NO_CAUSE) return; ic.driver = chanp->cs->myid; ic.command = ISDN_STAT_CAUSE; @@ -312,166 +330,121 @@ chanp->cs->iif.statcallb(&ic); } -static void -lli_d_established(struct FsmInst *fi, int event, void *arg) +static inline void +lli_close(struct FsmInst *fi) { - struct Channel *chanp = fi->userdata; - - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - if (chanp->leased) { - isdn_ctrl ic; - int ret; - char txt[32]; + struct Channel *chanp = fi->userdata; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); - FsmChangeState(fi, ST_IN_WAIT_LL); - test_and_set_bit(FLG_CALL_REC, &chanp->Flags); - if (chanp->debug & 1) - link_debug(chanp, "STAT_ICALL_LEASED", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_ICALL; - ic.arg = chanp->chan; - ic.parm.setup.si1 = 7; - ic.parm.setup.si2 = 0; - ic.parm.setup.plan = 0; - ic.parm.setup.screen = 0; - sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); - sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) { - sprintf(txt, "statcallb ret=%d", ret); - link_debug(chanp, txt, 1); - } - if (!ret) { - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); - FsmChangeState(fi, ST_NULL); - } - } else if (fi->state == ST_WAIT_DSHUTDOWN) - FsmChangeState(fi, ST_NULL); + FsmChangeState(fi, ST_NULL); + chanp->Flags = 0; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); +} + + static void +lli_leased_in(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + isdn_ctrl ic; + int ret; + + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_IN_WAIT_LL); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_ICALL_LEASED"); + ic.driver = chanp->cs->myid; + ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); + ic.arg = chanp->chan; + ic.parm.setup.si1 = 7; + ic.parm.setup.si2 = 0; + ic.parm.setup.plan = 0; + ic.parm.setup.screen = 0; + sprintf(ic.parm.setup.eazmsn,"%d", chanp->chan + 1); + sprintf(ic.parm.setup.phone,"LEASED%d", chanp->cs->myid); + ret = chanp->cs->iif.statcallb(&ic); + if (chanp->debug & 1) + link_debug(chanp, 1, "statcallb ret=%d", ret); + + if (!ret) { + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); + FsmChangeState(fi, ST_NULL); + } } -static void -lli_d_released(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - test_and_clear_bit(FLG_START_D, &chanp->Flags); -} /* * Dial out */ static void +lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_WAIT_BCONN); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DCONN"); + HL_LL(chanp, ISDN_STAT_DCONN); + init_b_st(chanp, 0); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); +} + +static void lli_prep_dialout(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_OUT_WAIT_D); FsmDelTimer(&chanp->drel_timer, 60); FsmDelTimer(&chanp->dial_timer, 73); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = 0; - chanp->lc_b->l2_start = !0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b->l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b->l2_establish = 0; - break; - default: - printk(KERN_WARNING "lli_prep_dialout unknown protocol\n"); - break; - } - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { - FsmEvent(fi, EV_DLEST, NULL); - } else { - chanp->Flags = 0; - test_and_set_bit(FLG_START_D, &chanp->Flags); - if (chanp->leased) { - chanp->lc_d->l2_establish = 0; - } - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); - } -} -static void -lli_do_dialout(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_OUT_DIAL); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); - if (chanp->leased) { - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - } else { - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_REQ, chanp); - test_and_set_bit(FLG_CALL_SEND, &chanp->Flags); - } + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + if (chanp->leased) { + lli_init_bchan_out(fi, event, arg); + } else { + FsmChangeState(fi, ST_OUT_DIAL); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); + } } static void -lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) +lli_resume(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - FsmChangeState(fi, ST_WAIT_BCONN); - test_and_set_bit(FLG_LL_DCONN, &chanp->Flags); - if (chanp->debug & 1) - link_debug(chanp, "STAT_DCONN", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DCONN; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - init_b_st(chanp, 0); - test_and_set_bit(FLG_START_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL); + FsmDelTimer(&chanp->drel_timer, 60); + FsmDelTimer(&chanp->dial_timer, 73); + chanp->l2_active_protocol = chanp->l2_protocol; + chanp->incoming = 0; + + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); + if (chanp->leased) { + lli_init_bchan_out(fi, event, arg); + } else { + FsmChangeState(fi, ST_OUT_DIAL); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); + } } static void lli_go_active(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; FsmChangeState(fi, ST_ACTIVE); chanp->data_open = !0; - test_and_set_bit(FLG_CONNECT_B, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_BCONN", 0); - test_and_set_bit(FLG_LL_BCONN, &chanp->Flags); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BCONN; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) chanp->chan); + link_debug(chanp, 0, "STAT_BCONN"); + HL_LL(chanp, ISDN_STAT_BCONN); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan); } -/* incomming call */ -static void -lli_start_dchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; +/* + * RESUME + */ - FsmChangeState(fi, ST_IN_WAIT_D); - FsmDelTimer(&chanp->drel_timer, 61); - if (event == EV_ACCEPTD) - test_and_set_bit(FLG_DO_CONNECT, &chanp->Flags); - else if (event == EV_HANGUP) { - test_and_set_bit(FLG_DO_HANGUP, &chanp->Flags); -#ifdef ALERT_REJECT - test_and_set_bit(FLG_DO_ALERT, &chanp->Flags); -#endif - } - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { - FsmEvent(fi, EV_DLEST, NULL); - } else if (!test_and_set_bit(FLG_START_D, &chanp->Flags)) - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); -} +/* incomming call */ static void lli_deliver_call(struct FsmInst *fi, int event, void *arg) @@ -479,9 +452,8 @@ struct Channel *chanp = fi->userdata; isdn_ctrl ic; int ret; - char txt[32]; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); /* * Report incoming calls only once to linklevel, use CallFlags * which is set to 3 with each broadcast message in isdnl1.c @@ -489,11 +461,11 @@ */ if (1) { /* for only one TEI */ FsmChangeState(fi, ST_IN_WAIT_LL); - test_and_set_bit(FLG_CALL_REC, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_ICALL", 0); + link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW"); ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_ICALL; + ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); + ic.arg = chanp->chan; /* * No need to return "unknown" for calls without OAD, @@ -501,962 +473,496 @@ */ ic.parm.setup = chanp->proc->para.setup; ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) { - sprintf(txt, "statcallb ret=%d", ret); - link_debug(chanp, txt, 1); - } + if (chanp->debug & 1) + link_debug(chanp, 1, "statcallb ret=%d", ret); + switch (ret) { - case 1: /* OK, anybody likes this call */ + case 1: /* OK, someone likes this call */ FsmDelTimer(&chanp->drel_timer, 61); - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) { - FsmChangeState(fi, ST_IN_ALERT_SEND); - test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc); - } else { - test_and_set_bit(FLG_DO_ALERT, &chanp->Flags); - FsmChangeState(fi, ST_IN_WAIT_D); - test_and_set_bit(FLG_START_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); - } + FsmChangeState(fi, ST_IN_ALERT_SENT); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); + break; + case 4: /* direct redirect */ + case 3: /* Proceeding desired */ + FsmDelTimer(&chanp->drel_timer, 61); + FsmChangeState(fi, ST_IN_PROCEED_SEND); + chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); + if (ret == 4) + { chanp->setup = ic.parm.setup; + chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); + } break; case 2: /* Rejecting Call */ - test_and_clear_bit(FLG_CALL_REC, &chanp->Flags); break; case 0: /* OK, nobody likes this call */ default: /* statcallb problems */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); FsmChangeState(fi, ST_NULL); -#ifndef LAYER2_WATCHING - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) - FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61); -#endif break; } } else { - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); - FsmChangeState(fi, ST_NULL); -#ifndef LAYER2_WATCHING - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) - FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62); -#endif + chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); } } static void -lli_establish_d(struct FsmInst *fi, int event, void *arg) +lli_send_dconnect(struct FsmInst *fi, int event, void *arg) { - /* This establish the D-channel for pending L3 messages - * without blocking th channel - */ struct Channel *chanp = fi->userdata; - test_and_set_bit(FLG_DO_ESTAB, &chanp->Flags); - FsmChangeState(fi, ST_IN_WAIT_D); - test_and_set_bit(FLG_START_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL); + FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); } static void -lli_do_action(struct FsmInst *fi, int event, void *arg) +lli_send_alert(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - if (chanp->leased) { - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags); - test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags); - FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); - } else if (test_and_clear_bit(FLG_DO_CONNECT, &chanp->Flags) && - !test_bit(FLG_DO_HANGUP, &chanp->Flags)) { - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc); - } else if (test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags)) { - if (test_bit(FLG_DO_HANGUP, &chanp->Flags)) - FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); - FsmChangeState(fi, ST_IN_ALERT_SEND); - test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc); - } else if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) { - FsmChangeState(fi, ST_WAIT_DRELEASE); - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT_REQ, chanp->proc); - test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); - } else if (test_and_clear_bit(FLG_DO_ESTAB, &chanp->Flags)) { - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ESTABLISH, chanp->proc); - chanp->proc = NULL; -#ifndef LAYER2_WATCHING - FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); -#endif - } + FsmChangeState(fi, ST_IN_ALERT_SENT); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); } static void -lli_send_dconnect(struct FsmInst *fi, int event, void *arg) +lli_send_redir(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc); + chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } static void lli_init_bchan_in(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; FsmChangeState(fi, ST_WAIT_BCONN); - test_and_set_bit(FLG_LL_DCONN, &chanp->Flags); if (chanp->debug & 1) - link_debug(chanp, "STAT_DCONN", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DCONN; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); + link_debug(chanp, 0, "STAT_DCONN"); + HL_LL(chanp, ISDN_STAT_DCONN); chanp->l2_active_protocol = chanp->l2_protocol; chanp->incoming = !0; - chanp->lc_b->l2_start = 0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b->l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b->l2_establish = 0; - break; - default: - printk(KERN_WARNING "bchannel unknown protocol\n"); - break; - } init_b_st(chanp, !0); - test_and_set_bit(FLG_START_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL); -} - -/* Call clearing */ - -static void -lli_cancel_call(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc); - test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); + chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); } static void -lli_shutdown_d(struct FsmInst *fi, int event, void *arg) +lli_setup_rsp(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - - FsmDelTimer(&chanp->drel_timer, 62); -#ifdef LAYER2_WATCHING - FsmChangeState(fi, ST_NULL); -#else - if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) { - if (chanp->chan) { - if (chanp->cs->channel[0].fi.state != ST_NULL) - return; - } else { - if (chanp->cs->channel[1].fi.state != ST_NULL) - return; - } - } - FsmChangeState(fi, ST_WAIT_DSHUTDOWN); - test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); + struct Channel *chanp = fi->userdata; + + if (chanp->leased) { + lli_init_bchan_in(fi, event, arg); + } else { + FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); +#ifdef WANT_ALERT + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); #endif + chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); + } } -static void -lli_timeout_d(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - test_and_set_bit(FLG_ESTAB_D, &chanp->Flags); -#ifndef LAYER2_WATCHING - FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60); -#endif - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); -} +/* Call suspend */ static void -lli_go_null(struct FsmInst *fi, int event, void *arg) +lli_suspend(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - FsmDelTimer(&chanp->drel_timer, 63); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); + chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); } -static void -lli_disconn_bchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_BRELEASE); - test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); -} +/* Call clearing */ static void -lli_send_d_disc(struct FsmInst *fi, int event, void *arg) +lli_disconnect_req(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - if (test_bit(FLG_DISC_REC, &chanp->Flags) || - test_bit(FLG_REL_REC, &chanp->Flags)) - return; FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - if (chanp->leased) { - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L0010"); - chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - FsmChangeState(fi, ST_WAIT_DSHUTDOWN); - test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); - } else { - if (test_and_clear_bit(FLG_DO_HANGUP, &chanp->Flags)) - chanp->proc->para.cause = 0x15; /* Call Reject */ - else - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc); - test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); - } + chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } static void -lli_released_bchan(struct FsmInst *fi, int event, void *arg) +lli_disconnect_reject(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; + struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_WAIT_DCOMMAND); - chanp->data_open = 0; - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - release_b_st(chanp); - test_and_clear_bit(FLG_START_B, &chanp->Flags); + FsmChangeState(fi, ST_WAIT_DRELEASE); + chanp->proc->para.cause = 0x15; /* Call Rejected */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc); } - static void -lli_release_bchan(struct FsmInst *fi, int event, void *arg) +lli_dhup_close(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; + struct Channel *chanp = fi->userdata; - chanp->data_open = 0; - test_and_set_bit(FLG_DISC_REC, &chanp->Flags); - FsmChangeState(fi, ST_WAIT_BREL_DISC); - test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags); - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + lli_deliver_cause(chanp); + HL_LL(chanp, ISDN_STAT_DHUP); + + lli_close(fi); } static void -lli_received_d_rel(struct FsmInst *fi, int event, void *arg) +lli_reject_req(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; + struct Channel *chanp = fi->userdata; - chanp->data_open = 0; - FsmChangeState(fi, ST_NULL); - test_and_set_bit(FLG_REL_REC, &chanp->Flags); - if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); - } - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags); - test_and_clear_bit(FLG_CALL_REC, &chanp->Flags); - test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); - test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); - test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); - lli_timeout_d(fi, event, arg); +#ifndef ALERT_REJECT + chanp->proc->para.cause = 0x15; /* Call Rejected */ + chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); + lli_dhup_close(fi, event, arg); +#else + FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); + FsmChangeState(fi, ST_IN_ALERT_SENT); + chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); +#endif } static void -lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg) +lli_disconn_bchan(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; chanp->data_open = 0; - FsmChangeState(fi, ST_NULL); - if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); - } - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - test_and_clear_bit(FLG_DISC_SEND, &chanp->Flags); - test_and_clear_bit(FLG_CALL_REC, &chanp->Flags); - test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); - test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); - test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); - lli_timeout_d(fi, event, arg); + FsmChangeState(fi, ST_WAIT_BRELEASE); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } static void -lli_received_d_disc(struct FsmInst *fi, int event, void *arg) +lli_start_disc(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; isdn_ctrl ic; - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_D_REL_CNF); - test_and_set_bit(FLG_DISC_REC, &chanp->Flags); - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; + if (chanp->leased) { + ic.command = ISDN_STAT_CAUSE; ic.arg = chanp->chan; + sprintf(ic.parm.num, "L0010"); chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - if (test_bit(FLG_LL_DCONN, &chanp->Flags) || - test_bit(FLG_CALL_SEND, &chanp->Flags) || - test_bit(FLG_CALL_ALERT, &chanp->Flags)) { if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); + link_debug(chanp, 0, "STAT_DHUP"); + HL_LL(chanp, ISDN_STAT_DHUP); + lli_close(fi); + } else { + lli_disconnect_req(fi, event, arg); } - test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags); - test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags); - test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE_REQ, chanp->proc); } -/* processing charge info */ static void -lli_charge_info(struct FsmInst *fi, int event, void *arg) +lli_rel_b_disc(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CINF; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo); - chanp->cs->iif.statcallb(&ic); -} - -/* error procedures */ - -static void -lli_no_dchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - if (chanp->debug & 1) - link_debug(chanp, "STAT_NODCH", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_NODCH; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->Flags = 0; - FsmChangeState(fi, ST_NULL); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); -} - -static void -lli_no_dchan_ready(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); -} - -static void -lli_no_dchan_in(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc); - chanp->Flags = 0; - FsmChangeState(fi, ST_NULL); - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); -} - -static void -lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_NULL); - test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags); - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - lli_shutdown_d(fi, event, arg); + struct Channel *chanp = fi->userdata; + + release_b_st(chanp); + lli_start_disc(fi, event, arg); } static void -lli_setup_err(struct FsmInst *fi, int event, void *arg) +lli_bhup_disc(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */ + struct Channel *chanp = fi->userdata; + + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + + lli_rel_b_disc(fi, event, arg); } static void -lli_connect_err(struct FsmInst *fi, int event, void *arg) +lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; + struct Channel *chanp = fi->userdata; - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */ + FsmChangeState(fi, ST_WAIT_DCOMMAND); + chanp->data_open = 0; + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + release_b_st(chanp); } static void -lli_got_dlrl(struct FsmInst *fi, int event, void *arg) +lli_release_bchan(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; - isdn_ctrl ic; chanp->data_open = 0; - FsmChangeState(fi, ST_NULL); - if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) { - chanp->lc_b->l2_establish = 0; /* direct reset in lc_b->lcfi */ - FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL); - } - if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_BHUP", 0); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) - release_b_st(chanp); - if (chanp->leased) { - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); - chanp->cs->iif.statcallb(&ic); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->Flags = 0; - } else { - if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) { - if (chanp->debug & 1) - link_debug(chanp, "STAT_DHUP", 0); - if (chanp->cs->protocol == ISDN_PTYPE_EURO) { - chanp->proc->para.cause = 0x2f; - chanp->proc->para.loc = 0; - } else { - chanp->proc->para.cause = 0x70; - chanp->proc->para.loc = 0; - } - lli_deliver_cause(chanp); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - } - chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc); - chanp->Flags = 0; - FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL); - } - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan); -} - -/* *INDENT-OFF* */ -static struct FsmNode fnlist[] HISAX_INITDATA = -{ - {ST_NULL, EV_DIAL, lli_prep_dialout}, - {ST_NULL, EV_SETUP_IND, lli_deliver_call}, - {ST_NULL, EV_SHUTDOWN_D, lli_shutdown_d}, - {ST_NULL, EV_DLRL, lli_go_null}, - {ST_NULL, EV_DLEST, lli_d_established}, - {ST_NULL, EV_ESTABLISH, lli_establish_d}, - {ST_OUT_WAIT_D, EV_DLEST, lli_do_dialout}, - {ST_OUT_WAIT_D, EV_DLRL, lli_no_dchan}, - {ST_OUT_WAIT_D, EV_HANGUP, lli_no_dchan}, - {ST_IN_WAIT_D, EV_DLEST, lli_do_action}, - {ST_IN_WAIT_D, EV_DLRL, lli_no_dchan_in}, - {ST_IN_WAIT_D, EV_ACCEPTD, lli_start_dchan}, - {ST_IN_WAIT_D, EV_HANGUP, lli_start_dchan}, - {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out}, - {ST_OUT_DIAL, EV_HANGUP, lli_cancel_call}, - {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_OUT_DIAL, EV_RELEASE_IND, lli_received_d_rel}, - {ST_OUT_DIAL, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp}, - {ST_OUT_DIAL, EV_SETUP_ERR, lli_setup_err}, - {ST_OUT_DIAL, EV_DLRL, lli_got_dlrl}, - {ST_IN_WAIT_LL, EV_DLEST, lli_d_established}, - {ST_IN_WAIT_LL, EV_DLRL, lli_d_released}, - {ST_IN_WAIT_LL, EV_ACCEPTD, lli_start_dchan}, - {ST_IN_WAIT_LL, EV_HANGUP, lli_start_dchan}, - {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_IN_WAIT_LL, EV_RELEASE_IND, lli_received_d_rel}, - {ST_IN_WAIT_LL, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_IN_ALERT_SEND, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_ALERT_SEND, EV_ACCEPTD, lli_send_dconnect}, - {ST_IN_ALERT_SEND, EV_HANGUP, lli_send_d_disc}, - {ST_IN_ALERT_SEND, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_IN_ALERT_SEND, EV_RELEASE_IND, lli_received_d_rel}, - {ST_IN_ALERT_SEND, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_IN_ALERT_SEND, EV_DLRL, lli_got_dlrl}, - {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_send_d_disc}, - {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_IN_WAIT_CONN_ACK, EV_RELEASE_IND, lli_received_d_rel}, - {ST_IN_WAIT_CONN_ACK, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_connect_err}, - {ST_IN_WAIT_CONN_ACK, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_BCONN, EV_BC_EST, lli_go_active}, - {ST_WAIT_BCONN, EV_BC_REL, lli_send_d_disc}, - {ST_WAIT_BCONN, EV_HANGUP, lli_send_d_disc}, - {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_WAIT_BCONN, EV_RELEASE_IND, lli_received_d_rel}, - {ST_WAIT_BCONN, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_WAIT_BCONN, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_BCONN, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_BC_REL, lli_released_bchan}, - {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan}, - {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan}, - {ST_ACTIVE, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_ACTIVE, EV_RELEASE_IND, lli_received_d_rel}, - {ST_ACTIVE, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_BRELEASE, EV_BC_REL, lli_send_d_disc}, - {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_WAIT_BRELEASE, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_WAIT_BRELEASE, EV_RELEASE_IND, lli_received_d_rel}, - {ST_WAIT_BRELEASE, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_BREL_DISC, EV_BC_REL, lli_received_d_disc}, - {ST_WAIT_BREL_DISC, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_WAIT_BREL_DISC, EV_RELEASE_IND, lli_received_d_rel}, - {ST_WAIT_BREL_DISC, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_DCOMMAND, EV_HANGUP, lli_send_d_disc}, - {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_received_d_disc}, - {ST_WAIT_DCOMMAND, EV_RELEASE_CNF, lli_received_d_relcnf}, - {ST_WAIT_DCOMMAND, EV_RELEASE_IND, lli_received_d_rel}, - {ST_WAIT_DCOMMAND, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_DRELEASE, EV_RELEASE_IND, lli_timeout_d}, - {ST_WAIT_DRELEASE, EV_RELEASE_CNF, lli_timeout_d}, - {ST_WAIT_DRELEASE, EV_RELEASE_ERR, lli_timeout_d}, - {ST_WAIT_DRELEASE, EV_DIAL, lli_no_dchan_ready}, - {ST_WAIT_DRELEASE, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_D_REL_CNF, EV_RELEASE_CNF, lli_timeout_d}, - {ST_WAIT_D_REL_CNF, EV_RELEASE_ERR, lli_timeout_d}, -/* ETS 300-104 16.1 */ - {ST_WAIT_D_REL_CNF, EV_RELEASE_IND, lli_timeout_d}, - {ST_WAIT_D_REL_CNF, EV_DIAL, lli_no_dchan_ready}, - {ST_WAIT_D_REL_CNF, EV_DLRL, lli_got_dlrl}, - {ST_WAIT_DSHUTDOWN, EV_DLRL, lli_go_null}, - {ST_WAIT_DSHUTDOWN, EV_DLEST, lli_d_established}, - {ST_WAIT_DSHUTDOWN, EV_DIAL, lli_prep_dialout}, - {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, lli_deliver_call}, -}; -/* *INDENT-ON* */ - - -#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) - -static void -lc_activate_l1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_ACTIVATE_WAIT); - /* This timeout is to avoid a hang if no L1 activation is possible */ - FsmAddTimer(&lf->act_timer, 30000, EV_LC_TIMER, NULL, 50); - lf->st->ma.manl1(lf->st, PH_ACTIVATE_REQ, NULL); -} - -static void -lc_activated_from_l1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - if (lf->l2_establish) - FsmChangeState(fi, ST_LC_DELAY); - else { - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); - } + FsmChangeState(fi, ST_WAIT_BREL_DISC); + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); } -static void -lc_l1_activated(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_DELAY); - /* This timer is needed for delay the first paket on a channel - to be shure that the other side is ready too */ - if (lf->delay) - FsmAddTimer(&lf->act_timer, lf->delay, EV_LC_TIMER, NULL, 51); - else - FsmEvent(fi, EV_LC_TIMER, NULL); -} static void -lc_start_l2(struct FsmInst *fi, int event, void *arg) +lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg) { - struct LcFsm *lf = fi->userdata; + struct Channel *chanp = fi->userdata; -/* if (!lf->st->l1.act_state) - lf->st->l1.act_state = 2; -*/ if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_ESTABLISH_WAIT); - if (lf->l2_start) - lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL); - } else { - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); - } + release_b_st(chanp); + lli_dhup_close(fi, event, arg); } static void -lc_connected(struct FsmInst *fi, int event, void *arg) +lli_bhup_dhup(struct FsmInst *fi, int event, void *arg) { - struct LcFsm *lf = fi->userdata; + struct Channel *chanp = fi->userdata; - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + + lli_rel_b_dhup(fi, event, arg); } static void -lc_release_l2(struct FsmInst *fi, int event, void *arg) +lli_abort(struct FsmInst *fi, int event, void *arg) { - struct LcFsm *lf = fi->userdata; + struct Channel *chanp = fi->userdata; - if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_RELEASE_WAIT); - lf->st->ma.manl2(lf->st, DL_RELEASE, NULL); - } else { - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL); - lf->lccall(lf, LC_RELEASE, NULL); - } + chanp->data_open = 0; + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + + lli_bhup_dhup(fi, event, arg); } - + static void -lc_l2_released(struct FsmInst *fi, int event, void *arg) +lli_release_req(struct FsmInst *fi, int event, void *arg) { - struct LcFsm *lf = fi->userdata; - - FsmChangeState(fi, ST_LC_RELEASE_WAIT); - FsmDelTimer(&lf->act_timer, 51); - /* This delay is needed for send out the UA frame before - * PH_DEACTIVATE the interface - */ - FsmAddTimer(&lf->act_timer, 20, EV_LC_TIMER, NULL, 54); + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_WAIT_D_REL_CNF); + chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc); } static void -lc_release_l1(struct FsmInst *fi, int event, void *arg) +lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg) { - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 54); - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL); - lf->lccall(lf, LC_RELEASE, NULL); + struct Channel *chanp = fi->userdata; + + release_b_st(chanp); + lli_release_req(fi, event, arg); } static void -lc_l1_deactivated(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 54); - FsmChangeState(fi, ST_LC_NULL); - lf->lccall(lf, LC_RELEASE, NULL); -} -/* *INDENT-OFF* */ -static struct FsmNode LcFnList[] HISAX_INITDATA = -{ - {ST_LC_NULL, EV_LC_ESTABLISH, lc_activate_l1}, - {ST_LC_NULL, EV_LC_PH_ACTIVATE, lc_activated_from_l1}, - {ST_LC_NULL, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_l1_activated}, - {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_release_l1}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_DELAY, EV_LC_ESTABLISH, lc_start_l2}, - {ST_LC_DELAY, EV_LC_TIMER, lc_start_l2}, - {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_DELAY, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_connected}, - {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_release_l1}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_release_l1}, - {ST_LC_ESTABLISH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_CONNECTED, EV_LC_ESTABLISH, lc_connected}, - {ST_LC_CONNECTED, EV_LC_RELEASE, lc_release_l2}, - {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_l2_released}, - {ST_LC_CONNECTED, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_FLUSH_WAIT, EV_LC_TIMER, lc_release_l2}, - {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, - {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_release_l1}, - {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_release_l1}, - {ST_LC_FLUSH_WAIT, EV_LC_PH_DEACTIVATE, lc_l1_deactivated}, -}; -/* *INDENT-ON* */ - - -#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) - -HISAX_INITFUNC(void -CallcNew(void)) +lli_bhup_release_req(struct FsmInst *fi, int event, void *arg) { - callcfsm.state_count = STATE_COUNT; - callcfsm.event_count = EVENT_COUNT; - callcfsm.strEvent = strEvent; - callcfsm.strState = strState; - FsmNew(&callcfsm, fnlist, FNCOUNT); - - lcfsm.state_count = LC_STATE_COUNT; - lcfsm.event_count = LC_EVENT_COUNT; - lcfsm.strEvent = strLcEvent; - lcfsm.strState = strLcState; - FsmNew(&lcfsm, LcFnList, LC_FN_COUNT); + struct Channel *chanp = fi->userdata; + + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + + lli_rel_b_release_req(fi, event, arg); } -void -CallcFree(void) -{ - FsmFree(&lcfsm); - FsmFree(&callcfsm); -} +/* processing charge info */ static void -release_b_st(struct Channel *chanp) +lli_charge_info(struct FsmInst *fi, int event, void *arg) { - struct PStack *st = chanp->b_st; + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; - chanp->bcs->BC_Close(chanp->bcs); - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - releasestack_isdnl2(st); - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - releasestack_transl2(st); - break; - } - /* Reset B-Channel Statemachine */ - FsmDelTimer(&chanp->lc_b->act_timer, 79); - FsmChangeState(&chanp->lc_b->lcfi, ST_LC_NULL); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_CINF; + ic.arg = chanp->chan; + sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo); + chanp->cs->iif.statcallb(&ic); } +/* error procedures */ + static void -dc_l1man(struct PStack *st, int pr, void *arg) +lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp; + struct Channel *chanp = fi->userdata; - chanp = (struct Channel *) st->lli.userdata; - switch (pr) { - case (PH_ACTIVATE_CNF): - case (PH_ACTIVATE_IND): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE_IND): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + HL_LL(chanp, ISDN_STAT_DHUP); } static void -dc_l2man(struct PStack *st, int pr, void *arg) +lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) { - struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct Channel *chanp = fi->userdata; - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_RELEASE, NULL); - break; - } -} + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_DHUP"); + HL_LL(chanp, ISDN_STAT_DHUP); + lli_close(fi); +} + +static void +lli_error(struct FsmInst *fi, int event, void *arg) +{ + FsmChangeState(fi, ST_WAIT_DRELEASE); +} + +static void +lli_failure_l(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + isdn_ctrl ic; + + FsmChangeState(fi, ST_NULL); + ic.driver = chanp->cs->myid; + ic.command = ISDN_STAT_CAUSE; + ic.arg = chanp->chan; + sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); + chanp->cs->iif.statcallb(&ic); + HL_LL(chanp, ISDN_STAT_DHUP); + chanp->Flags = 0; + chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); +} + +static void +lli_rel_b_fail(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + release_b_st(chanp); + lli_failure_l(fi, event, arg); +} + +static void +lli_bhup_fail(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + if (chanp->debug & 1) + link_debug(chanp, 0, "STAT_BHUP"); + HL_LL(chanp, ISDN_STAT_BHUP); + + lli_rel_b_fail(fi, event, arg); +} + +static void +lli_failure_a(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->data_open = 0; + chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); + + lli_bhup_fail(fi, event, arg); +} + + /* *INDENT-OFF* */ + static struct FsmNode fnlist[] HISAX_INITDATA = + { + {ST_NULL, EV_DIAL, lli_prep_dialout}, + {ST_NULL, EV_RESUME, lli_resume}, + {ST_NULL, EV_SETUP_IND, lli_deliver_call}, + {ST_NULL, EV_LEASED, lli_leased_in}, + {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out}, + {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req}, + {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req}, + {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close}, + {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp}, + {ST_OUT_DIAL, EV_SETUP_ERR, lli_error}, + {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l}, + {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp}, + {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, + {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, + {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, + {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, + {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, + {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, + {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req}, + {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, + {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir}, + {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir}, + {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert}, + {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect}, + {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject}, + {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close}, + {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in}, + {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req}, + {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req}, + {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close}, + {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error}, + {ST_WAIT_BCONN, EV_BC_EST, lli_go_active}, + {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc}, + {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc}, + {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req}, + {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup}, + {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail}, + {ST_WAIT_BCONN, EV_CINF, lli_charge_info}, + {ST_ACTIVE, EV_CINF, lli_charge_info}, + {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b}, + {ST_ACTIVE, EV_SUSPEND, lli_suspend}, + {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan}, + {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan}, + {ST_ACTIVE, EV_RELEASE, lli_abort}, + {ST_ACTIVE, EV_LEASED_REL, lli_failure_a}, + {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc}, + {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req}, + {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup}, + {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail}, + {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req}, + {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup}, + {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc}, + {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req}, + {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close}, + {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l}, + {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close}, + {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready}, + /* ETS 300-104 16.1 */ + {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close}, + {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready}, +}; + /* *INDENT-ON* */ -static void -bc_l1man(struct PStack *st, int pr, void *arg) + + #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) + +HISAX_INITFUNC(void +CallcNew(void)) { - struct Channel *chanp = (struct Channel *) st->lli.userdata; + callcfsm.state_count = STATE_COUNT; + callcfsm.event_count = EVENT_COUNT; + callcfsm.strEvent = strEvent; + callcfsm.strState = strState; + FsmNew(&callcfsm, fnlist, FNCOUNT); +} - switch (pr) { - case (PH_ACTIVATE_IND): - case (PH_ACTIVATE_CNF): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE_IND): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } +void +CallcFree(void) +{ + FsmFree(&callcfsm); } static void -bc_l2man(struct PStack *st, int pr, void *arg) +release_b_st(struct Channel *chanp) { - struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct PStack *st = chanp->b_st; - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_RELEASE, NULL); - break; - } + if(test_and_clear_bit(FLG_START_B, &chanp->Flags)) { + chanp->bcs->BC_Close(chanp->bcs); + switch (chanp->l2_active_protocol) { + case (ISDN_PROTO_L2_X75I): + releasestack_isdnl2(st); + break; + case (ISDN_PROTO_L2_HDLC): + case (ISDN_PROTO_L2_TRANS): + case (ISDN_PROTO_L2_MODEM): + releasestack_transl2(st); + break; + } + } } struct Channel -*selectfreechannel(struct PStack *st) +*selectfreechannel(struct PStack *st, int bch) { struct IsdnCardState *cs = st->l1.hardware; struct Channel *chanp = st->lli.userdata; @@ -1466,87 +972,96 @@ i=1; else i=0; - while (i<2) { + + if (!bch) + { i = 2; /* virtual channel */ + chanp += 2; + } + + while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) { if (chanp->fi.state == ST_NULL) return (chanp); chanp++; i++; - } - return (NULL); -} - -int -is_activ(struct PStack *st) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct Channel *chanp = st->lli.userdata; - int i; + } - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) - i=1; - else - i=0; - while (i<2) { - if (test_bit(FLG_ESTAB_D, &chanp->Flags)) - return (1); + if (bch) /* number of channels is limited */ + { i = 2; /* virtual channel */ + chanp = st->lli.userdata; + chanp += i; + while (i < (2 + MAX_WAITING_CALLS)) { + if (chanp->fi.state == ST_NULL) + return (chanp); chanp++; i++; - } - return (0); + } + } + return (NULL); } +static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result) +{ isdn_ctrl ic; + + ic.driver = cs->myid; + ic.command = ISDN_STAT_REDIR; + ic.arg = chan; + (ulong)(ic.parm.num[0]) = result; + cs->iif.statcallb(&ic); +} /* stat_redir_result */ + static void -ll_handler(struct l3_process *pc, int pr, void *arg) +dchan_l3l4(struct PStack *st, int pr, void *arg) { + struct l3_process *pc = arg; + struct IsdnCardState *cs = st->l1.hardware; struct Channel *chanp; - char tmp[64], tm[32]; - if (pr == CC_SETUP_IND) { - if (!(chanp = selectfreechannel(pc->st))) { - pc->st->lli.l4l3(pc->st, CC_DLRL, pc); - return; - } else { - chanp->proc = pc; - pc->chan = chanp; + if(!pc) + return; + + if (pr == (CC_SETUP | INDICATION)) { + if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { + pc->para.cause = 0x11; /* User busy */ + pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); + } else { + chanp->proc = pc; + pc->chan = chanp; FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - return; } - } else if (pr == CC_ESTABLISH) { - if (is_activ(pc->st)) { - pc->st->lli.l4l3(pc->st, CC_ESTABLISH, pc); - return; - } else if (!(chanp = selectfreechannel(pc->st))) { - pc->st->lli.l4l3(pc->st, CC_DLRL, pc); - return; - } else { - chanp->proc = pc; - FsmEvent(&chanp->fi, EV_ESTABLISH, NULL); - return; - } - - + return; } - chanp = pc->chan; + if (!(chanp = pc->chan)) + return; + switch (pr) { - case (CC_DISCONNECT_IND): + case (CC_DISCONNECT | INDICATION): FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); break; - case (CC_RELEASE_CNF): - FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); + case (CC_RELEASE | CONFIRM): + FsmEvent(&chanp->fi, EV_RELEASE, NULL); + break; + case (CC_SUSPEND | CONFIRM): + FsmEvent(&chanp->fi, EV_RELEASE, NULL); + break; + case (CC_RESUME | CONFIRM): + FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); + break; + case (CC_RESUME_ERR): + FsmEvent(&chanp->fi, EV_RELEASE, NULL); break; - case (CC_RELEASE_IND): - FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL); + case (CC_RELEASE | INDICATION): + FsmEvent(&chanp->fi, EV_RELEASE, NULL); break; - case (CC_SETUP_COMPLETE_IND): + case (CC_SETUP_COMPL | INDICATION): FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); break; - case (CC_SETUP_CNF): + case (CC_SETUP | CONFIRM): FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); break; - case (CC_INFO_CHARGE): + case (CC_CHARGE | INDICATION): FsmEvent(&chanp->fi, EV_CINF, NULL); break; - case (CC_NOSETUP_RSP_ERR): + case (CC_NOSETUP_RSP): FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL); break; case (CC_SETUP_ERR): @@ -1556,17 +1071,22 @@ FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL); break; case (CC_RELEASE_ERR): - FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL); - break; - case (CC_PROCEEDING_IND): - case (CC_ALERTING_IND): + FsmEvent(&chanp->fi, EV_RELEASE, NULL); break; + case (CC_PROCEED_SEND | INDICATION): + case (CC_PROCEEDING | INDICATION): + case (CC_ALERTING | INDICATION): + case (CC_PROGRESS | INDICATION): + case (CC_NOTIFY | INDICATION): + break; + case (CC_REDIR | INDICATION): + stat_redir_result(cs, chanp->chan, pc->redir_result); + break; default: if (chanp->debug & 0x800) { - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n", - tm, chanp->chan, pr); - HiSax_putstatus(chanp->cs, tmp); + HiSax_putstatus(chanp->cs, "Ch", + "%d L3->L4 unknown primitiv %#x", + chanp->chan, pr); } } } @@ -1576,7 +1096,7 @@ { struct PStack *st = chanp->d_st; struct IsdnCardState *cs = chanp->cs; - char tmp[128]; + char tmp[16]; HiSax_addlist(cs, st); setstack_HiSax(st, cs); @@ -1590,95 +1110,51 @@ st->l2.window = 1; st->l2.T200 = 1000; /* 1000 milliseconds */ st->l2.N200 = 3; /* try 3 times */ - if (st->protocol == ISDN_PTYPE_1TR6) - st->l2.T203 = 10000; /* 10000 milliseconds */ + st->l2.T203 = 10000; /* 10000 milliseconds */ + if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) + sprintf(tmp, "DCh%d Q.921 ", chanp->chan); else - st->l2.T203 = 10000; /* 5000 milliseconds */ - - sprintf(tmp, "Channel %d q.921", chanp->chan); + sprintf(tmp, "DCh Q.921 "); setstack_isdnl2(st, tmp); - setstack_isdnl3(st, chanp); + setstack_l3dc(st, chanp); st->lli.userdata = chanp; st->lli.l2writewakeup = NULL; - st->l3.l3l4 = ll_handler; - st->l1.l1man = dc_l1man; - st->l2.l2man = dc_l2man; + st->l3.l3l4 = dchan_l3l4; } static void -callc_debug(struct FsmInst *fi, char *s) +callc_debug(struct FsmInst *fi, char *fmt, ...) { - char str[80], tm[32]; + va_list args; struct Channel *chanp = fi->userdata; + char tmp[16]; - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s); - HiSax_putstatus(chanp->cs, str); -} - -static void -lc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d dc %s\n", tm, lf->ch->chan, s); - HiSax_putstatus(lf->ch->cs, str); -} - -static void -dlc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d bc %s\n", tm, lf->ch->chan, s); - HiSax_putstatus(lf->ch->cs, str); + va_start(args, fmt); + sprintf(tmp, "Ch%d callc ", chanp->chan); + VHiSax_putstatus(chanp->cs, tmp, fmt, args); + va_end(args); } static void -lccall_d(struct LcFsm *lf, int pr, void *arg) -{ - struct IsdnCardState *cs = lf->st->l1.hardware; - struct Channel *chanp; - int i; - - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) { - chanp = lf->ch; - i = 1; - } else { - chanp = cs->channel; - i = 0; - } - while (i < 2) { - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_DLEST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_DLRL, NULL); - break; - } - chanp++; - i++; - } +dummy_pstack(struct PStack *st, int pr, void *arg) { + printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg); } static void -lccall_b(struct LcFsm *lf, int pr, void *arg) -{ - struct Channel *chanp = lf->ch; - - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - } +init_PStack(struct PStack **stp) { + *stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC); + (*stp)->next = NULL; + (*stp)->l1.l1l2 = dummy_pstack; + (*stp)->l1.l1hw = dummy_pstack; + (*stp)->l1.l1tei = dummy_pstack; + (*stp)->l2.l2tei = dummy_pstack; + (*stp)->l2.l2l1 = dummy_pstack; + (*stp)->l2.l2l3 = dummy_pstack; + (*stp)->l3.l3l2 = dummy_pstack; + (*stp)->l3.l3ml3 = dummy_pstack; + (*stp)->l3.l3l4 = dummy_pstack; + (*stp)->lli.l4l3 = dummy_pstack; + (*stp)->ma.layer = dummy_pstack; } static void @@ -1693,9 +1169,8 @@ chanp->debug = 0; chanp->Flags = 0; chanp->leased = 0; - chanp->b_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC); - chanp->b_st->next = NULL; - + init_PStack(&chanp->b_st); + chanp->b_st->l1.delay = DEFAULT_B_DELAY; chanp->fi.fsm = &callcfsm; chanp->fi.state = ST_NULL; chanp->fi.debug = 0; @@ -1704,56 +1179,35 @@ FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - chanp->d_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC); + init_PStack(&chanp->d_st); + if (chan) + csta->channel->d_st->next = chanp->d_st; chanp->d_st->next = NULL; init_d_st(chanp); - chanp->lc_d = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC); - chanp->lc_d->lcfi.fsm = &lcfsm; - chanp->lc_d->lcfi.state = ST_LC_NULL; - chanp->lc_d->lcfi.debug = 0; - chanp->lc_d->lcfi.userdata = chanp->lc_d; - chanp->lc_d->lcfi.printdebug = lc_debug; - chanp->lc_d->type = LC_D; - chanp->lc_d->delay = 0; - chanp->lc_d->ch = chanp; - chanp->lc_d->st = chanp->d_st; - chanp->lc_d->l2_establish = !0; - chanp->lc_d->l2_start = !0; - chanp->lc_d->lccall = lccall_d; - FsmInitTimer(&chanp->lc_d->lcfi, &chanp->lc_d->act_timer); } else { chanp->d_st = csta->channel->d_st; - chanp->lc_d = csta->channel->lc_d; } - chanp->lc_b = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC); - chanp->lc_b->lcfi.fsm = &lcfsm; - chanp->lc_b->lcfi.state = ST_LC_NULL; - chanp->lc_b->lcfi.debug = 0; - chanp->lc_b->lcfi.userdata = chanp->lc_b; - chanp->lc_b->lcfi.printdebug = dlc_debug; - chanp->lc_b->type = LC_B; - chanp->lc_b->delay = DEFAULT_B_DELAY; - chanp->lc_b->ch = chanp; - chanp->lc_b->st = chanp->b_st; - chanp->lc_b->l2_establish = !0; - chanp->lc_b->l2_start = !0; - chanp->lc_b->lccall = lccall_b; - FsmInitTimer(&chanp->lc_b->lcfi, &chanp->lc_b->act_timer); chanp->data_open = 0; } int CallcNewChan(struct IsdnCardState *csta) -{ +{ int i; + chancount += 2; init_chan(0, csta); init_chan(1, csta); printk(KERN_INFO "HiSax: 2 channels added\n"); -#ifdef LAYER2_WATCHING - printk(KERN_INFO "LAYER2 ESTABLISH\n"); - test_and_set_bit(FLG_START_D, &csta->channel->Flags); - FsmEvent(&csta->channel->lc_d->lcfi, EV_LC_ESTABLISH, NULL); -#endif + + for (i = 0; i < MAX_WAITING_CALLS; i++) + init_chan(i+2,csta); + printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); + + if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { + printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); + csta->channel->d_st->lli.l4l3(csta->channel->d_st, + DL_ESTABLISH | REQUEST, NULL); + } return (2); } @@ -1779,29 +1233,16 @@ for (i = 0; i < 2; i++) { FsmDelTimer(&csta->channel[i].drel_timer, 74); FsmDelTimer(&csta->channel[i].dial_timer, 75); - FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77); - FsmDelTimer(&csta->channel[i].lc_b->act_timer, 76); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) - release_d_st(csta->channel + i); - if (csta->channel[i].b_st) { - if (test_and_clear_bit(FLG_START_B, &csta->channel[i].Flags)) - release_b_st(csta->channel + i); - kfree(csta->channel[i].b_st); - csta->channel[i].b_st = NULL; - } else + if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) + release_d_st(csta->channel + i); + if (csta->channel[i].b_st) { + release_b_st(csta->channel + i); + kfree(csta->channel[i].b_st); + csta->channel[i].b_st = NULL; + } else printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i); - if (csta->channel[i].lc_b) { - kfree(csta->channel[i].lc_b); - csta->channel[i].b_st = NULL; - } if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { release_d_st(csta->channel + i); - FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77); - if (csta->channel[i].lc_d) { - kfree(csta->channel[i].lc_d); - csta->channel[i].d_st = NULL; - } else - printk(KERN_WARNING "CallcFreeChan lc_d ch%d allready freed\n", i); } else csta->channel[i].d_st = NULL; } @@ -1814,15 +1255,23 @@ struct sk_buff *skb = arg; switch (pr) { - case (DL_DATA): + case (DL_DATA | INDICATION): if (chanp->data_open) chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); else { - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } break; + case (DL_ESTABLISH | INDICATION): + case (DL_ESTABLISH | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_EST, NULL); + break; + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_REL, NULL); + break; default: - printk(KERN_WARNING "lldata_handler unknown primitive %d\n", + printk(KERN_WARNING "lldata_handler unknown primitive %#x\n", pr); break; } @@ -1835,22 +1284,24 @@ struct sk_buff *skb = arg; switch (pr) { - case (PH_DATA_IND): + case (PH_DATA | INDICATION): if (chanp->data_open) chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); else { - if (chanp->lc_b->lcfi.state == ST_LC_DELAY) - FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL); - if (chanp->data_open) { - link_debug(chanp, "channel now open", 0); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, - chanp->chan, skb); - } else - dev_kfree_skb(skb); + link_debug(chanp, 0, "channel not open"); + idev_kfree_skb(skb, FREE_READ); } break; + case (PH_ACTIVATE | INDICATION): + case (PH_ACTIVATE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_EST, NULL); + break; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + FsmEvent(&chanp->fi, EV_BC_REL, NULL); + break; default: - printk(KERN_WARNING "lltrans_handler unknown primitive %d\n", + printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n", pr); break; } @@ -1874,10 +1325,25 @@ { struct PStack *st = chanp->b_st; struct IsdnCardState *cs = chanp->cs; - char tmp[128]; + char tmp[16]; st->l1.hardware = cs; - chanp->bcs->mode = 2; + if (chanp->leased) + st->l1.bc = chanp->chan & 1; + else + st->l1.bc = chanp->proc->para.bchannel - 1; + switch (chanp->l2_active_protocol) { + case (ISDN_PROTO_L2_X75I): + case (ISDN_PROTO_L2_HDLC): + st->l1.mode = L1_MODE_HDLC; + break; + case (ISDN_PROTO_L2_TRANS): + st->l1.mode = L1_MODE_TRANS; + break; + case (ISDN_PROTO_L2_MODEM): + st->l1.mode = L1_MODE_MODEM; + break; + } if (chanp->bcs->BC_SetStack(st, chanp->bcs)) return (-1); st->l2.flag = 0; @@ -1892,50 +1358,89 @@ st->l3.debug = 0; switch (chanp->l2_active_protocol) { case (ISDN_PROTO_L2_X75I): - sprintf(tmp, "Channel %d x.75", chanp->chan); + sprintf(tmp, "Ch%d X.75", chanp->chan); setstack_isdnl2(st, tmp); + setstack_l3bc(st, chanp); st->l2.l2l3 = lldata_handler; - st->l1.l1man = bc_l1man; - st->l2.l2man = bc_l2man; st->lli.userdata = chanp; st->lli.l1writewakeup = NULL; st->lli.l2writewakeup = ll_writewakeup; st->l2.l2m.debug = chanp->debug & 16; st->l2.debug = chanp->debug & 64; - st->ma.manl2(st, MDL_NOTEIPROC, NULL); - st->l1.mode = L1_MODE_HDLC; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; break; case (ISDN_PROTO_L2_HDLC): - st->l1.l1l2 = lltrans_handler; - st->l1.l1man = bc_l1man; - st->lli.userdata = chanp; - st->lli.l1writewakeup = ll_writewakeup; - st->l1.mode = L1_MODE_HDLC; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; - break; case (ISDN_PROTO_L2_TRANS): + case (ISDN_PROTO_L2_MODEM): st->l1.l1l2 = lltrans_handler; - st->l1.l1man = bc_l1man; st->lli.userdata = chanp; st->lli.l1writewakeup = ll_writewakeup; - st->l1.mode = L1_MODE_TRANS; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; + setstack_transl2(st); + setstack_l3bc(st, chanp); break; } + test_and_set_bit(FLG_START_B, &chanp->Flags); + return (0); } static void +leased_l4l3(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct sk_buff *skb = arg; + + switch (pr) { + case (DL_DATA | REQUEST): + link_debug(chanp, 0, "leased line d-channel DATA"); + idev_kfree_skb(skb, FREE_READ); + break; + case (DL_ESTABLISH | REQUEST): + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); + break; + case (DL_RELEASE | REQUEST): + break; + default: + printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n", + pr); + break; + } +} + +static void +leased_l1l2(struct PStack *st, int pr, void *arg) +{ + struct Channel *chanp = (struct Channel *) st->lli.userdata; + struct sk_buff *skb = arg; + int i,event = EV_LEASED_REL; + + switch (pr) { + case (PH_DATA | INDICATION): + link_debug(chanp, 0, "leased line d-channel DATA"); + idev_kfree_skb(skb, FREE_READ); + break; + case (PH_ACTIVATE | INDICATION): + case (PH_ACTIVATE | CONFIRM): + event = EV_LEASED; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) + i = 1; + else + i = 0; + while (i < 2) { + FsmEvent(&chanp->fi, event, NULL); + chanp++; + i++; + } + break; + default: + printk(KERN_WARNING + "transd_l1l2 unknown primitive %#x\n", pr); + break; + } +} + +static void channel_report(struct Channel *chanp) { } @@ -1946,30 +1451,117 @@ int i; struct Channel *chanp = csta->channel; - for (i = 0; i < 2; i++) { + for (i = 0; i < (2 + MAX_WAITING_CALLS) ; i++) { chanp[i].debug = debugflags; chanp[i].fi.debug = debugflags & 2; chanp[i].d_st->l2.l2m.debug = debugflags & 8; chanp[i].b_st->l2.l2m.debug = debugflags & 0x10; chanp[i].d_st->l2.debug = debugflags & 0x20; chanp[i].b_st->l2.debug = debugflags & 0x40; - chanp[i].lc_d->lcfi.debug = debugflags & 0x80; - chanp[i].lc_b->lcfi.debug = debugflags & 0x100; + chanp[i].d_st->l3.l3m.debug = debugflags & 0x80; + chanp[i].b_st->l3.l3m.debug = debugflags & 0x100; chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200; chanp[i].b_st->ma.debug = debugflags & 0x200; chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000; + chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000; + } + if (debugflags & 4) + csta->debug |= DEB_DLOG_HEX; + else + csta->debug &= ~DEB_DLOG_HEX; +} + +static char tmpbuf[256]; + +static void +capi_debug(struct Channel *chanp, capi_msg *cm) +{ + char *t = tmpbuf; + + t += sprintf(tmpbuf, "%d CAPIMSG", chanp->chan); + t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length); + t--; + *t= 0; + HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); +} + +void +lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { + if ((cm->para[0] != 3) || (cm->para[1] != 0)) + return; + if (cm->para[2]<3) + return; + if (cm->para[4] != 0) + return; + switch(cm->para[3]) { + case 4: /* Suspend */ + if (cm->para[5]) { + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + FsmEvent(&chanp->fi, EV_SUSPEND, cm); + } + break; + case 5: /* Resume */ + if (cm->para[5]) { + strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1); + if (chanp->fi.state == ST_NULL) { + FsmEvent(&chanp->fi, EV_RESUME, cm); + } else { + FsmDelTimer(&chanp->dial_timer, 72); + FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73); + } + } + break; + } +} + +void +lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { + if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || + (cs->typ == ISDN_CTYPE_ELSA_PCI)) { + if (cs->hw.elsa.MFlag) { + cs->cardmsg(cs, CARD_AUX_IND, cm->para); + } } - csta->dlogflag = debugflags & 4; } + +/***************************************************************/ +/* Limit the available number of channels for the current card */ +/***************************************************************/ +static int +set_channel_limit(struct IsdnCardState *cs, int chanmax) +{ isdn_ctrl ic; + int i, ii; + + if ((chanmax < 0) || (chanmax > 2)) + return(-EINVAL); + cs->chanlimit = 0; + for (ii = 0; ii < 2; ii++) { + ic.driver = cs->myid; + ic.command = ISDN_STAT_DISCH; + ic.arg = ii; + if (ii >= chanmax) + ic.parm.num[0] = 0; /* disabled */ + else + ic.parm.num[0] = 1; /* enabled */ + i = cs->iif.statcallb(&ic); + if (i) return(-EINVAL); + if (ii < chanmax) + cs->chanlimit++; + } + return(0); +} /* set_channel_limit */ + + int HiSax_command(isdn_ctrl * ic) { struct IsdnCardState *csta = hisax_findcard(ic->driver); + struct PStack *st; struct Channel *chanp; - char tmp[128]; int i; - unsigned int num; + u_int num; + u_long adr; if (!csta) { printk(KERN_ERR @@ -1977,32 +1569,32 @@ ic->command, ic->driver); return -ENODEV; } + switch (ic->command) { case (ISDN_CMD_SETEAZ): chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "SETEAZ card %d %s", csta->cardnr + 1, - ic->parm.num); - link_debug(chanp, tmp, 1); - } break; + case (ISDN_CMD_SETL2): chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "SETL2 card %d %ld", csta->cardnr + 1, - ic->arg >> 8); - link_debug(chanp, tmp, 1); - } + if (chanp->debug & 1) + link_debug(chanp, 1, "SETL2 card %d %ld", + csta->cardnr + 1, ic->arg >> 8); chanp->l2_protocol = ic->arg >> 8; break; + case (ISDN_CMD_SETL3): + chanp = csta->channel + (ic->arg & 0xff); + if (chanp->debug & 1) + link_debug(chanp, 1, "SETL3 card %d %ld", + csta->cardnr + 1, ic->arg >> 8); + chanp->l3_protocol = ic->arg >> 8; + break; case (ISDN_CMD_DIAL): chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "DIAL %s -> %s (%d,%d)", + if (chanp->debug & 1) + link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", ic->parm.setup.eazmsn, ic->parm.setup.phone, - ic->parm.setup.si1, ic->parm.setup.si2); - link_debug(chanp, tmp, 1); - } + ic->parm.setup.si1, ic->parm.setup.si2); chanp->setup = ic->parm.setup; if (!strcmp(chanp->setup.eazmsn, "0")) chanp->setup.eazmsn[0] = '\0'; @@ -2018,57 +1610,54 @@ case (ISDN_CMD_ACCEPTB): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "ACCEPTB", 1); + link_debug(chanp, 1, "ACCEPTB"); FsmEvent(&chanp->fi, EV_ACCEPTB, NULL); break; case (ISDN_CMD_ACCEPTD): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "ACCEPTD", 1); + link_debug(chanp, 1, "ACCEPTD"); FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); break; case (ISDN_CMD_HANGUP): chanp = csta->channel + ic->arg; if (chanp->debug & 1) - link_debug(chanp, "HANGUP", 1); + link_debug(chanp, 1, "HANGUP"); FsmEvent(&chanp->fi, EV_HANGUP, NULL); break; - case (ISDN_CMD_SUSPEND): + case (CAPI_PUT_MESSAGE): chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "SUSPEND %s", ic->parm.num); - link_debug(chanp, tmp, 1); - } - FsmEvent(&chanp->fi, EV_SUSPEND, ic); - break; - case (ISDN_CMD_RESUME): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "RESUME %s", ic->parm.num); - link_debug(chanp, tmp, 1); + if (chanp->debug & 1) + capi_debug(chanp, &ic->parm.cmsg); + if (ic->parm.cmsg.Length < 8) + break; + switch(ic->parm.cmsg.Command) { + case CAPI_FACILITY: + if (ic->parm.cmsg.Subcommand == CAPI_REQ) + lli_got_fac_req(chanp, &ic->parm.cmsg); + break; + case CAPI_MANUFACTURER: + if (ic->parm.cmsg.Subcommand == CAPI_REQ) + lli_got_manufacturer(chanp, csta, &ic->parm.cmsg); + break; + default: + break; } - FsmEvent(&chanp->fi, EV_RESUME, ic); break; case (ISDN_CMD_LOCK): HiSax_mod_inc_use_count(); #ifdef MODULE - if (csta->channel[0].debug & 0x400) { - jiftime(tmp, jiffies); - i = strlen(tmp); - sprintf(tmp + i, " LOCK modcnt %d\n", MOD_USE_COUNT); - HiSax_putstatus(csta, tmp); - } + if (csta->channel[0].debug & 0x400) + HiSax_putstatus(csta, " LOCK ", "modcnt %lx", + MOD_USE_COUNT); #endif /* MODULE */ break; case (ISDN_CMD_UNLOCK): HiSax_mod_dec_use_count(); #ifdef MODULE - if (csta->channel[0].debug & 0x400) { - jiftime(tmp, jiffies); - i = strlen(tmp); - sprintf(tmp + i, " UNLOCK modcnt %d\n", MOD_USE_COUNT); - HiSax_putstatus(csta, tmp); - } + if (csta->channel[0].debug & 0x400) + HiSax_putstatus(csta, " UNLOCK ", "modcnt %lx", + MOD_USE_COUNT); #endif /* MODULE */ break; case (ISDN_CMD_IOCTL): @@ -2081,19 +1670,19 @@ case (1): num = *(unsigned int *) ic->parm.num; distr_debug(csta, num); - sprintf(tmp, "debugging flags card %d set to %x\n", + printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n", csta->cardnr + 1, num); - HiSax_putstatus(csta, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); + HiSax_putstatus(csta, "debugging flags ", + "card %d set to %x", csta->cardnr + 1, num); break; case (2): - num = *(unsigned int *) ic->parm.num; - csta->channel[0].lc_b->delay = num; - csta->channel[1].lc_b->delay = num; - sprintf(tmp, "delay card %d set to %d ms\n", + num = *(unsigned int *) ic->parm.num; + csta->channel[0].b_st->l1.delay = num; + csta->channel[1].b_st->l1.delay = num; + HiSax_putstatus(csta, "delay ", "card %d set to %d ms", + csta->cardnr + 1, num); + printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n", csta->cardnr + 1, num); - HiSax_putstatus(csta, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; case (3): for (i = 0; i < *(unsigned int *) ic->parm.num; i++) @@ -2106,54 +1695,141 @@ case (5): /* set card in leased mode */ num = *(unsigned int *) ic->parm.num; if ((num <1) || (num > 2)) { - sprintf(tmp, "Set LEASED wrong channel %d\n", + HiSax_putstatus(csta, "Set LEASED ", + "wrong channel %d", num); + printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n", num); - HiSax_putstatus(csta, tmp); - printk(KERN_WARNING "HiSax: %s", tmp); } else { num--; - csta->channel[num].leased = 1; - csta->channel[num].lc_d->l2_establish = 0; - sprintf(tmp, "card %d channel %d set leased mode\n", + chanp = csta->channel +num; + chanp->leased = 1; + HiSax_putstatus(csta, "Card", + "%d channel %d set leased mode\n", csta->cardnr + 1, num + 1); - HiSax_putstatus(csta, tmp); - FsmEvent(&csta->channel[num].lc_d->lcfi, EV_LC_ESTABLISH, NULL); + chanp->d_st->l1.l1l2 = leased_l1l2; + chanp->d_st->lli.l4l3 = leased_l4l3; + chanp->d_st->lli.l4l3(chanp->d_st, + DL_ESTABLISH | REQUEST, NULL); } break; case (6): /* set B-channel test loop */ num = *(unsigned int *) ic->parm.num; if (csta->stlist) - csta->stlist->ma.manl1(csta->stlist, - PH_TESTLOOP_REQ, (void *) num); + csta->stlist->l2.l2l1(csta->stlist, + PH_TESTLOOP | REQUEST, (void *) (long)num); + break; + case (7): /* set card in PTP mode */ + num = *(unsigned int *) ic->parm.num; + if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { + printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n"); + } else if (num) { + test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); + test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); + csta->channel[0].d_st->l2.tei = 0; + HiSax_putstatus(csta, "set card ", "in PTP mode"); + printk(KERN_DEBUG "HiSax: set card in PTP mode\n"); + printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); + csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st, + DL_ESTABLISH | REQUEST, NULL); + } else { + test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); + test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); + HiSax_putstatus(csta, "set card ", "in PTMP mode"); + printk(KERN_DEBUG "HiSax: set card in PTMP mode\n"); + } + break; + case (8): /* set card in FIXED TEI mode */ + num = *(unsigned int *) ic->parm.num; + chanp = csta->channel + (num & 1); + num = num >>1; + test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); + chanp->d_st->l2.tei = num; + HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); + printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", + num); + break; + case (9): /* load firmware */ + memcpy(&adr, ic->parm.num, sizeof(ulong)); + csta->cardmsg(csta, CARD_LOAD_FIRM, + (void *) adr); break; #ifdef MODULE case (55): - while ( MOD_USE_COUNT > 0) - MOD_DEC_USE_COUNT; + MOD_USE_COUNT = 0; HiSax_mod_inc_use_count(); break; #endif /* MODULE */ case (11): + num = csta->debug & DEB_DLOG_HEX; csta->debug = *(unsigned int *) ic->parm.num; - sprintf(tmp, "l1 debugging flags card %d set to %x\n", + csta->debug |= num; + HiSax_putstatus(cards[0].cs, "l1 debugging ", + "flags card %d set to %x", + csta->cardnr + 1, csta->debug); + printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n", csta->cardnr + 1, csta->debug); - HiSax_putstatus(cards[0].cs, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; case (13): csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num; csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num; - sprintf(tmp, "l3 debugging flags card %d set to %x\n", + HiSax_putstatus(cards[0].cs, "l3 debugging ", + "flags card %d set to %x\n", csta->cardnr + 1, + *(unsigned int *) ic->parm.num); + printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", csta->cardnr + 1, *(unsigned int *) ic->parm.num); - HiSax_putstatus(cards[0].cs, tmp); - printk(KERN_DEBUG "HiSax: %s", tmp); break; + case (10): + i = *(unsigned int *) ic->parm.num; + if ((i < 0) || (i > 2)) + return(-EINVAL); /* invalid number */ + return(set_channel_limit(csta, i)); + break; + case (12): + i = *(unsigned int *) ic->parm.num; +#ifdef CONFIG_HISAX_HFC_PCI + if (csta->typ != ISDN_CTYPE_HFC_PCI) + return(-EINVAL); + return(hfcpci_set_echo(csta,i)); +#else + return(-EINVAL); +#endif + break; default: printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", (int) ic->arg); return (-EINVAL); } break; + + case (ISDN_CMD_PROCEED): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) + link_debug(chanp, 1, "PROCEED"); + FsmEvent(&chanp->fi, EV_PROCEED, NULL); + break; + + case (ISDN_CMD_ALERT): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) + link_debug(chanp, 1, "ALERT"); + FsmEvent(&chanp->fi, EV_ALERT, NULL); + break; + + case (ISDN_CMD_REDIR): + chanp = csta->channel + ic->arg; + if (chanp->debug & 1) + link_debug(chanp, 1, "REDIR"); + chanp->setup = ic->parm.setup; + FsmEvent(&chanp->fi, EV_REDIR, NULL); + break; + + /* protocol specific io commands */ + case (ISDN_CMD_PROT_IO): + for (st = csta->stlist; st; st = st->next) + if (st->protocol == (ic->arg & 0xFF)) + return(st->lli.l4l3_proto(st, ic)); + return(-EINVAL); + break; default: break; } @@ -2170,7 +1846,6 @@ int len = skb->len; unsigned long flags; struct sk_buff *nskb; - char tmp[64]; if (!csta) { printk(KERN_ERR @@ -2180,13 +1855,13 @@ chanp = csta->channel + chan; st = chanp->b_st; if (!chanp->data_open) { - link_debug(chanp, "writebuf: channel not open", 1); + link_debug(chanp, 1, "writebuf: channel not open"); return -EIO; } if (len > MAX_DATA_SIZE) { - sprintf(tmp, "writebuf: packet too large (%d bytes)", len); - printk(KERN_WARNING "HiSax_%s !\n", tmp); - link_debug(chanp, tmp, 1); + link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len); + printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n", + len); return -EINVAL; } if (len) { @@ -2194,25 +1869,24 @@ /* Must return 0 here, since this is not an error * but a temporary lack of resources. */ - if (chanp->debug & 0x800) { - sprintf(tmp, "writebuf: no buffers for %d bytes", len); - link_debug(chanp, tmp, 1); - } + if (chanp->debug & 0x800) + link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len); return 0; - } + } else if (chanp->debug & 0x800) + link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM); save_flags(flags); cli(); nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { if (!ack) nskb->pkt_type = PACKET_NOACK; - if (chanp->lc_b->l2_establish) - st->l3.l3l2(st, DL_DATA, nskb); + if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I) + st->l3.l3l2(st, DL_DATA | REQUEST, nskb); else { chanp->bcs->tx_cnt += len; - st->l2.l2l1(st, PH_DATA_REQ, nskb); + st->l2.l2l1(st, PH_DATA | REQUEST, nskb); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_WRITE); } else len = 0; restore_flags(flags); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c --- v2.2.10/linux/drivers/isdn/hisax/cert.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/cert.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,55 @@ +/* $Id: cert.c,v 2.1 1998/11/15 23:51:15 keil Exp $ + + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * + * $Log: cert.c,v $ + * Revision 2.1 1998/11/15 23:51:15 keil + * certification stuff + * + * Revision 1.2.2.1 1998/11/03 21:46:37 keil + * first version + * + * + */ + +#include + +int +certification_check(int output) { + +#ifdef CERTIFICATION +#if CERTIFICATION == 0 + if (output) { + printk(KERN_INFO "HiSax: Approval certification valid\n"); + printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n"); + printk(KERN_INFO "HiSax: Approval registration numbers:\n"); + printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n"); + printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n"); + } + return(0); +#endif +#if CERTIFICATION == 1 + if (output) { + printk(KERN_INFO "HiSax: Approval certification failed because of\n"); + printk(KERN_INFO "HiSax: unauthorized source code changes\n"); + } + return(1); +#endif +#if CERTIFICATION == 127 + if (output) { + printk(KERN_INFO "HiSax: Approval certification not possible\n"); + printk(KERN_INFO "HiSax: because \"md5sum\" is not available\n"); + } + return(2); +#endif +#else + if (output) { + printk(KERN_INFO "HiSax: Certification not verified\n"); + } + return(3); +#endif +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.2.10/linux/drivers/isdn/hisax/config.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/config.c Mon Aug 9 12:04:39 1999 @@ -1,10 +1,67 @@ -/* $Id: config.c,v 2.12 1998/02/11 17:28:02 keil Exp $ +/* $Id: config.c,v 2.28 1999/07/14 12:38:36 werner Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.28 1999/07/14 12:38:36 werner + * Added changes for echo channel handling + * + * Revision 2.27 1999/07/12 21:05:00 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.26 1999/07/08 21:27:17 keil + * version 3.2 + * + * Revision 2.25 1999/07/05 23:51:44 werner + * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl + * hisaxctrl id 10 + * + * Revision 2.24 1999/07/01 08:11:26 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.23 1999/02/17 10:53:02 cpetig + * Added Hisax_closecard to exported symbols. + * As indicated by Oliver Schoett . + * + * If anyone is annoyed by exporting symbols deep inside the code, please + * contact me. + * + * Revision 2.22 1999/02/04 21:41:53 keil + * Fix printk msg + * + * Revision 2.21 1999/02/04 10:48:52 keil + * Fix readstat bug + * + * Revision 2.20 1998/11/15 23:54:28 keil + * changes from 2.0 + * + * Revision 2.19 1998/08/13 23:36:18 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.18 1998/07/30 21:01:37 niemann + * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new + * + * Revision 2.17 1998/07/15 15:01:26 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.16 1998/05/25 14:10:03 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.15 1998/05/25 12:57:43 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.14 1998/04/15 16:38:25 keil + * Add S0Box and Teles PCI support + * + * Revision 2.13 1998/03/09 23:19:23 keil + * Changes for PCMCIA + * * Revision 2.12 1998/02/11 17:28:02 keil * Niccy PnP/PCI support * @@ -55,6 +112,12 @@ #include #include #include "hisax.h" +#include +#include +#include +#include +#define HISAX_STATUS_BUFSIZE 4096 +#define INCLUDE_INLINE_FUNCS /* * This structure array contains one entry per card. An entry looks @@ -78,42 +141,107 @@ * 13 Teleint p0=irq p1=iobase * 14 Teles 16.3c p0=irq p1=iobase * 15 Sedlbauer speed p0=irq p1=iobase + * 15 Sedlbauer PC/104 p0=irq p1=iobase + * 15 Sedlbauer speed pci no parameter * 16 USR Sportster internal p0=irq p1=iobase * 17 MIC card p0=irq p1=iobase * 18 ELSA Quickstep 1000PCI no parameter * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 * 20 Travers Technologies NETjet PCI card - * 21 reserved TELES PCI + * 21 TELES PCI no parameter * 22 Sedlbauer Speed Star p0=irq p1=iobase * 23 reserved * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only) - * - * + * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup) + * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase + * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter) + * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup) + * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup) + * 30 ACER P10 p0=irq p1=iobase (from isapnp setup) + * 31 HST Saphir p0=irq p1=iobase + * 32 Telekom A4T none + * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4) + * 34 Gazel ISDN cards + * 35 HFC 2BDS0 PCI none * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 * * */ +const char *CardType[] = +{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP", + "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", + "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", + "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", + "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", + "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", + "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", + "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", +}; + +void HiSax_closecard(int cardnr); + #ifdef CONFIG_HISAX_ELSA #define DEFAULT_CARD ISDN_CTYPE_ELSA #define DEFAULT_CFG {0,0,0,0} -#ifdef MODULE int elsa_init_pcmcia(void*, int, int*, int); +#ifdef COMPAT_HAS_NEW_SYMTAB EXPORT_SYMBOL(elsa_init_pcmcia); -#endif -#endif +#else +static struct symbol_table hisax_syms_elsa = { +#include + X(elsa_init_pcmcia), +#include +}; +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* CONFIG_HISAX_ELSA */ + #ifdef CONFIG_HISAX_AVM_A1 #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_A1 #define DEFAULT_CFG {10,0x340,0,0} #endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA +#define DEFAULT_CFG {11,0x170,0,0} +int avm_a1_init_pcmcia(void*, int, int*, int); +#ifdef COMPAT_HAS_NEW_SYMTAB +EXPORT_SYMBOL(avm_a1_init_pcmcia); +#else +static struct symbol_table hisax_syms_avm_a1= { +#include + X(avm_a1_init_pcmcia), + X(HiSax_closecard), +#include +}; +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ + +#ifdef CONFIG_HISAX_FRITZPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_16_3 #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_16_3 #define DEFAULT_CFG {15,0x180,0,0} #endif + +#ifdef CONFIG_HISAX_S0BOX +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_S0BOX +#define DEFAULT_CFG {7,0x378,0,0} +#endif + #ifdef CONFIG_HISAX_16_0 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -121,6 +249,13 @@ #define DEFAULT_CFG {15,0xd0000,0xd80,0} #endif +#ifdef CONFIG_HISAX_TELESPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_TELESPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + #ifdef CONFIG_HISAX_IX1MICROR2 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -155,8 +290,16 @@ #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER #define DEFAULT_CFG {11,0x270,0,0} int sedl_init_pcmcia(void*, int, int*, int); +#ifdef COMPAT_HAS_NEW_SYMTAB EXPORT_SYMBOL(sedl_init_pcmcia); -#endif +#else +static struct symbol_table hisax_syms_sedl= { +#include + X(sedl_init_pcmcia), +#include +}; +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* CONFIG_HISAX_SEDLBAUER */ #ifdef CONFIG_HISAX_SPORTSTER #undef DEFAULT_CARD @@ -179,13 +322,21 @@ #define DEFAULT_CFG {0,0,0,0} #endif -#ifdef CONFIG_HISAX_TELES3C +#ifdef CONFIG_HISAX_HFCS #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_TELES3C #define DEFAULT_CFG {5,0x500,0,0} #endif +#ifdef CONFIG_HISAX_HFC_PCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI +#define DEFAULT_CFG {0,0,0,0} +#endif + + #ifdef CONFIG_HISAX_AMD7930 #undef DEFAULT_CARD #undef DEFAULT_CFG @@ -193,20 +344,48 @@ #define DEFAULT_CFG {12,0x3e0,0,0} #endif -#ifdef CONFIG_HISAX_DBRI +#ifdef CONFIG_HISAX_NICCY #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_DBRI +#define DEFAULT_CARD ISDN_CTYPE_NICCY #define DEFAULT_CFG {0,0x0,0,0} #endif -#ifdef CONFIG_HISAX_NICCY +#ifdef CONFIG_HISAX_ISURF #undef DEFAULT_CARD #undef DEFAULT_CFG -#define DEFAULT_CARD ISDN_CTYPE_NICCY +#define DEFAULT_CARD ISDN_CTYPE_ISURF +#define DEFAULT_CFG {5,0x100,0xc8000,0} +#endif + +#ifdef CONFIG_HISAX_HSTSAPHIR +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR +#define DEFAULT_CFG {5,0x250,0,0} +#endif + +#ifdef CONFIG_HISAX_BKM_A4T +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T #define DEFAULT_CFG {0,0x0,0,0} #endif +#ifdef CONFIG_HISAX_SCT_QUADRO +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO +#define DEFAULT_CFG {1,0x0,0,0} +#endif + +#ifdef CONFIG_HISAX_GAZEL +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_GAZEL +#define DEFAULT_CFG {15,0x180,0,0} +#endif + #ifdef CONFIG_HISAX_1TR6 #define DEFAULT_PROTO ISDN_PTYPE_1TR6 #define DEFAULT_PROTO_NAME "1TR6" @@ -232,10 +411,10 @@ #endif #define FIRST_CARD { \ - DEFAULT_CARD, \ - DEFAULT_PROTO, \ - DEFAULT_CFG, \ - NULL, \ + DEFAULT_CARD, \ + DEFAULT_PROTO, \ + DEFAULT_CFG, \ + NULL, \ } #define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL} @@ -250,29 +429,20 @@ EMPTY_CARD, EMPTY_CARD, EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, - EMPTY_CARD, }; -static char HiSaxID[96] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ +static char HiSaxID[64] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \ -"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; char *HiSax_id HISAX_INITDATA = HiSaxID; #ifdef MODULE /* Variables for insmod */ static int type[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int protocol[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int io[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; #undef IO0_IO1 #ifdef CONFIG_HISAX_16_3 #define IO0_IO1 @@ -283,29 +453,30 @@ #endif #ifdef IO0_IO1 static int io0[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int io1[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; #endif static int irq[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static int mem[] HISAX_INITDATA = -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +{0, 0, 0, 0, 0, 0, 0, 0}; static char *id HISAX_INITDATA = HiSaxID; +#ifdef COMPAT_HAS_NEW_SYMTAB MODULE_AUTHOR("Karsten Keil"); -MODULE_PARM(type, "1-3i"); -MODULE_PARM(protocol, "1-2i"); +MODULE_PARM(type, "1-8i"); +MODULE_PARM(protocol, "1-8i"); MODULE_PARM(io, "1-8i"); -MODULE_PARM(irq, "1-2i"); -MODULE_PARM(mem, "1-12i"); +MODULE_PARM(irq, "1-8i"); +MODULE_PARM(mem, "1-8i"); MODULE_PARM(id, "s"); #ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ MODULE_PARM(io0, "1-8i"); MODULE_PARM(io1, "1-8i"); -#endif - -#endif +#endif /* CONFIG_HISAX_16_3 */ +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* MODULE */ int nrcards; @@ -333,23 +504,25 @@ HISAX_INITFUNC(void HiSaxVersion(void)) { - char tmp[64], rev[64]; - char *r = rev; + char tmp[64]; + printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); +#ifdef MODULE + printk(KERN_INFO "HiSax: Version 3.2a (module)\n"); +#else + printk(KERN_INFO "HiSax: Version 3.2a (kernel)\n"); +#endif strcpy(tmp, l1_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, l2_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, tei_revision); + printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, l3_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, lli_revision); - r += sprintf(r, "%s/", HiSax_getrev(tmp)); - strcpy(tmp, tei_revision); - r += sprintf(r, "%s", HiSax_getrev(tmp)); - - printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n"); - printk(KERN_INFO "HiSax: Version 2.8\n"); - printk(KERN_INFO "HiSax: Revisions %s\n", rev); + printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp)); + certification_check(1); } void @@ -375,7 +548,7 @@ argc = ints[0]; i = 0; j = 1; - while (argc && (i < 16)) { + while (argc && (i < HISAX_MAX_CARDS)) { if (argc) { cards[i].typ = ints[j]; j++; @@ -413,32 +586,864 @@ } #endif +#if CARD_TELES0 +extern int setup_teles0(struct IsdnCard *card); +#endif + +#if CARD_TELES3 +extern int setup_teles3(struct IsdnCard *card); +#endif + +#if CARD_S0BOX +extern int setup_s0box(struct IsdnCard *card); +#endif + +#if CARD_TELESPCI +extern int setup_telespci(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1 +extern int setup_avm_a1(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1_PCMCIA +extern int setup_avm_a1_pcmcia(struct IsdnCard *card); +#endif + +#if CARD_FRITZPCI +extern int setup_avm_pcipnp(struct IsdnCard *card); +#endif + +#if CARD_ELSA +extern int setup_elsa(struct IsdnCard *card); +#endif + +#if CARD_IX1MICROR2 +extern int setup_ix1micro(struct IsdnCard *card); +#endif + +#if CARD_DIEHLDIVA +extern int setup_diva(struct IsdnCard *card); +#endif + +#if CARD_ASUSCOM +extern int setup_asuscom(struct IsdnCard *card); +#endif + +#if CARD_TELEINT +extern int setup_TeleInt(struct IsdnCard *card); +#endif + +#if CARD_SEDLBAUER +extern int setup_sedlbauer(struct IsdnCard *card); +#endif + +#if CARD_SPORTSTER +extern int setup_sportster(struct IsdnCard *card); +#endif + +#if CARD_MIC +extern int setup_mic(struct IsdnCard *card); +#endif + +#if CARD_NETJET +extern int setup_netjet(struct IsdnCard *card); +#endif + +#if CARD_HFCS +extern int setup_hfcs(struct IsdnCard *card); +#endif + +#if CARD_HFC_PCI +extern int setup_hfcpci(struct IsdnCard *card); +#endif + +#if CARD_AMD7930 +extern int setup_amd7930(struct IsdnCard *card); +#endif + +#if CARD_NICCY +extern int setup_niccy(struct IsdnCard *card); +#endif + +#if CARD_ISURF +extern int setup_isurf(struct IsdnCard *card); +#endif + +#if CARD_HSTSAPHIR +extern int setup_saphir(struct IsdnCard *card); +#endif + +#if CARD_TESTEMU +extern int setup_testemu(struct IsdnCard *card); +#endif + +#if CARD_BKM_A4T +extern int setup_bkm_a4t(struct IsdnCard *card); +#endif + +#if CARD_SCT_QUADRO +extern int setup_sct_quadro(struct IsdnCard *card); +#endif + +#if CARD_GAZEL +extern int setup_gazel(struct IsdnCard *card); +#endif + +/* + * Find card with given driverId + */ +static inline struct IsdnCardState +*hisax_findcard(int driverid) +{ + int i; + + for (i = 0; i < nrcards; i++) + if (cards[i].cs) + if (cards[i].cs->myid == driverid) + return (cards[i].cs); + return (NULL); +} + +/* + * Find card with given card number + */ +struct IsdnCardState +*hisax_get_card(int cardnr) +{ + if ((cardnr <= nrcards) && (cardnr>0)) + if (cards[cardnr-1].cs) + return (cards[cardnr-1].cs); + return (NULL); +} + +int +HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) +{ + int count,cnt; + u_char *p = buf; + struct IsdnCardState *cs = hisax_findcard(id); + + if (cs) { + if (len > HISAX_STATUS_BUFSIZE) { + printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + } + count = cs->status_end - cs->status_read +1; + if (count >= len) + count = len; + if (user) + copy_to_user(p, cs->status_read, count); + else + memcpy(p, cs->status_read, count); + cs->status_read += count; + if (cs->status_read > cs->status_end) + cs->status_read = cs->status_buf; + p += count; + count = len - count; + while (count) { + if (count > HISAX_STATUS_BUFSIZE) + cnt = HISAX_STATUS_BUFSIZE; + else + cnt = count; + if (user) + copy_to_user(p, cs->status_read, cnt); + else + memcpy(p, cs->status_read, cnt); + p += cnt; + cs->status_read += cnt % HISAX_STATUS_BUFSIZE; + count -= cnt; + } + return len; + } else { + printk(KERN_ERR + "HiSax: if_readstatus called with invalid driverId!\n"); + return -ENODEV; + } +} + +inline int +jiftime(char *s, long mark) +{ + s += 8; + + *s-- = '\0'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = '.'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 6 + '0'; + mark /= 6; + *s-- = ':'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + return(8); +} + +static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; + +void +VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) +{ +/* if head == NULL the fmt contains the full info */ + + long flags; + int count, i; + u_char *p; + isdn_ctrl ic; + int len; + + save_flags(flags); + cli(); + p = tmpbuf; + if (head) { + p += jiftime(p, jiffies); + p += sprintf(p, " %s", head); + p += vsprintf(p, fmt, args); + *p++ = '\n'; + *p = 0; + len = p - tmpbuf; + p = tmpbuf; + } else { + p = fmt; + len = strlen(fmt); + } + if (!cs) { + printk(KERN_WARNING "HiSax: No CardStatus for message %s", p); + restore_flags(flags); + return; + } + if (len > HISAX_STATUS_BUFSIZE) { + printk(KERN_WARNING "HiSax: status overflow %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + restore_flags(flags); + return; + } + count = len; + i = cs->status_end - cs->status_write +1; + if (i >= len) + i = len; + len -= i; + memcpy(cs->status_write, p, i); + cs->status_write += i; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + p += i; + if (len) { + memcpy(cs->status_write, p, len); + cs->status_write += len; + } +#ifdef KERNELSTACK_DEBUG + i = (ulong)&len - current->kernel_stack_page; + sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm, + current->kernel_stack_page, i); + len = strlen(tmpbuf); + for (p = tmpbuf, i = len; i > 0; i--, p++) { + *cs->status_write++ = *p; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + count++; + } +#endif + restore_flags(flags); + if (count) { + ic.command = ISDN_STAT_STAVAIL; + ic.driver = cs->myid; + ic.arg = count; + cs->iif.statcallb(&ic); + } +} + +void +HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + VHiSax_putstatus(cs, head, fmt, args); + va_end(args); +} + +int +ll_run(struct IsdnCardState *cs) +{ + long flags; + isdn_ctrl ic; + + save_flags(flags); + cli(); + ic.driver = cs->myid; + ic.command = ISDN_STAT_RUN; + cs->iif.statcallb(&ic); + restore_flags(flags); + return 0; +} + +void +ll_stop(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_STOP; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + CallcFreeChan(cs); +} + +static void +ll_unload(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_UNLOAD; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + if (cs->status_buf) + kfree(cs->status_buf); + cs->status_read = NULL; + cs->status_write = NULL; + cs->status_end = NULL; + kfree(cs->dlog); +} + +static void +closecard(int cardnr) +{ + struct IsdnCardState *csta = cards[cardnr].cs; + + if (csta->bcs->BC_Close != NULL) { + csta->bcs->BC_Close(csta->bcs + 1); + csta->bcs->BC_Close(csta->bcs); + } + + discard_queue(&csta->rq); + discard_queue(&csta->sq); + if (csta->rcvbuf) { + kfree(csta->rcvbuf); + csta->rcvbuf = NULL; + } + if (csta->tx_skb) { + idev_kfree_skb(csta->tx_skb, FREE_WRITE); + csta->tx_skb = NULL; + } + if (csta->DC_Close != NULL) { + csta->DC_Close(csta); + } + csta->cardmsg(csta, CARD_RELEASE, NULL); + if (csta->dbusytimer.function != NULL) + del_timer(&csta->dbusytimer); + ll_unload(csta); +} + +HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) +{ + int irq_cnt, cnt = 3; + long flags; + + if (!cs->irq) + return(cs->cardmsg(cs, CARD_INIT, NULL)); + save_flags(flags); + cli(); + irq_cnt = kstat_irqs(cs->irq); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, + irq_cnt); + if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) { + printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", + cs->irq); + restore_flags(flags); + return(1); + } + while (cnt) { + cs->cardmsg(cs, CARD_INIT, NULL); + sti(); + current->state = TASK_INTERRUPTIBLE; + /* Timeout 10ms */ + schedule_timeout((10*HZ)/1000); + restore_flags(flags); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], + cs->irq, kstat_irqs(cs->irq)); + if (kstat_irqs(cs->irq) == irq_cnt) { + printk(KERN_WARNING + "%s: IRQ(%d) getting no interrupts during init %d\n", + CardType[cs->typ], cs->irq, 4 - cnt); + if (cnt == 1) { + free_irq(cs->irq, cs); + return (2); + } else { + cs->cardmsg(cs, CARD_RESET, NULL); + cnt--; + } + } else { + cs->cardmsg(cs, CARD_TEST, NULL); + return(0); + } + } + restore_flags(flags); + return(3); +} + +HISAX_INITFUNC(static int +checkcard(int cardnr, char *id, int *busy_flag)) +{ + long flags; + int ret = 0; + struct IsdnCard *card = cards + cardnr; + struct IsdnCardState *cs; + + save_flags(flags); + cli(); + if (!(cs = (struct IsdnCardState *) + kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for IsdnCardState(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + memset(cs, 0, sizeof(struct IsdnCardState)); + card->cs = cs; + cs->chanlimit = 2; /* maximum B-channel number */ + cs->logecho = 0; /* No echo logging */ + cs->cardnr = cardnr; + cs->debug = L1_DEB_WARN; + cs->HW_Flags = 0; + cs->busy_flag = busy_flag; + cs->irq_flags = I4L_IRQ_FLAG; +#if TEI_PER_CARD +#else + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#endif + cs->protocol = card->protocol; + + if ((card->typ > 0) && (card->typ <= ISDN_CTYPE_COUNT)) { + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", + cardnr + 1); + restore_flags(flags); + return (0); + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + kfree(cs->dlog); + restore_flags(flags); + return (0); + } + cs->stlist = NULL; + cs->status_read = cs->status_buf; + cs->status_write = cs->status_buf; + cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; + cs->typ = card->typ; + strcpy(cs->iif.id, id); + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | +// ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | +#ifdef CONFIG_HISAX_1TR6 + ISDN_FEATURE_P_1TR6 | +#endif +#ifdef CONFIG_HISAX_EURO + ISDN_FEATURE_P_EURO | +#endif +#ifdef CONFIG_HISAX_NI1 + ISDN_FEATURE_P_NI1 | +#endif + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); + switch (card->typ) { +#if CARD_TELES0 + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = setup_teles0(card); + break; +#endif +#if CARD_TELES3 + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_COMPAQ_ISA: + ret = setup_teles3(card); + break; +#endif +#if CARD_S0BOX + case ISDN_CTYPE_S0BOX: + ret = setup_s0box(card); + break; +#endif +#if CARD_TELESPCI + case ISDN_CTYPE_TELESPCI: + ret = setup_telespci(card); + break; +#endif +#if CARD_AVM_A1 + case ISDN_CTYPE_A1: + ret = setup_avm_a1(card); + break; +#endif +#if CARD_AVM_A1_PCMCIA + case ISDN_CTYPE_A1_PCMCIA: + ret = setup_avm_a1_pcmcia(card); + break; +#endif +#if CARD_FRITZPCI + case ISDN_CTYPE_FRITZPCI: + ret = setup_avm_pcipnp(card); + break; +#endif +#if CARD_ELSA + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_ELSA_PCI: + ret = setup_elsa(card); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; +#endif +#if CARD_DIEHLDIVA + case ISDN_CTYPE_DIEHLDIVA: + ret = setup_diva(card); + break; +#endif +#if CARD_ASUSCOM + case ISDN_CTYPE_ASUSCOM: + ret = setup_asuscom(card); + break; +#endif +#if CARD_TELEINT + case ISDN_CTYPE_TELEINT: + ret = setup_TeleInt(card); + break; +#endif +#if CARD_SEDLBAUER + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + ret = setup_sedlbauer(card); + break; +#endif +#if CARD_SPORTSTER + case ISDN_CTYPE_SPORTSTER: + ret = setup_sportster(card); + break; +#endif +#if CARD_MIC + case ISDN_CTYPE_MIC: + ret = setup_mic(card); + break; +#endif +#if CARD_NETJET + case ISDN_CTYPE_NETJET: + ret = setup_netjet(card); + break; +#endif +#if CARD_HFCS + case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + ret = setup_hfcs(card); + break; +#endif +#if CARD_HFC_PCI + case ISDN_CTYPE_HFC_PCI: + ret = setup_hfcpci(card); + break; +#endif +#if CARD_NICCY + case ISDN_CTYPE_NICCY: + ret = setup_niccy(card); + break; +#endif +#if CARD_AMD7930 + case ISDN_CTYPE_AMD7930: + ret = setup_amd7930(card); + break; +#endif +#if CARD_ISURF + case ISDN_CTYPE_ISURF: + ret = setup_isurf(card); + break; +#endif +#if CARD_HSTSAPHIR + case ISDN_CTYPE_HSTSAPHIR: + ret = setup_saphir(card); + break; +#endif +#if CARD_TESTEMU + case ISDN_CTYPE_TESTEMU: + ret = setup_testemu(card); + break; +#endif +#if CARD_BKM_A4T + case ISDN_CTYPE_BKM_A4T: + ret = setup_bkm_a4t(card); + break; +#endif +#if CARD_SCT_QUADRO + case ISDN_CTYPE_SCT_QUADRO: + ret = setup_sct_quadro(card); + break; +#endif +#if CARD_GAZEL + case ISDN_CTYPE_GAZEL: + ret = setup_gazel(card); + break; +#endif + default: + printk(KERN_WARNING + "HiSax: Support for %s Card not selected\n", + CardType[card->typ]); + ll_unload(cs); + restore_flags(flags); + return (0); + } + } else { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", + card->typ); + restore_flags(flags); + return (0); + } + if (!ret) { + ll_unload(cs); + restore_flags(flags); + return (0); + } + if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for isac rcvbuf\n"); + return (1); + } + cs->rcvidx = 0; + cs->tx_skb = NULL; + cs->tx_cnt = 0; + cs->event = 0; + cs->tqueue.next = 0; + cs->tqueue.sync = 0; + cs->tqueue.data = cs; + + skb_queue_head_init(&cs->rq); + skb_queue_head_init(&cs->sq); + + init_bcstate(cs, 0); + init_bcstate(cs, 1); + ret = init_card(cs); + if (ret) { + closecard(cardnr); + restore_flags(flags); + return (0); + } + init_tei(cs, cs->protocol); + CallcNewChan(cs); + /* ISAR needs firmware download first */ + if (!test_bit(HW_ISAR, &cs->HW_Flags)) + ll_run(cs); + restore_flags(flags); + return (1); +} + +HISAX_INITFUNC(void +HiSax_shiftcards(int idx)) +{ + int i; + + for (i = idx; i < (HISAX_MAX_CARDS - 1); i++) + memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); +} + +HISAX_INITFUNC(int +HiSax_inithardware(int *busy_flag)) +{ + int foundcards = 0; + int i = 0; + int t = ','; + int flg = 0; + char *id; + char *next_id = HiSax_id; + char ids[20]; + + if (strchr(HiSax_id, ',')) + t = ','; + else if (strchr(HiSax_id, '%')) + t = '%'; + + while (i < nrcards) { + if (cards[i].typ < 1) + break; + id = next_id; + if ((next_id = strchr(id, t))) { + *next_id++ = 0; + strcpy(ids, id); + flg = i + 1; + } else { + next_id = id; + if (flg >= i) + strcpy(ids, id); + else + sprintf(ids, "%s%d", id, i); + } + if (checkcard(i, ids, busy_flag)) { + foundcards++; + i++; + } else { + printk(KERN_WARNING "HiSax: Card %s not installed !\n", + CardType[cards[i].typ]); + if (cards[i].cs) + kfree((void *) cards[i].cs); + cards[i].cs = NULL; + HiSax_shiftcards(i); + } + } + return foundcards; +} + +void +HiSax_closecard(int cardnr) +{ + int i,last=nrcards - 1; + + if (cardnr>last) + return; + if (cards[cardnr].cs) { + ll_stop(cards[cardnr].cs); + release_tei(cards[cardnr].cs); + closecard(cardnr); + if (cards[cardnr].cs->irq) + free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); + kfree((void *) cards[cardnr].cs); + cards[cardnr].cs = NULL; + } + i = cardnr; + while (i!=last) { + cards[i] = cards[i+1]; + i++; + } + nrcards--; +} + +void +HiSax_reportcard(int cardnr) +{ + struct IsdnCardState *cs = cards[cardnr].cs; + struct PStack *stptr; + struct l3_process *pc; + int j, i = 1; + + printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); + printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); + printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); + printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", + (ulong) & HiSax_reportcard); + printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); + printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc0 flg %x\n", + cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); + printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", + cs->bcs[0].mode, cs->bcs[0].channel); + printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n", + cs->bcs[1].mode, cs->bcs[1].channel); + printk(KERN_DEBUG "HiSax: cs setstack_d 0x%lX\n", (ulong) cs->setstack_d); + printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist)); + stptr = cs->stlist; + while (stptr != NULL) { + printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr); + printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp); + printk(KERN_DEBUG "HiSax: dst%d l1.l1hw 0x%lX\n", i, (ulong) stptr->l1.l1hw); + printk(KERN_DEBUG "HiSax: tei %d sapi %d\n", + stptr->l2.tei, stptr->l2.sap); + printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); + pc = stptr->l3.proc; + while (pc) { + printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref, + (ulong) pc); + printk(KERN_DEBUG "HiSax: state %d st 0x%lX chan 0x%lX\n", + pc->state, (ulong) pc->st, (ulong) pc->chan); + pc = pc->next; + } + stptr = stptr->next; + i++; + } + for (j = 0; j < 2; j++) { + printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j, + (ulong) & cs->channel[j]); + stptr = cs->channel[j].b_st; + i = 1; + while (stptr != NULL) { + printk(KERN_DEBUG "HiSax: b_st%d 0x%lX\n", i, (ulong) stptr); + printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); + stptr = stptr->next; + i++; + } + } +} + + __initfunc(int HiSax_init(void)) { int i; - + #ifdef MODULE int nzproto = 0; #ifdef CONFIG_HISAX_ELSA if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { /* we have exported and return in this case */ +#ifndef COMPAT_HAS_NEW_SYMTAB + register_symtab(&hisax_syms_elsa); +#endif return 0; } #endif #ifdef CONFIG_HISAX_SEDLBAUER if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) { /* we have to export and return in this case */ +#ifndef COMPAT_HAS_NEW_SYMTAB + register_symtab(&hisax_syms_sedl); +#endif + return 0; + } +#endif +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA + if (type[0] == ISDN_CTYPE_A1_PCMCIA) { + /* we have to export and return in this case */ +#ifndef COMPAT_HAS_NEW_SYMTAB + register_symtab(&hisax_syms_avm_a1); +#endif return 0; } #endif #endif - HiSaxVersion(); nrcards = 0; + HiSaxVersion(); #ifdef MODULE if (id) /* If id= string used */ HiSax_id = id; - for (i = 0; i < 16; i++) { + for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].typ = type[i]; if (protocol[i]) { cards[i].protocol = protocol[i]; @@ -476,6 +1481,7 @@ case ISDN_CTYPE_16_3: case ISDN_CTYPE_TELESPCMCIA: case ISDN_CTYPE_A1: + case ISDN_CTYPE_A1_PCMCIA: case ISDN_CTYPE_ELSA_PNP: case ISDN_CTYPE_ELSA_PCMCIA: case ISDN_CTYPE_IX1MICROR2: @@ -484,16 +1490,32 @@ case ISDN_CTYPE_TELEINT: case ISDN_CTYPE_SEDLBAUER: case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: case ISDN_CTYPE_SPORTSTER: case ISDN_CTYPE_MIC: case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + case ISDN_CTYPE_S0BOX: + case ISDN_CTYPE_FRITZPCI: + case ISDN_CTYPE_HSTSAPHIR: + case ISDN_CTYPE_GAZEL: + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + break; + case ISDN_CTYPE_ISURF: cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; + cards[i].para[2] = mem[i]; break; case ISDN_CTYPE_ELSA_PCI: case ISDN_CTYPE_NETJET: case ISDN_CTYPE_AMD7930: - case ISDN_CTYPE_DBRI: + case ISDN_CTYPE_TELESPCI: + break; + case ISDN_CTYPE_BKM_A4T: + break; + case ISDN_CTYPE_SCT_QUADRO: + cards[i].para[0] = irq[i]; break; } } @@ -507,29 +1529,32 @@ HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", nrcards, (nrcards > 1) ? "s" : ""); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); Isdnl1New(); if (HiSax_inithardware(NULL)) { /* Install only, if at least one card found */ - /* No symbols to export, hide all symbols */ - #ifdef MODULE - EXPORT_NO_SYMBOLS; +#ifndef COMPAT_HAS_NEW_SYMTAB + /* No symbols to export, hide all symbols */ + register_symtab(NULL); printk(KERN_INFO "HiSax: module installed\n"); -#endif +#endif /* COMPAT_HAS_NEW_SYMTAB */ +#endif /* MODULE */ return (0); } else { Isdnl1Free(); TeiFree(); Isdnl2Free(); + Isdnl3Free(); CallcFree(); return -EIO; } @@ -539,13 +1564,27 @@ void cleanup_module(void) { - HiSax_closehardware(); + int cardnr = nrcards -1; + long flags; + + save_flags(flags); + cli(); + while(cardnr>=0) + HiSax_closecard(cardnr--); + Isdnl1Free(); + TeiFree(); + Isdnl2Free(); + Isdnl3Free(); + CallcFree(); + restore_flags(flags); printk(KERN_INFO "HiSax module removed\n"); } +#endif #ifdef CONFIG_HISAX_ELSA int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) { +#ifdef MODULE int i; int nzproto = 0; @@ -553,10 +1592,10 @@ HiSaxVersion(); if (id) /* If id= string used */ HiSax_id = id; - /* Initialize all 16 structs, even though we only accept + /* Initialize all 8 structs, even though we only accept two pcmcia cards */ - for (i = 0; i < 16; i++) { + for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; cards[i].typ = type[i]; @@ -575,7 +1614,7 @@ HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", @@ -583,16 +1622,71 @@ Isdnl1New(); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); +#endif return (0); } #endif + #ifdef CONFIG_HISAX_SEDLBAUER int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) { +#ifdef MODULE + int i; + int nzproto = 0; + + nrcards = 0; + HiSaxVersion(); + if (id) /* If id= string used */ + HiSax_id = id; + /* Initialize all 8 structs, even though we only accept + two pcmcia cards + */ + for (i = 0; i < HISAX_MAX_CARDS; i++) { + cards[i].para[0] = irq[i]; + cards[i].para[1] = io[i]; + cards[i].typ = type[i]; + if (protocol[i]) { + cards[i].protocol = protocol[i]; + nzproto++; + } + } + cards[0].para[0] = pcm_irq; + cards[0].para[1] = (int)pcm_iob; + cards[0].protocol = prot; + cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; + nzproto = 1; + + if (!HiSax_id) + HiSax_id = HiSaxID; + if (!HiSaxID[0]) + strcpy(HiSaxID, "HiSax"); + for (i = 0; i < HISAX_MAX_CARDS; i++) + if (cards[i].typ > 0) + nrcards++; + printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", + nrcards, (nrcards > 1) ? "s" : ""); + + CallcNew(); + Isdnl3New(); + Isdnl2New(); + Isdnl1New(); + TeiNew(); + HiSax_inithardware(busy_flag); + printk(KERN_NOTICE "HiSax: module installed\n"); +#endif + return (0); +} +#endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) +{ +#ifdef MODULE int i; int nzproto = 0; @@ -615,14 +1709,14 @@ cards[0].para[0] = pcm_irq; cards[0].para[1] = (int)pcm_iob; cards[0].protocol = prot; - cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; + cards[0].typ = ISDN_CTYPE_A1_PCMCIA; nzproto = 1; if (!HiSax_id) HiSax_id = HiSaxID; if (!HiSaxID[0]) strcpy(HiSaxID, "HiSax"); - for (i = 0; i < 16; i++) + for (i = 0; i < HISAX_MAX_CARDS; i++) if (cards[i].typ > 0) nrcards++; printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", @@ -630,11 +1724,12 @@ Isdnl1New(); CallcNew(); + Isdnl3New(); Isdnl2New(); TeiNew(); HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); +#endif return (0); } #endif -#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.2.10/linux/drivers/isdn/hisax/diva.c Thu Nov 5 09:58:43 1998 +++ linux/drivers/isdn/hisax/diva.c Mon Aug 9 12:04:39 1999 @@ -1,13 +1,37 @@ -/* $Id: diva.c,v 1.5 1998/02/02 13:29:38 keil Exp $ +/* $Id: diva.c,v 1.12 1999/07/12 21:05:04 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations * * * $Log: diva.c,v $ + * Revision 1.12 1999/07/12 21:05:04 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.11 1999/07/01 08:11:29 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.10 1998/11/15 23:54:31 keil + * changes from 2.0 + * + * Revision 1.9 1998/06/27 22:52:03 keil + * support for Diva 2.01 + * + * Revision 1.8 1998/05/25 12:57:46 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.7 1998/04/15 16:42:36 keil + * new init code + * new PCI init (2.1.94) + * + * Revision 1.6 1998/03/07 22:56:57 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.5 1998/02/02 13:29:38 keil * fast io * @@ -31,13 +55,16 @@ #include "hisax.h" #include "isac.h" #include "hscx.h" +#include "ipac.h" #include "isdnl1.h" #include +#ifndef COMPAT_HAS_NEW_PCI #include +#endif extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.5 $"; +const char *Diva_revision = "$Revision: 1.12 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -47,6 +74,8 @@ #define DIVA_ISA_ISAC_DATA 2 #define DIVA_ISA_ISAC_ADR 6 #define DIVA_ISA_CTRL 7 +#define DIVA_IPAC_ADR 0 +#define DIVA_IPAC_DATA 1 #define DIVA_PCI_ISAC_DATA 8 #define DIVA_PCI_ISAC_ADR 0xc @@ -55,6 +84,8 @@ /* SUB Types */ #define DIVA_ISA 1 #define DIVA_PCI 2 +#define DIVA_IPAC_ISA 3 +#define DIVA_IPAC_PCI 4 /* PCI stuff */ #define PCI_VENDOR_EICON_DIEHL 0x1133 @@ -62,10 +93,12 @@ #define PCI_DIVA20_ID 0xe002 #define PCI_DIVA20PRO_U_ID 0xe003 #define PCI_DIVA20_U_ID 0xe004 +#define PCI_DIVA_201 0xe005 /* CTRL (Read) */ #define DIVA_IRQ_STAT 0x01 #define DIVA_EEPROM_SDA 0x02 + /* CTRL (Write) */ #define DIVA_IRQ_REQ 0x01 #define DIVA_RESET 0x08 @@ -76,6 +109,13 @@ #define DIVA_ISA_LED_B 0x40 #define DIVA_IRQ_CLR 0x80 +/* Siemens PITA */ +#define PITA_MISC_REG 0x1c +#define PITA_PARA_SOFTRESET 0x01000000 +#define PITA_PARA_MPX_MODE 0x04000000 +#define PITA_INT0_ENABLE 0x00020000 +#define PITA_INT0_STATUS 0x00000002 + static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) { @@ -120,6 +160,22 @@ outsb(adr, data, size); } +static inline u_char +memreadreg(unsigned long adr, u_char off) +{ + return(0xff & *((unsigned int *) + (((unsigned int *)adr) + off))); +} + +static inline void +memwritereg(unsigned long adr, u_char off, u_char data) +{ + register u_char *p; + + p = (unsigned char *)(((unsigned int *)adr) + off); + *p = data; +} + /* Interface functions */ static u_char @@ -140,13 +196,37 @@ readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } -static void +static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) { writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80)); +} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return(readreg(cs->hw.diva.hscx_adr, @@ -160,6 +240,44 @@ cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value); } +static u_char +MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (memreadreg(cs->hw.diva.cfg_reg, offset+0x80)); +} + +static void +MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + memwritereg(cs->hw.diva.cfg_reg, offset|0x80, value); +} + +static void +MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + while(size--) + *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80); +} + +static void +MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + while(size--) + memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++); +} + +static u_char +MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return(memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0))); +} + +static void +MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value); +} + /* * fast interrupt HSCX stuff goes here */ @@ -168,21 +286,21 @@ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0)) #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data) - + #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - + #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - + #include "hscx_irq.c" static void diva_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, sval, stat = 0; - int cnt=8; + u_char val, sval; + int cnt=5; if (!cs) { printk(KERN_WARNING "Diva: Spurious interrupt!\n"); @@ -190,43 +308,421 @@ } while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) { val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40); - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA); - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } cnt--; } if (!cnt) printk(KERN_WARNING "Diva: IRQ LOOP\n"); - if (stat & 1) { - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0); - } - if (stat & 2) { - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0); +} + +static void +diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista,val; + int icnt=5; + + if (!cs) { + printk(KERN_WARNING "Diva: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); +Start_IPACISA: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPACISA; + } + if (!icnt) + printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0); +} + +static inline void +MemwaitforCEC(struct IsdnCardState *cs, int hscx) +{ + int to = 50; + + while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); +} + + +static inline void +MemwaitforXFW(struct IsdnCardState *cs, int hscx) +{ + int to = 50; + + while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); +} + +static inline void +MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) +{ + long flags; + + save_flags(flags); + cli(); + MemwaitforCEC(cs, hscx); + MemWriteHSCX(cs, hscx, HSCX_CMDR, data); + restore_flags(flags); +} + +static void +Memhscx_empty_fifo(struct BCState *bcs, int count) +{ + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + long flags; + int cnt; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_empty_fifo"); + + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hscx_empty_fifo: incoming packet too large"); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + bcs->hw.hscx.rcvidx = 0; + return; + } + save_flags(flags); + cli(); + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + cnt = count; + while (cnt--) + *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + restore_flags(flags); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_empty_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); } } +static void +Memhscx_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int more, count, cnt; + int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; + u_char *ptr,*p; + long flags; + + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hscx_fill_fifo"); + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > fifo_size) { + more = !0; + count = fifo_size; + } else + count = bcs->tx_skb->len; + cnt = count; + MemwaitforXFW(cs, bcs->hw.hscx.hscx); + save_flags(flags); + cli(); + p = ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + while(cnt--) + memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0, + *p++); + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); + restore_flags(flags); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "hscx_fill_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +static inline void +Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) +{ + u_char r; + struct BCState *bcs = cs->bcs + hscx; + struct sk_buff *skb; + int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; + int count; + + if (!test_bit(BC_FLG_INIT, &bcs->Flag)) + return; + + if (val & 0x80) { /* RME */ + r = MemReadHSCX(cs, hscx, HSCX_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!(r & 0x80)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX invalid frame"); + if ((r & 0x40) && bcs->mode) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX RDO mode=%d", + bcs->mode); + if (!(r & 0x20)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX CRC error"); + MemWriteHSCXCMDR(cs, hscx, 0x80); + } else { + count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( + test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); + if (count == 0) + count = fifo_size; + Memhscx_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "HSCX: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } + } + bcs->hw.hscx.rcvidx = 0; + hscx_sched_event(bcs, B_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + Memhscx_empty_fifo(bcs, fifo_size); + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(fifo_size))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + hscx_sched_event(bcs, B_RCVBUFREADY); + } + } + if (val & 0x10) { /* XPR */ + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + Memhscx_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + Memhscx_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + hscx_sched_event(bcs, B_XMTBUFREADY); + } + } +} + +static inline void +Memhscx_int_main(struct IsdnCardState *cs, u_char val) +{ + + u_char exval; + struct BCState *bcs; + + if (val & 0x01) { + bcs = cs->bcs + 1; + exval = MemReadHSCX(cs, 1, HSCX_EXIR); + if (exval & 0x40) { + if (bcs->mode == 1) + Memhscx_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX B EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B EXIR %x", exval); + } + if (val & 0xf8) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B interrupt %x", val); + Memhscx_interrupt(cs, val, 1); + } + if (val & 0x02) { + bcs = cs->bcs; + exval = MemReadHSCX(cs, 0, HSCX_EXIR); + if (exval & 0x40) { + if (bcs->mode == L1_MODE_TRANS) + Memhscx_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX A EXIR %x Lost TX", exval); + } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A EXIR %x", exval); + } + if (val & 0x04) { + exval = MemReadHSCX(cs, 0, HSCX_ISTA); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A interrupt %x", exval); + Memhscx_interrupt(cs, exval, 0); + } +} + +static void +diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista,val; + int icnt=5; + u_char *cfg; + + if (!cs) { + printk(KERN_WARNING "Diva: Spurious interrupt!\n"); + return; + } + cfg = (u_char *) cs->hw.diva.pci_cfg; + val = *cfg; + if (!(val & PITA_INT0_STATUS)) + return; /* other shared IRQ */ + *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */ + ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); +Start_IPACPCI: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + Memhscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPACPCI; + } + if (!icnt) + printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n"); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0); +} + void release_io_diva(struct IsdnCardState *cs) { int bytecnt; - - del_timer(&cs->hw.diva.tl); - if (cs->subtyp == DIVA_ISA) + + if (cs->subtyp == DIVA_IPAC_PCI) { + u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg; + + *cfg = 0; /* disable INT0/1 */ + *cfg = 2; /* reset pending INT0 */ + iounmap((void *)cs->hw.diva.cfg_reg); + iounmap((void *)cs->hw.diva.pci_cfg); + return; + } else if (cs->subtyp != DIVA_IPAC_ISA) { + del_timer(&cs->hw.diva.tl); + if (cs->hw.diva.cfg_reg) + byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ + } + if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) bytecnt = 8; else bytecnt = 32; if (cs->hw.diva.cfg_reg) { - byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ release_region(cs->hw.diva.cfg_reg, bytecnt); } } @@ -238,19 +734,43 @@ save_flags(flags); sti(); - cs->hw.diva.ctrl_reg = 0; /* Reset On */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ - if (cs->subtyp == DIVA_ISA) - cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; - else - cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + if (cs->subtyp == DIVA_IPAC_ISA) { + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); + } else if (cs->subtyp == DIVA_IPAC_PCI) { + unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + + PITA_MISC_REG); + *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + *ireg = PITA_PARA_MPX_MODE; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); + } else { /* DIVA 2.0 */ + cs->hw.diva.ctrl_reg = 0; /* Reset On */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + if (cs->subtyp == DIVA_ISA) + cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; + else { + /* Workaround PCI9060 */ + byteout(cs->hw.diva.pci_cfg + 0x69, 9); + cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; + } + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); + } + restore_flags(flags); } #define DIVA_ASSIGN 1 @@ -260,6 +780,8 @@ { int blink = 0; + if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI)) + return; del_timer(&cs->hw.diva.tl); if (cs->hw.diva.status & DIVA_ASSIGN) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? @@ -272,14 +794,14 @@ if (cs->hw.diva.status & 0xf000) cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; - else if (cs->hw.diva.status & 0x0f00) { + else if (cs->hw.diva.status & 0x0f00) { cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B; blink = 500; } else cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ? DIVA_ISA_LED_B : DIVA_PCI_LED_B); - + byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); if (blink) { init_timer(&cs->hw.diva.tl); @@ -291,6 +813,8 @@ static int Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) { + u_int *ireg; + switch (mt) { case CARD_RESET: reset_diva(cs); @@ -298,37 +822,35 @@ case CARD_RELEASE: release_io_diva(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &diva_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + if (cs->subtyp == DIVA_IPAC_PCI) { + ireg = (unsigned int *)cs->hw.diva.pci_cfg; + *ireg = PITA_INT0_ENABLE; + } + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); - case MDL_REMOVE_REQ: + case (MDL_REMOVE | REQUEST): cs->hw.diva.status = 0; break; - case MDL_ASSIGN_REQ: + case (MDL_ASSIGN | REQUEST): cs->hw.diva.status |= DIVA_ASSIGN; break; case MDL_INFO_SETUP: - if ((int)arg) + if ((long)arg) cs->hw.diva.status |= 0x0200; else cs->hw.diva.status |= 0x0100; break; case MDL_INFO_CONN: - if ((int)arg) + if ((long)arg) cs->hw.diva.status |= 0x2000; else cs->hw.diva.status |= 0x1000; break; case MDL_INFO_REL: - if ((int)arg) { + if ((long)arg) { cs->hw.diva.status &= ~0x2000; cs->hw.diva.status &= ~0x0200; } else { @@ -337,18 +859,24 @@ } break; } - diva_led_handler(cs); + if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI)) + diva_led_handler(cs); return(0); } - - -static int pci_index __initdata = 0; +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_diva __initdata = NULL; +static struct pci_dev *dev_diva_u __initdata = NULL; +static struct pci_dev *dev_diva201 __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif __initfunc(int setup_diva(struct IsdnCard *card)) { int bytecnt; + u_char val; struct IsdnCardState *cs = card->cs; char tmp[64]; @@ -358,18 +886,75 @@ return(0); cs->hw.diva.status = 0; if (card->para[1]) { - cs->subtyp = DIVA_ISA; cs->hw.diva.ctrl_reg = 0; cs->hw.diva.cfg_reg = card->para[1]; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, + cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + if (val == 1) { + cs->subtyp = DIVA_IPAC_ISA; + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + } else { + cs->subtyp = DIVA_ISA; + cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; + cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; + cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; + cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; + } cs->irq = card->para[0]; bytecnt = 8; } else { #if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "Diva: no PCI bus present\n"); + return(0); + } + + cs->subtyp = 0; + if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA20_ID, dev_diva))) { + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva->irq; + cs->hw.diva.cfg_reg = dev_diva->base_address[2] + & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA20_U_ID, dev_diva_u))) { + cs->subtyp = DIVA_PCI; + cs->irq = dev_diva_u->irq; + cs->hw.diva.cfg_reg = dev_diva_u->base_address[2] + & PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA_201, dev_diva201))) { + cs->subtyp = DIVA_IPAC_PCI; + cs->irq = dev_diva201->irq; + cs->hw.diva.pci_cfg = + (ulong) ioremap((dev_diva201->base_address[0] + & PCI_BASE_ADDRESS_IO_MASK), 4096); + cs->hw.diva.cfg_reg = + (ulong) ioremap((dev_diva201->base_address[1] + & PCI_BASE_ADDRESS_IO_MASK), 4096); + } else { + printk(KERN_WARNING "Diva: No PCI card found\n"); + return(0); + } + + if (!cs->irq) { + printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); + return(0); + } + + if (!cs->hw.diva.cfg_reg) { + printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); + return(0); + } +#else u_char pci_bus, pci_device_fn, pci_irq; u_int pci_ioaddr; @@ -380,9 +965,13 @@ == PCIBIOS_SUCCESSFUL) cs->subtyp = DIVA_PCI; else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL, - PCI_DIVA20_ID, pci_index, &pci_bus, &pci_device_fn) + PCI_DIVA20_U_ID, pci_index, &pci_bus, &pci_device_fn) == PCIBIOS_SUCCESSFUL) cs->subtyp = DIVA_PCI; + else if (pcibios_find_device(PCI_VENDOR_EICON_DIEHL, + PCI_DIVA_201, pci_index, &pci_bus, &pci_device_fn) + == PCIBIOS_SUCCESSFUL) + cs->subtyp = DIVA_IPAC_PCI; else break; /* get IRQ */ @@ -390,8 +979,23 @@ PCI_INTERRUPT_LINE, &pci_irq); /* get IO address */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_2, &pci_ioaddr); + if (cs->subtyp == DIVA_IPAC_PCI) { + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + cs->hw.diva.pci_cfg = (ulong) ioremap(pci_ioaddr, + 4096); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &pci_ioaddr); + cs->hw.diva.cfg_reg = (ulong) ioremap(pci_ioaddr, + 4096); + } else { + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &pci_ioaddr); + cs->hw.diva.pci_cfg = pci_ioaddr & ~3; + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_2, &pci_ioaddr); + cs->hw.diva.cfg_reg = pci_ioaddr & ~3; + } if (cs->subtyp) break; } @@ -399,65 +1003,103 @@ printk(KERN_WARNING "Diva: No PCI card found\n"); return(0); } + pci_index++; if (!pci_irq) { printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); return(0); } - if (!pci_ioaddr) { printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.diva.cfg_reg = pci_ioaddr; - cs->hw.diva.ctrl = pci_ioaddr + DIVA_PCI_CTRL; - cs->hw.diva.isac = pci_ioaddr + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = pci_ioaddr + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = pci_ioaddr + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = pci_ioaddr + DIVA_HSCX_ADR; cs->irq = pci_irq; - bytecnt = 32; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->irq_flags |= SA_SHIRQ; #else printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n"); printk(KERN_WARNING "Diva: unable to config DIVA PCI\n"); return (0); #endif /* CONFIG_PCI */ + if (cs->subtyp == DIVA_IPAC_PCI) { + cs->hw.diva.ctrl = 0; + cs->hw.diva.isac = 0; + cs->hw.diva.hscx = 0; + cs->hw.diva.isac_adr = 0; + cs->hw.diva.hscx_adr = 0; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + bytecnt = 0; + } else { + cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; + cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; + cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; + cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; + cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; + bytecnt = 32; + } } printk(KERN_INFO - "Diva: %s card configured at 0x%x IRQ %d\n", - (cs->subtyp == DIVA_ISA) ? "ISA" : "PCI", + "Diva: %s card configured at %#lx IRQ %d\n", + (cs->subtyp == DIVA_PCI) ? "PCI" : + (cs->subtyp == DIVA_ISA) ? "ISA" : + (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI", cs->hw.diva.cfg_reg, cs->irq); - if (check_region(cs->hw.diva.cfg_reg, bytecnt)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.diva.cfg_reg, - cs->hw.diva.cfg_reg + bytecnt); - return (0); - } else { - request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn"); + if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI)) + printk(KERN_INFO "Diva: %s PCI space at %#lx\n", + (cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI", + cs->hw.diva.pci_cfg); + if (cs->subtyp != DIVA_IPAC_PCI) { + if (check_region(cs->hw.diva.cfg_reg, bytecnt)) { + printk(KERN_WARNING + "HiSax: %s config port %lx-%lx already in use\n", + CardType[card->typ], + cs->hw.diva.cfg_reg, + cs->hw.diva.cfg_reg + bytecnt); + return (0); + } else { + request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn"); + } } - reset_diva(cs); - cs->hw.diva.tl.function = (void *) diva_led_handler; - cs->hw.diva.tl.data = (long) cs; - init_timer(&cs->hw.diva.tl); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Diva_card_msg; - - ISACVersion(cs, "Diva:"); - if (HscxVersion(cs, "Diva:")) { - printk(KERN_WARNING + if (cs->subtyp == DIVA_IPAC_ISA) { + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &diva_irq_ipac_isa; + val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + } else if (cs->subtyp == DIVA_IPAC_PCI) { + cs->readisac = &MemReadISAC_IPAC; + cs->writeisac = &MemWriteISAC_IPAC; + cs->readisacfifo = &MemReadISACfifo_IPAC; + cs->writeisacfifo = &MemWriteISACfifo_IPAC; + cs->BC_Read_Reg = &MemReadHSCX; + cs->BC_Write_Reg = &MemWriteHSCX; + cs->BC_Send_Data = &Memhscx_fill_fifo; + cs->irq_func = &diva_irq_ipac_pci; + val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID); + printk(KERN_INFO "Diva: IPAC version %x\n", val); + } else { /* DIVA 2.0 */ + cs->hw.diva.tl.function = (void *) diva_led_handler; + cs->hw.diva.tl.data = (long) cs; + init_timer(&cs->hw.diva.tl); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &diva_interrupt; + ISACVersion(cs, "Diva:"); + if (HscxVersion(cs, "Diva:")) { + printk(KERN_WARNING "Diva: wrong HSCX versions check IO address\n"); - release_io_diva(cs); - return (0); + release_io_diva(cs); + return (0); + } } return (1); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.2.10/linux/drivers/isdn/hisax/elsa.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/elsa.c Mon Aug 9 12:04:39 1999 @@ -1,13 +1,48 @@ -/* $Id: elsa.c,v 2.6 1998/02/02 13:29:40 keil Exp $ +/* $Id: elsa.c,v 2.14 1999/07/12 21:05:07 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * Thanks to Elsa GmbH for documents and informations * + * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) + * for ELSA PCMCIA support + * * * $Log: elsa.c,v $ + * Revision 2.14 1999/07/12 21:05:07 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.13 1999/07/01 08:11:31 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.12 1998/11/15 23:54:35 keil + * changes from 2.0 + * + * Revision 2.11 1998/08/20 13:50:34 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.10 1998/08/13 23:36:22 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.9 1998/05/25 12:57:48 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/04/15 16:41:42 keil + * QS3000 PCI support + * new init code + * new PCI init (2.1.94) + * + * Revision 2.7 1998/03/07 22:56:58 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.6 1998/02/02 13:29:40 keil * fast io * @@ -29,15 +64,6 @@ * Revision 2.0 1997/06/26 11:02:40 keil * New Layer and card interface * - * Revision 1.14 1997/04/13 19:53:25 keil - * Fixed QS1000 init, change in IRQ check delay for SMP - * - * Revision 1.13 1997/04/07 22:58:07 keil - * need include config.h - * - * Revision 1.12 1997/04/06 22:54:14 keil - * Using SKB's - * * old changes removed KKe * */ @@ -51,14 +77,18 @@ #include "hscx.h" #include "isdnl1.h" #include +#ifndef COMPAT_HAS_NEW_PCI #include +#endif +#include +#include extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.6 $"; +const char *Elsa_revision = "$Revision: 2.14 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI"}; + "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI"}; const char *ITACVer[] = {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", @@ -87,11 +117,13 @@ #define ELSA_QS1000 7 #define ELSA_QS3000 8 #define ELSA_QS1000PCI 9 +#define ELSA_QS3000PCI 10 /* PCI stuff */ #define PCI_VENDOR_ELSA 0x1048 #define PCI_QS1000_ID 0x1000 - +#define PCI_QS3000_ID 0x3000 +#define ELSA_PCI_IRQ_MASK 0x04 /* ITAC Registeradressen (only Microlink PC) */ #define ITAC_SYS 0x34 @@ -128,6 +160,40 @@ #define ELSA_BAD_PWR 2 #define ELSA_ASSIGN 4 +#define RS_ISR_PASS_LIMIT 256 +#define _INLINE_ inline +#define FLG_MODEM_ACTIVE 1 +/* IPAC AUX */ +#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ +#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ + +static struct arcofi_msg ARCOFI_XOP_F = + {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ +static struct arcofi_msg ARCOFI_XOP_1 = + {&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */ +static struct arcofi_msg ARCOFI_SOP_F = + {&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}}; +static struct arcofi_msg ARCOFI_COP_9 = + {&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */ +static struct arcofi_msg ARCOFI_COP_8 = + {&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */ +static struct arcofi_msg ARCOFI_COP_7 = + {&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */ +static struct arcofi_msg ARCOFI_COP_6 = + {&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */ +static struct arcofi_msg ARCOFI_COP_5 = + {&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */ +static struct arcofi_msg ARCOFI_VERSION = + {NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}}; +static struct arcofi_msg ARCOFI_XOP_0 = + {NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */ + +static void set_arcofi(struct IsdnCardState *cs, int bc); + +#if ARCOFI_USE +#include "elsa_ser.c" +#endif + static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) { @@ -296,12 +362,27 @@ { struct IsdnCardState *cs = dev_id; u_char val; - int icnt=20; + int icnt=5; if (!cs) { printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } + if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { + /* The card tends to generate interrupts while being removed + causing us to just crash the kernel. bad. */ + printk(KERN_WARNING "Elsa: card not available!\n"); + return; + } +#if ARCOFI_USE + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_IIR); + if (!(val & UART_IIR_NO_INT)) { + debugl1(cs,"IIR %02x", val); + rs_interrupt_elsa(intno, cs); + } + } +#endif val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); Start_HSCX: if (val) { @@ -338,6 +419,14 @@ cs->hw.elsa.counter++; } } + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_MCR); + val ^= 0x8; + serial_outp(cs, UART_MCR, val); + val = serial_inp(cs, UART_MCR); + val ^= 0x8; + serial_outp(cs, UART_MCR, val); + } if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); @@ -350,25 +439,28 @@ { struct IsdnCardState *cs = dev_id; u_char ista,val; - char tmp[64]; - int icnt=20; + int icnt=5; if (!cs) { printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } - if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Elsa: card not available!\n"); - return; + val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ + if (!(val & ELSA_PCI_IRQ_MASK)) + return; +#if ARCOFI_USE + if (cs->hw.elsa.MFlag) { + val = serial_inp(cs, UART_IIR); + if (!(val & UART_IIR_NO_INT)) { + debugl1(cs,"IIR %02x", val); + rs_interrupt_elsa(intno, cs); + } } +#endif ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); Start_IPAC: - if (cs->debug & L1_DEB_IPAC) { - sprintf(tmp, "IPAC ISTA %02X", ista); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); if (ista & 0x0f) { val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); if (ista & 0x01) @@ -407,17 +499,27 @@ int bytecnt = 8; del_timer(&cs->hw.elsa.tl); + clear_arcofi(cs); if (cs->hw.elsa.ctrl) byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ - if ((cs->subtyp == ELSA_PCFPRO) || - (cs->subtyp == ELSA_QS3000) || - (cs->subtyp == ELSA_PCF)) - bytecnt = 16; if (cs->subtyp == ELSA_QS1000PCI) { byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); bytecnt = 2; release_region(cs->hw.elsa.cfg, 0x80); } + if (cs->subtyp == ELSA_QS3000PCI) { + byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + release_region(cs->hw.elsa.cfg, 0x80); + } + if ((cs->subtyp == ELSA_PCFPRO) || + (cs->subtyp == ELSA_QS3000) || + (cs->subtyp == ELSA_PCF) || + (cs->subtyp == ELSA_QS3000PCI)) { + bytecnt = 16; + release_modem(cs); + } if (cs->hw.elsa.base) release_region(cs->hw.elsa.base, bytecnt); } @@ -445,45 +547,35 @@ if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0xff); } - if (cs->subtyp == ELSA_QS1000PCI) { + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { save_flags(flags); sti(); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); current->state = TASK_INTERRUPTIBLE; - schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ restore_flags(flags); - byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); + if (cs->subtyp == ELSA_QS1000PCI) + byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ + else if (cs->subtyp == ELSA_QS3000PCI) + byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ } } -const u_char ARCOFI_VERSION[] = {2,0xa0,0}; -const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */ -const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */ -const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */ -const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */ -const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0x9e,0x88,0x00,0xc8,0xd8,0x80}; /* RX */ -const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */ -const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR Down */ -const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* PWR Down */ -const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}; - static void -init_arcofi(struct IsdnCardState *cs) { - send_arcofi(cs, ARCOFI_COP_5); - send_arcofi(cs, ARCOFI_COP_6); - send_arcofi(cs, ARCOFI_COP_7); - send_arcofi(cs, ARCOFI_COP_8); - send_arcofi(cs, ARCOFI_COP_9); - send_arcofi(cs, ARCOFI_SOP_F); - send_arcofi(cs, ARCOFI_XOP_F); +set_arcofi(struct IsdnCardState *cs, int bc) { + cs->dc.isac.arcofi_bc = bc; + arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5); + interruptible_sleep_on(&cs->dc.isac.arcofi_wait); } -static void +static int check_arcofi(struct IsdnCardState *cs) { #if ARCOFI_USE @@ -492,24 +584,24 @@ char *t; u_char *p; - if (!cs->mon_tx) - if (!(cs->mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (!cs->dc.isac.mon_tx) + if (!(cs->dc.isac.mon_tx=kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON TX out of buffers!"); - return; + return(0); } - send_arcofi(cs, ARCOFI_VERSION); - if (test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags)) { - if (test_and_clear_bit(HW_MON1_RX_END, &cs->HW_Flags)) { - sprintf(tmp, "Arcofi response received %d bytes", cs->mon_rxp); - debugl1(cs, tmp); - p = cs->mon_rx; + cs->dc.isac.arcofi_bc = 0; + arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); + interruptible_sleep_on(&cs->dc.isac.arcofi_wait); + if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { + debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); + p = cs->dc.isac.mon_rx; t = tmp; t += sprintf(tmp, "Arcofi data"); - QuickHex(t, p, cs->mon_rxp); + QuickHex(t, p, cs->dc.isac.mon_rxp); debugl1(cs, tmp); - if ((cs->mon_rxp == 2) && (cs->mon_rx[0] == 0xa0)) { - switch(cs->mon_rx[1]) { + if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) { + switch(cs->dc.isac.mon_rx[1]) { case 0x80: debugl1(cs, "Arcofi 2160 detected"); arcofi_present = 1; @@ -528,11 +620,9 @@ } } else debugl1(cs, "undefined Monitor response"); - cs->mon_rxp = 0; - } - } else if (cs->mon_tx) { - sprintf(tmp, "Arcofi not detected"); - debugl1(cs, tmp); + cs->dc.isac.mon_rxp = 0; + } else if (cs->dc.isac.mon_tx) { + debugl1(cs, "Arcofi not detected"); } if (arcofi_present) { if (cs->subtyp==ELSA_QS1000) { @@ -572,9 +662,12 @@ "Elsa: %s detected modem at 0x%x\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); - init_arcofi(cs); + arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); + interruptible_sleep_on(&cs->dc.isac.arcofi_wait); + return(1); } #endif + return(0); } static void @@ -582,8 +675,7 @@ { int blink = 0; - if ((cs->subtyp == ELSA_PCMCIA) && - (cs->subtyp == ELSA_QS1000PCI)) + if (cs->subtyp == ELSA_PCMCIA) return; del_timer(&cs->hw.elsa.tl); if (cs->hw.elsa.status & ELSA_ASSIGN) @@ -602,7 +694,16 @@ } else cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + if ((cs->subtyp == ELSA_QS1000PCI) || + (cs->subtyp == ELSA_QS3000PCI)) { + u_char led = 0xff; + if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) + led ^= ELSA_IPAC_LINE_LED; + if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) + led ^= ELSA_IPAC_STAT_LED; + writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); + } else + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); if (blink) { init_timer(&cs->hw.elsa.tl); cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); @@ -613,8 +714,9 @@ static int Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int pwr, ret = 0; - long flags; + int len, ret = 0; + u_char *msg; + long flags; switch (mt) { case CARD_RESET: @@ -623,29 +725,25 @@ case CARD_RELEASE: release_io_elsa(cs); return(0); - case CARD_SETIRQ: - if (cs->subtyp == ELSA_QS1000PCI) - ret = request_irq(cs->irq, &elsa_interrupt_ipac, - I4L_IRQ_FLAG, "HiSax", cs); - else - ret = request_irq(cs->irq, &elsa_interrupt, - I4L_IRQ_FLAG, "HiSax", cs); - return(ret); case CARD_INIT: - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); - if (cs->subtyp == ELSA_QS1000) { + cs->debug |= L1_DEB_IPAC; + inithscxisac(cs, 1); + if ((cs->subtyp == ELSA_QS1000) || + (cs->subtyp == ELSA_QS3000)) + { byteout(cs->hw.elsa.timer, 0); - byteout(cs->hw.elsa.trig, 0xff); } + if (cs->hw.elsa.trig) + byteout(cs->hw.elsa.trig, 0xff); + inithscxisac(cs, 2); return(0); case CARD_TEST: - if ((cs->subtyp != ELSA_PCMCIA) && - (cs->subtyp != ELSA_QS1000PCI)) { + if ((cs->subtyp == ELSA_PCMCIA) || + (cs->subtyp == ELSA_QS1000PCI)) { + return(0); + } else if (cs->subtyp == ELSA_QS3000PCI) { + ret = 0; + } else { save_flags(flags); cs->hw.elsa.counter = 0; sti(); @@ -653,48 +751,51 @@ cs->hw.elsa.status |= ELSA_TIMER_AKTIV; byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); byteout(cs->hw.elsa.timer, 0); - } else - return(0); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((110*HZ)/1000); /* Timeout 110ms */ - restore_flags(flags); - cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; - printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", - cs->hw.elsa.counter); - if (abs(cs->hw.elsa.counter - 13) < 3) { - printk(KERN_INFO "Elsa: timer and irq OK\n"); - ret = 0; - } else { - printk(KERN_WARNING - "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", - cs->hw.elsa.counter, cs->irq); - ret = 1; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((110*HZ)/1000); + restore_flags(flags); + cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; + byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); + cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV; + printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", + cs->hw.elsa.counter); + if (abs(cs->hw.elsa.counter - 13) < 3) { + printk(KERN_INFO "Elsa: timer and irq OK\n"); + ret = 0; + } else { + printk(KERN_WARNING + "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", + cs->hw.elsa.counter, cs->irq); + ret = 1; + } + } +#if ARCOFI_USE + if (check_arcofi(cs)) { + init_modem(cs); } - check_arcofi(cs); +#endif elsa_led_handler(cs); return(ret); - case MDL_REMOVE_REQ: + case (MDL_REMOVE | REQUEST): cs->hw.elsa.status &= 0; break; - case MDL_ASSIGN_REQ: + case (MDL_ASSIGN | REQUEST): cs->hw.elsa.status |= ELSA_ASSIGN; break; case MDL_INFO_SETUP: - if ((int) arg) + if ((long) arg) cs->hw.elsa.status |= 0x0200; else cs->hw.elsa.status |= 0x0100; break; case MDL_INFO_CONN: - if ((int) arg) + if ((long) arg) cs->hw.elsa.status |= 0x2000; else cs->hw.elsa.status |= 0x1000; break; case MDL_INFO_REL: - if ((int) arg) { + if ((long) arg) { cs->hw.elsa.status &= ~0x2000; cs->hw.elsa.status &= ~0x0200; } else { @@ -703,13 +804,23 @@ } break; case CARD_AUX_IND: + if (cs->hw.elsa.MFlag) { + if (!arg) + return(0); + msg = arg; + len = *msg; + msg++; + modem_write_cmd(cs, msg, len); + } break; } - pwr = bytein(cs->hw.elsa.ale); - if (pwr & 0x08) - cs->hw.elsa.status |= ELSA_BAD_PWR; - else - cs->hw.elsa.status &= ~ELSA_BAD_PWR; + if (cs->typ == ISDN_CTYPE_ELSA) { + int pwr = bytein(cs->hw.elsa.ale); + if (pwr & 0x08) + cs->hw.elsa.status |= ELSA_BAD_PWR; + else + cs->hw.elsa.status &= ~ELSA_BAD_PWR; + } elsa_led_handler(cs); return(ret); } @@ -778,7 +889,12 @@ return (CARD_portlist[i]); } +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_qs1000 __initdata = NULL; +static struct pci_dev *dev_qs3000 __initdata = NULL; +#else static int pci_index __initdata = 0; +#endif int setup_elsa(struct IsdnCard *card) @@ -793,6 +909,7 @@ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); cs->hw.elsa.ctrl_reg = 0; cs->hw.elsa.status = 0; + cs->hw.elsa.MFlag = 0; if (cs->typ == ISDN_CTYPE_ELSA) { cs->hw.elsa.base = card->para[0]; printk(KERN_INFO "Elsa: Microlink IO probing\n"); @@ -886,6 +1003,52 @@ cs->irq); } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { #if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "Elsa: no PCI bus present\n"); + return(0); + } + cs->subtyp = 0; + if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID, + dev_qs1000))) { + cs->subtyp = ELSA_QS1000PCI; + cs->irq = dev_qs1000->irq; + cs->hw.elsa.cfg = dev_qs1000->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs1000->base_address[3] & + PCI_BASE_ADDRESS_IO_MASK; + } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA, + PCI_QS3000_ID, dev_qs3000))) { + cs->subtyp = ELSA_QS3000PCI; + cs->irq = dev_qs3000->irq; + cs->hw.elsa.cfg = dev_qs3000->base_address[1] & + PCI_BASE_ADDRESS_IO_MASK; + cs->hw.elsa.base = dev_qs3000->base_address[3] & + PCI_BASE_ADDRESS_IO_MASK; + } else { + printk(KERN_WARNING "Elsa: No PCI card found\n"); + return(0); + } + if (!cs->irq) { + printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); + return(0); + } + + if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { + printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); + return(0); + } + if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { + printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); + printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); + printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); + printk(KERN_WARNING "Elsa: Waiting 5 sec to sync discs\n"); + save_flags(flags); + sti(); + HZDELAY(500); /* wait 500*10 ms */ + restore_flags(flags); + } +#else u_char pci_bus, pci_device_fn, pci_irq; u_int pci_ioaddr; @@ -895,6 +1058,10 @@ PCI_QS1000_ID, pci_index, &pci_bus, &pci_device_fn) == PCIBIOS_SUCCESSFUL) cs->subtyp = ELSA_QS1000PCI; + else if (pcibios_find_device(PCI_VENDOR_ELSA, + PCI_QS3000_ID, pci_index, &pci_bus, &pci_device_fn) + == PCIBIOS_SUCCESSFUL) + cs->subtyp = ELSA_QS3000PCI; else break; /* get IRQ */ @@ -915,6 +1082,7 @@ printk(KERN_WARNING "Elsa: No PCI card found\n"); return(0); } + pci_index++; if (!pci_irq) { printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); return(0); @@ -926,13 +1094,15 @@ } pci_ioaddr &= ~3; /* remove io/mem flag */ cs->hw.elsa.base = pci_ioaddr; - cs->hw.elsa.ale = pci_ioaddr; - cs->hw.elsa.isac = pci_ioaddr +1; - cs->hw.elsa.hscx = pci_ioaddr +1; cs->irq = pci_irq; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->hw.elsa.ale = cs->hw.elsa.base; + cs->hw.elsa.isac = cs->hw.elsa.base +1; + cs->hw.elsa.hscx = cs->hw.elsa.base +1; test_and_set_bit(HW_IPAC, &cs->HW_Flags); cs->hw.elsa.timer = 0; cs->hw.elsa.trig = 0; + cs->irq_flags |= SA_SHIRQ; printk(KERN_INFO "Elsa: %s defined at 0x%x/0x%x IRQ %d\n", Elsa_Types[cs->subtyp], @@ -957,6 +1127,7 @@ break; case ELSA_PCFPRO: case ELSA_PCF: + case ELSA_QS3000PCI: bytecnt = 16; break; case ELSA_QS1000PCI: @@ -980,7 +1151,7 @@ } else { request_region(cs->hw.elsa.base, bytecnt, "elsa isdn"); } - if (cs->subtyp == ELSA_QS1000PCI) { + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { if (check_region(cs->hw.elsa.cfg, 0x80)) { printk(KERN_WARNING "HiSax: %s pci port %x-%x already in use\n", @@ -993,6 +1164,7 @@ request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci"); } } + init_arcofi(cs); cs->hw.elsa.tl.function = (void *) elsa_led_handler; cs->hw.elsa.tl.data = (long) cs; init_timer(&cs->hw.elsa.tl); @@ -1020,16 +1192,17 @@ } printk(KERN_INFO "Elsa: timer OK; resetting card\n"); } - reset_elsa(cs); cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Elsa_card_msg; - if (cs->subtyp == ELSA_QS1000PCI) { + reset_elsa(cs); + if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { cs->readisac = &ReadISAC_IPAC; cs->writeisac = &WriteISAC_IPAC; cs->readisacfifo = &ReadISACfifo_IPAC; cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &elsa_interrupt_ipac; val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); printk(KERN_INFO "Elsa: IPAC version %x\n", val); } else { @@ -1037,6 +1210,7 @@ cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; cs->writeisacfifo = &WriteISACfifo; + cs->irq_func = &elsa_interrupt; ISACVersion(cs, "Elsa:"); if (HscxVersion(cs, "Elsa:")) { printk(KERN_WARNING @@ -1056,4 +1230,3 @@ } return (1); } - diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c --- v2.2.10/linux/drivers/isdn/hisax/elsa_ser.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/elsa_ser.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,750 @@ +#include +#include + +#define MAX_MODEM_BUF 256 +#define WAKEUP_CHARS (MAX_MODEM_BUF/2) +#define RS_ISR_PASS_LIMIT 256 +#define BASE_BAUD ( 1843200 / 16 ) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +//#define SERIAL_DEBUG_OPEN 1 +//#define SERIAL_DEBUG_INTR 1 +//#define SERIAL_DEBUG_FLOW 1 +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_REG +//#define SERIAL_DEBUG_REG 1 + +#ifdef SERIAL_DEBUG_REG +static u_char deb[32]; +const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"}; +const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"}; +#endif + +static char *MInit_1 = "AT&F&C1E0&D2\r\0"; +static char *MInit_2 = "ATL2M1S64=13\r\0"; +static char *MInit_3 = "AT+FCLASS=0\r\0"; +static char *MInit_4 = "ATV1S2=128X1\r\0"; +static char *MInit_5 = "AT\\V8\\N3\r\0"; +static char *MInit_6 = "ATL0M0&G0%E1\r\0"; +static char *MInit_7 = "AT%L1%M0%C3\r\0"; + +static char *MInit_speed28800 = "AT%G0%B28800\r\0"; + +static char *MInit_dialout = "ATs7=60 x1 d\r\0"; +static char *MInit_dialin = "ATs7=60 x1 a\r\0"; + + +static inline unsigned int serial_in(struct IsdnCardState *cs, int offset) +{ +#ifdef SERIAL_DEBUG_REG + u_int val = inb(cs->hw.elsa.base + 8 + offset); + debugl1(cs,"in %s %02x",ModemIn[offset], val); + return(val); +#else + return inb(cs->hw.elsa.base + 8 + offset); +#endif +} + +static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset) +{ +#ifdef SERIAL_DEBUG_REG +#ifdef CONFIG_SERIAL_NOPAUSE_IO + u_int val = inb(cs->hw.elsa.base + 8 + offset); + debugl1(cs,"inp %s %02x",ModemIn[offset], val); +#else + u_int val = inb_p(cs->hw.elsa.base + 8 + offset); + debugl1(cs,"inP %s %02x",ModemIn[offset], val); +#endif + return(val); +#else +#ifdef CONFIG_SERIAL_NOPAUSE_IO + return inb(cs->hw.elsa.base + 8 + offset); +#else + return inb_p(cs->hw.elsa.base + 8 + offset); +#endif +#endif +} + +static inline void serial_out(struct IsdnCardState *cs, int offset, int value) +{ +#ifdef SERIAL_DEBUG_REG + debugl1(cs,"out %s %02x",ModemOut[offset], value); +#endif + outb(value, cs->hw.elsa.base + 8 + offset); +} + +static inline void serial_outp(struct IsdnCardState *cs, int offset, + int value) +{ +#ifdef SERIAL_DEBUG_REG +#ifdef CONFIG_SERIAL_NOPAUSE_IO + debugl1(cs,"outp %s %02x",ModemOut[offset], value); +#else + debugl1(cs,"outP %s %02x",ModemOut[offset], value); +#endif +#endif +#ifdef CONFIG_SERIAL_NOPAUSE_IO + outb(value, cs->hw.elsa.base + 8 + offset); +#else + outb_p(value, cs->hw.elsa.base + 8 + offset); +#endif +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct IsdnCardState *cs, int baud) +{ + int quot = 0, baud_base; + unsigned cval, fcr = 0; + int bits; + unsigned long flags; + + + /* byte size and parity */ + cval = 0x03; bits = 10; + /* Determine divisor based on baud rate */ + baud_base = BASE_BAUD; + quot = baud_base / baud; + /* If the quotient is ever zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + + /* Set up FIFO's */ + if ((baud_base / quot) < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + serial_outp(cs, UART_FCR, fcr); + /* CTS flow control flag and modem status interrupts */ + cs->hw.elsa.IER &= ~UART_IER_MSI; + cs->hw.elsa.IER |= UART_IER_MSI; + serial_outp(cs, UART_IER, cs->hw.elsa.IER); + + debugl1(cs,"modem quot=0x%x", quot); + save_flags(flags); + cli(); + serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ + serial_outp(cs, UART_LCR, cval); /* reset DLAB */ + serial_inp(cs, UART_RX); + restore_flags(flags); +} + +static int mstartup(struct IsdnCardState *cs) +{ + unsigned long flags; + int retval=0; + + + save_flags(flags); cli(); + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (serial_inp(cs, UART_LSR) == 0xff) { + retval = -ENODEV; + goto errout; + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(cs, UART_RX); + (void) serial_inp(cs, UART_IIR); + (void) serial_inp(cs, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + + cs->hw.elsa.MCR = 0; + cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); + + /* + * Finally, enable interrupts + */ + cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */ + + /* + * And clear the interrupt registers again for luck. + */ + (void)serial_inp(cs, UART_LSR); + (void)serial_inp(cs, UART_RX); + (void)serial_inp(cs, UART_IIR); + (void)serial_inp(cs, UART_MSR); + + cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0; + cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp =0; + + /* + * and set the speed of the serial port + */ + change_speed(cs, BASE_BAUD); + cs->hw.elsa.MFlag = 1; +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void mshutdown(struct IsdnCardState *cs) +{ + unsigned long flags; + + +#ifdef SERIAL_DEBUG_OPEN + printk(KERN_DEBUG"Shutting down serial ...."); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + + cs->hw.elsa.IER = 0; + serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ + cs->hw.elsa.MCR &= ~UART_MCR_OUT2; + + /* disable break condition */ + serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); + + cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); + + /* disable FIFO's */ + serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); + serial_inp(cs, UART_RX); /* read data port to reset things */ + + restore_flags(flags); +#ifdef SERIAL_DEBUG_OPEN + printk(" done\n"); +#endif +} + +inline int +write_modem(struct BCState *bcs) { + int ret=0; + struct IsdnCardState *cs = bcs->cs; + int count, len, fp, buflen; + long flags; + + if (!bcs->tx_skb) + return 0; + if (bcs->tx_skb->len <= 0) + return 0; + save_flags(flags); + cli(); + buflen = MAX_MODEM_BUF - cs->hw.elsa.transcnt; + len = MIN(buflen, bcs->tx_skb->len); + fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; + fp &= (MAX_MODEM_BUF -1); + count = MIN(len, MAX_MODEM_BUF - fp); + if (count < len) { + memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count); + skb_pull(bcs->tx_skb, count); + cs->hw.elsa.transcnt += count; + ret = count; + count = len - count; + fp = 0; + } + memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count); + skb_pull(bcs->tx_skb, count); + cs->hw.elsa.transcnt += count; + ret += count; + + if (cs->hw.elsa.transcnt && + !(cs->hw.elsa.IER & UART_IER_THRI)) { + cs->hw.elsa.IER |= UART_IER_THRI; + serial_outp(cs, UART_IER, cs->hw.elsa.IER); + } + restore_flags(flags); + return(ret); +} + +inline void +modem_fill(struct BCState *bcs) { + + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + write_modem(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, + bcs->hw.hscx.count); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + write_modem(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + hscx_sched_event(bcs, B_XMTBUFREADY); + } +} + +static inline void receive_chars(struct IsdnCardState *cs, + int *status) +{ + unsigned char ch; + struct sk_buff *skb; + + do { + ch = serial_in(cs, UART_RX); + if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF) + break; + cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch; +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + if (*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE)) { + +#ifdef SERIAL_DEBUG_INTR + printk("handling exept...."); +#endif + } + *status = serial_inp(cs, UART_LSR); + } while (*status & UART_LSR_DR); + if (cs->hw.elsa.MFlag == 2) { + if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) + printk(KERN_WARNING "ElsaSER: receive out of memory\n"); + else { + memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf, + cs->hw.elsa.rcvcnt); + skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb); + } + hscx_sched_event(cs->hw.elsa.bcs, B_RCVBUFREADY); + } else { + char tmp[128]; + char *t = tmp; + + t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt); + QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); + debugl1(cs, tmp); + } + cs->hw.elsa.rcvcnt = 0; +} + +static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done) +{ + int count; + + debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, + cs->hw.elsa.transcnt); + + if (cs->hw.elsa.transcnt <= 0) { + cs->hw.elsa.IER &= ~UART_IER_THRI; + serial_out(cs, UART_IER, cs->hw.elsa.IER); + return; + } + count = 16; + do { + serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]); + if (cs->hw.elsa.transp >= MAX_MODEM_BUF) + cs->hw.elsa.transp=0; + if (--cs->hw.elsa.transcnt <= 0) + break; + } while (--count > 0); + if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag==2)) + modem_fill(cs->hw.elsa.bcs); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + if (cs->hw.elsa.transcnt <= 0) { + cs->hw.elsa.IER &= ~UART_IER_THRI; + serial_outp(cs, UART_IER, cs->hw.elsa.IER); + } +} + +#if 0 +static inline void check_modem_status(struct IsdnCardState *cs) +{ + int status; + struct async_struct *info = cs->hw.elsa.info; + struct async_icount *icount; + + status = serial_inp(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->state->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; + } + if (status & UART_MSR_DCTS) + icount->cts++; +// wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) +// wake_up_interruptible(&info->open_wait); +; + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("doing serial hangup..."); +#endif + if (info->tty) + tty_hangup(info->tty); + } + } +#if 0 + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_outp(info, UART_IER, info->IER); +// rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_outp(info, UART_IER, info->IER); + } + } + } +#endif 0 +} +#endif + +static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs) +{ + int status, iir, msr; + int pass_counter = 0; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + do { + status = serial_inp(cs, UART_LSR); + debugl1(cs,"rs LSR %02x", status); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(cs, &status); + if (status & UART_LSR_THRE) + transmit_chars(cs, 0); + if (pass_counter++ > RS_ISR_PASS_LIMIT) { + printk("rs_single loop break.\n"); + break; + } + iir = serial_inp(cs, UART_IIR); + debugl1(cs,"rs IIR %02x", iir); + if ((iir & 0xf) == 0) { + msr = serial_inp(cs, UART_MSR); + debugl1(cs,"rs MSR %02x", msr); + } + } while (!(iir & UART_IIR_NO_INT)); +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs); +extern void modehscx(struct BCState *bcs, int mode, int bc); +extern void hscx_l2l1(struct PStack *st, int pr, void *arg); + +void +close_elsastate(struct BCState *bcs) +{ + struct sk_buff *skb; + + modehscx(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + if (bcs->mode != L1_MODE_MODEM) + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + while ((skb = skb_dequeue(&bcs->rqueue))) { + idev_kfree_skb(skb, FREE_READ); + } + while ((skb = skb_dequeue(&bcs->squeue))) { + idev_kfree_skb(skb, FREE_WRITE); + } + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +void +modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { + int count, fp; + u_char *msg = buf; + long flags; + + if (!len) + return; + save_flags(flags); + cli(); + if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) { + restore_flags(flags); + return; + } + fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; + fp &= (MAX_MODEM_BUF -1); + count = MIN(len, MAX_MODEM_BUF - fp); + if (count < len) { + memcpy(cs->hw.elsa.transbuf + fp, msg, count); + cs->hw.elsa.transcnt += count; + msg += count; + count = len - count; + fp = 0; + } + memcpy(cs->hw.elsa.transbuf + fp, msg, count); + cs->hw.elsa.transcnt += count; + if (cs->hw.elsa.transcnt && + !(cs->hw.elsa.IER & UART_IER_THRI)) { + cs->hw.elsa.IER |= UART_IER_THRI; + serial_outp(cs, UART_IER, cs->hw.elsa.IER); + } + restore_flags(flags); +} + +void +modem_set_init(struct IsdnCardState *cs) { + long flags; + int timeout; + +#define RCV_DELAY 20000 + save_flags(flags); + sti(); + modem_write_cmd(cs, MInit_1, strlen(MInit_1)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + modem_write_cmd(cs, MInit_2, strlen(MInit_2)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + modem_write_cmd(cs, MInit_3, strlen(MInit_3)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + modem_write_cmd(cs, MInit_4, strlen(MInit_4)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY ); + modem_write_cmd(cs, MInit_5, strlen(MInit_5)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + modem_write_cmd(cs, MInit_6, strlen(MInit_6)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + modem_write_cmd(cs, MInit_7, strlen(MInit_7)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + restore_flags(flags); +} + +void +modem_set_dial(struct IsdnCardState *cs, int outgoing) { + long flags; + int timeout; +#define RCV_DELAY 20000 + + save_flags(flags); + sti(); + modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + if (outgoing) + modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout)); + else + modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin)); + timeout = 1000; + while(timeout-- && cs->hw.elsa.transcnt) + udelay(1000); + debugl1(cs, "msi tout=%d", timeout); + udelay(RCV_DELAY); + restore_flags(flags); +} + +void +modem_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + if (pr == (PH_DATA | REQUEST)) { + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->hw.hscx.count = 0; + restore_flags(flags); + write_modem(st->l1.bcs); + } + } else if (pr == (PH_ACTIVATE | REQUEST)) { + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); + set_arcofi(st->l1.bcs->cs, st->l1.bc); + mstartup(st->l1.bcs->cs); + modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); + st->l1.bcs->cs->hw.elsa.MFlag=2; + } else if (pr == (PH_DEACTIVATE | REQUEST)) { + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + st->l1.bcs->cs->dc.isac.arcofi_bc = st->l1.bc; + arcofi_fsm(st->l1.bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); + interruptible_sleep_on(&st->l1.bcs->cs->dc.isac.arcofi_wait); + st->l1.bcs->cs->hw.elsa.MFlag=1; + } else { + printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr); + } +} + +int +setstack_elsa(struct PStack *st, struct BCState *bcs) +{ + + bcs->channel = st->l1.bc; + switch (st->l1.mode) { + case L1_MODE_HDLC: + case L1_MODE_TRANS: + if (open_hscxstate(st->l1.hardware, bcs)) + return (-1); + st->l2.l2l1 = hscx_l2l1; + break; + case L1_MODE_MODEM: + bcs->mode = L1_MODE_MODEM; + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf; + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + bcs->cs->hw.elsa.bcs = bcs; + st->l2.l2l1 = modem_l2l1; + break; + } + st->l1.bcs = bcs; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +void +init_modem(struct IsdnCardState *cs) { + + cs->bcs[0].BC_SetStack = setstack_elsa; + cs->bcs[1].BC_SetStack = setstack_elsa; + cs->bcs[0].BC_Close = close_elsastate; + cs->bcs[1].BC_Close = close_elsastate; + if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF, + GFP_ATOMIC))) { + printk(KERN_WARNING + "Elsa: No modem mem hw.elsa.rcvbuf\n"); + return; + } + if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF, + GFP_ATOMIC))) { + printk(KERN_WARNING + "Elsa: No modem mem hw.elsa.transbuf\n"); + kfree(cs->hw.elsa.rcvbuf); + cs->hw.elsa.rcvbuf = NULL; + return; + } + if (mstartup(cs)) { + printk(KERN_WARNING "Elsa: problem startup modem\n"); + } + modem_set_init(cs); +} + +void +release_modem(struct IsdnCardState *cs) { + + cs->hw.elsa.MFlag = 0; + if (cs->hw.elsa.transbuf) { + if (cs->hw.elsa.rcvbuf) { + mshutdown(cs); + kfree(cs->hw.elsa.rcvbuf); + cs->hw.elsa.rcvbuf = NULL; + } + kfree(cs->hw.elsa.transbuf); + cs->hw.elsa.transbuf = NULL; + } +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/foreign.c linux/drivers/isdn/hisax/foreign.c --- v2.2.10/linux/drivers/isdn/hisax/foreign.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/foreign.c Wed Dec 31 16:00:00 1969 @@ -1,780 +0,0 @@ -/* $Id: foreign.c,v 1.1 1998/11/09 07:48:48 baccala Exp $ - * - * HiSax ISDN driver - foreign chipset interface - * - * Author Brent Baccala (baccala@FreeSoft.org) - * - * - * - * $Log: foreign.c,v $ - * Revision 1.1 1998/11/09 07:48:48 baccala - * Initial DBRI ISDN code. Sometimes works (brings up the link and you - * can telnet through it), sometimes doesn't (crashes the machine) - * - * Revision 1.2 1998/02/12 23:07:10 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.1 1998/02/03 23:20:51 keil - * New files for SPARC isdn support - * - * Revision 1.1 1998/01/08 04:17:12 baccala - * ISDN comes to the Sparc. Key points: - * - * - Existing ISDN HiSax driver provides all the smarts - * - it compiles, runs, talks to an isolated phone switch, connects - * to a Cisco, pings go through - * - AMD 7930 support only (no DBRI yet) - * - no US NI-1 support (may not work on US phone system - untested) - * - periodic packet loss, apparently due to lost interrupts - * - ISDN sometimes freezes, requiring reboot before it will work again - * - * The code is unreliable enough to be consider alpha - * - * - * - */ - -#define __NO_VERSION__ -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include "foreign.h" -#include "rawhdlc.h" -#include - -static const char *foreign_revision = "$Revision: 1.1 $"; - -#define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */ -#define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into - * (must divide RCV_BUFSIZE) */ - -static void Bchan_fill_fifo(struct BCState *, struct sk_buff *); - -static void -Bchan_xmt_bh(struct BCState *bcs) -{ - struct sk_buff *skb; - - if (bcs->hw.foreign.tx_skb != NULL) { - dev_kfree_skb(bcs->hw.foreign.tx_skb); - bcs->hw.foreign.tx_skb = NULL; - } - - if ((skb = skb_dequeue(&bcs->squeue))) { - Bchan_fill_fifo(bcs, skb); - } else { - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event |= 1 << B_XMTBUFREADY; - queue_task(&bcs->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } -} - -static void -Bchan_xmit_callback(struct BCState *bcs) -{ - queue_task(&bcs->hw.foreign.tq_xmt, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -/* B channel transmission: two modes (three, if you count L1_MODE_NULL) - * - * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting - * the packet (i.e. make_raw_hdlc_data). Since this can be a - * time-consuming operation, our completion callback just schedules - * a bottom half to do encapsulation for the next packet. In between, - * the link will just idle - * - * L1_MODE_TRANS - Data goes through, well, transparent. No HDLC encap, - * and we can't just let the link idle, so the "bottom half" actually - * gets called during the top half (it's our callback routine in this case), - * but it's a lot faster now since we don't call make_raw_hdlc_data - */ - -static void -Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb) -{ - struct IsdnCardState *cs = bcs->cs; - struct foreign_hw *hw = &bcs->hw.foreign; - int len; - - if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) { - char tmp[2048]; - char *t = tmp; - - t += sprintf(t, "Bchan_fill_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', skb->len); - if (cs->debug & L1_DEB_HSCX_FIFO) - QuickHex(t, skb->data, skb->len); - debugl1(cs, tmp); - } - - if (hw->doHDLCprocessing) { - len = make_raw_hdlc_data(skb->data, skb->len, - bcs->hw.foreign.tx_buff, RAW_BUFMAX); - if (len > 0) - cs->hw.foreign->bxmit(0, bcs->channel, - bcs->hw.foreign.tx_buff, len, - (void *) &Bchan_xmit_callback, - (void *) bcs); - dev_kfree_skb(skb); - } else { - cs->hw.foreign->bxmit(0, bcs->channel, - skb->data, skb->len, - (void *) &Bchan_xmit_callback, - (void *) bcs); - bcs->hw.foreign.tx_skb = skb; - } -} - -static void -Bchan_mode(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "foreign mode %d bchan %d/%d", - mode, bc, bcs->channel); - debugl1(cs, tmp); - } - bcs->mode = mode; -} - -/* Bchan_l2l1 is the entry point for upper layer routines that want to - * transmit on the B channel. PH_DATA_REQ is a normal packet that - * we either start transmitting (if idle) or queue (if busy). - * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF) - * once the link is idle. After a "pull" callback, the upper layer - * routines can use PH_PULL_IND to send data. - */ - -static void -Bchan_l2l1(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA_REQ): - if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) { - skb_queue_tail(&st->l1.bcs->squeue, skb); - } else { - test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - Bchan_fill_fifo(st->l1.bcs, skb); - } - break; - case (PH_PULL_IND): - if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) { - printk(KERN_WARNING "foreign: this shouldn't happen\n"); - break; - } - test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - Bchan_fill_fifo(st->l1.bcs, skb); - break; - case (PH_PULL_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) { - clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); - } else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - } -} - -/* -**************************************************************************** -***************** Receiver callback and bottom half ************************ -**************************************************************************** -*/ - -/* Bchan_recv_done() is called when a frame has been completely decoded - * into hw->rv_skb and we're ready to hand it off to the HiSax upper - * layer. If a "large" packet is received, stick rv_skb on the - * receive queue and alloc a new (large) skb to act as buffer for - * future receives. If a small packet is received, leave rv_skb - * alone, alloc a new skb of the correct size, and copy the packet - * into it. In any case, flag the channel as B_RCVBUFREADY and - * queue the upper layer's task. - */ - -static void -Bchan_recv_done(struct BCState *bcs, unsigned int len) -{ - struct IsdnCardState *cs = bcs->cs; - struct foreign_hw *hw = &bcs->hw.foreign; - struct sk_buff *skb; - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[2048]; - char *t = tmp; - - t += sprintf(t, "Bchan_rcv %c cnt %d (%x)", bcs->channel ? 'B' : 'A', len, hw->rv_skb->tail); - QuickHex(t, hw->rv_skb->tail, len); - debugl1(cs, tmp); - } - - if (len > HSCX_BUFMAX/2) { - /* Large packet received */ - - if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) { - printk(KERN_WARNING "foreign: receive out of memory\n"); - } else { - skb_put(hw->rv_skb, len); - skb_queue_tail(&bcs->rqueue, hw->rv_skb); - hw->rv_skb = skb; - - bcs->event |= 1 << B_RCVBUFREADY; - queue_task(&bcs->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - } else { - /* Small packet received */ - - if (!(skb = dev_alloc_skb(len))) { - printk(KERN_WARNING "foreign: receive out of memory\n"); - } else { - memcpy(skb_put(skb, len), hw->rv_skb->tail, len); - skb_queue_tail(&bcs->rqueue, skb); - - bcs->event |= 1 << B_RCVBUFREADY; - queue_task(&bcs->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - } -} - -/* Bchan_recv_callback()'s behavior depends on whether we're doing local - * HDLC processing. If so, receive into hw->rv_buff and queue Bchan_rcv_bh - * to decode the HDLC at leisure. Otherwise, receive directly into hw->rv_skb - * and call Bchan_recv_done(). In either case, prepare a new buffer for - * further receives and hand it to the hardware driver. - */ - -static void -Bchan_recv_callback(struct BCState *bcs, int error, unsigned int len) -{ - struct IsdnCardState *cs = bcs->cs; - struct foreign_hw *hw = &bcs->hw.foreign; - - if (hw->doHDLCprocessing) { - - hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS; - hw->rv_buff_in %= RCV_BUFSIZE; - - if (hw->rv_buff_in != hw->rv_buff_out) { - cs->hw.foreign->brecv(0, bcs->channel, - hw->rv_buff + hw->rv_buff_in, - RCV_BUFSIZE/RCV_BUFBLKS, - (void *) &Bchan_recv_callback, - (void *) bcs); - - } - queue_task(&hw->tq_rcv, &tq_immediate); - mark_bh(IMMEDIATE_BH); - - } else { - if (error) { - char tmp[256]; - sprintf(tmp, "B channel %c receive error %x", - bcs->channel ? 'B' : 'A', error); - debugl1(cs, tmp); - } else { - Bchan_recv_done(bcs, len); - } - cs->hw.foreign->brecv(0, bcs->channel, - hw->rv_skb->tail, HSCX_BUFMAX, - (void *) &Bchan_recv_callback, - (void *) bcs); - - } -} - -/* Bchan_rcv_bh() is a "shim" bottom half handler stuck in between - * Bchan_recv_callback() and the HiSax upper layer if we need to - * do local HDLC processing. - */ - -static void -Bchan_rcv_bh(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - struct foreign_hw *hw = &bcs->hw.foreign; - struct sk_buff *skb; - int len; - - if (cs->debug & L1_DEB_HSCX) { - char tmp[1024]; - - sprintf(tmp, "foreign_Bchan_rcv (%d/%d)", - hw->rv_buff_in, hw->rv_buff_out); - debugl1(cs, tmp); - } - - do { - if (cs->debug & L1_DEB_HSCX) { - char tmp[1024]; - - QuickHex(tmp, hw->rv_buff + hw->rv_buff_out, - RCV_BUFSIZE/RCV_BUFBLKS); - debugl1(cs, tmp); - } - - while ((len = read_raw_hdlc_data(hw->hdlc_state, - hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS, - hw->rv_skb->tail, HSCX_BUFMAX))) { - if (len > 0) { - Bchan_recv_done(bcs, len); - } else { - char tmp[256]; - sprintf(tmp, "B channel %c receive error", - bcs->channel ? 'B' : 'A'); - debugl1(cs, tmp); - } - } - - if (hw->rv_buff_in == hw->rv_buff_out) { - /* Buffer was filled up - need to restart receiver */ - cs->hw.foreign->brecv(0, bcs->channel, - hw->rv_buff + hw->rv_buff_in, - RCV_BUFSIZE/RCV_BUFBLKS, - (void *) &Bchan_recv_callback, - (void *) bcs); - } - - hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS; - hw->rv_buff_out %= RCV_BUFSIZE; - - } while (hw->rv_buff_in != hw->rv_buff_out); -} - -static void -Bchan_close(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - struct sk_buff *skb; - - Bchan_mode(bcs, 0, 0); - cs->hw.foreign->bclose(0, bcs->channel); - - if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - } - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); -} - -static int -Bchan_open(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - struct foreign_hw *hw = &bcs->hw.foreign; - - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - - hw->doHDLCprocessing = 0; - if (bcs->mode == L1_MODE_HDLC) { - if (cs->hw.foreign->bopen(0, bcs->channel, 1, 0xff) == -1) { - if (cs->hw.foreign->bopen(0, bcs->channel, 0, 0xff) == -1) { - return (-1); - } - hw->doHDLCprocessing = 1; - } - } else { - if (cs->hw.foreign->bopen(0, bcs->channel, 0, 0xff) == -1) { - return (-1); - } - } - - hw->rv_buff_in = 0; - hw->rv_buff_out = 0; - hw->tx_skb = NULL; - init_hdlc_state(hw->hdlc_state, 0); - cs->hw.foreign->brecv(0, bcs->channel, - hw->rv_buff + hw->rv_buff_in, - RCV_BUFSIZE/RCV_BUFBLKS, - (void *) &Bchan_recv_callback, (void *) bcs); - - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static void -Bchan_init(struct BCState *bcs) -{ - if (!(bcs->hw.foreign.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for foreign.tx_buff\n"); - return; - } - if (!(bcs->hw.foreign.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for foreign.rv_buff\n"); - return; - } - if (!(bcs->hw.foreign.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) { - printk(KERN_WARNING - "HiSax: No memory for foreign.rv_skb\n"); - return; - } - if (!(bcs->hw.foreign.hdlc_state = kmalloc(sizeof(struct hdlc_state), - GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for foreign.hdlc_state\n"); - return; - } - - bcs->hw.foreign.tq_rcv.sync = 0; - bcs->hw.foreign.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh; - bcs->hw.foreign.tq_rcv.data = (void *) bcs; - - bcs->hw.foreign.tq_xmt.sync = 0; - bcs->hw.foreign.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh; - bcs->hw.foreign.tq_xmt.data = (void *) bcs; -} - -static void -Bchan_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - Bchan_mode(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - -int -setstack_foreign(struct PStack *st, struct BCState *bcs) -{ - if (Bchan_open(bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = Bchan_l2l1; - st->ma.manl1 = Bchan_manl1; - setstack_manager(st); - bcs->st = st; - return (0); -} - - -static void -foreign_drecv_callback(void *arg, int error, unsigned int count) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) arg; - static struct tq_struct task = {0, 0, (void *) &DChannel_proc_rcv, 0}; - struct sk_buff *skb; - - /* NOTE: This function is called directly from an interrupt handler */ - - if (1) { - if (!(skb = alloc_skb(count, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - memcpy(skb_put(skb, count), cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - - task.data = (void *) cs; - queue_task(&task, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; - - t += sprintf(t, "foreign Drecv cnt %d", count); - if (error) t += sprintf(t, " ERR %x", error); - QuickHex(t, cs->rcvbuf, count); - debugl1(cs, tmp); - } - - cs->hw.foreign->drecv(0, cs->rcvbuf, MAX_DFRAME_LEN, - &foreign_drecv_callback, cs); -} - -static void -foreign_dxmit_callback(void *arg, int error) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) arg; - static struct tq_struct task = {0, 0, (void *) &DChannel_proc_xmt, 0}; - - /* NOTE: This function is called directly from an interrupt handler */ - - /* may wish to do retransmission here, if error indicates collision */ - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; - - t += sprintf(t, "foreign Dxmit cnt %d", cs->tx_skb->len); - if (error) t += sprintf(t, " ERR %x", error); - QuickHex(t, cs->tx_skb->data, cs->tx_skb->len); - debugl1(cs, tmp); - } - - cs->tx_skb = NULL; - - task.data = (void *) cs; - queue_task(&task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static void -foreign_Dchan_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - char str[64]; - - switch (pr) { - case (PH_DATA_REQ): - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { - /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data+4, skb->len-4, - str); - } - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - cs->hw.foreign->dxmit(0, skb->data, skb->len, - &foreign_dxmit_callback, cs); - } - break; - case (PH_PULL_IND): - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - break; - } - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - cs->hw.foreign->dxmit(0, cs->tx_skb->data, cs->tx_skb->len, - &foreign_dxmit_callback, cs); - break; - case (PH_PULL_REQ): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - } -} - -int -setDstack_foreign(struct PStack *st, struct IsdnCardState *cs) -{ - st->l2.l2l1 = foreign_Dchan_l2l1; - if (! cs->rcvbuf) { - printk("setDstack_foreign: No cs->rcvbuf!\n"); - } else { - cs->hw.foreign->drecv(0, cs->rcvbuf, MAX_DFRAME_LEN, - &foreign_drecv_callback, cs); - } - return (0); -} - -static void -manl1_msg(struct IsdnCardState *cs, int msg, void *arg) { - struct PStack *st; - - st = cs->stlist; - while (st) { - st->ma.manl1(st, msg, arg); - st = st->next; - } -} - -void -foreign_l1cmd(struct IsdnCardState *cs, int msg, void *arg) -{ - u_char val; - char tmp[32]; - - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "foreign_l1cmd msg %x", msg); - debugl1(cs, tmp); - } - - switch(msg) { - case PH_RESET_REQ: - cs->hw.foreign->liu_deactivate(0); - manl1_msg(cs, PH_POWERUP_CNF, NULL); - break; - case PH_ENABLE_REQ: - break; - case PH_INFO3_REQ: - cs->hw.foreign->liu_activate(0,0); - break; - case PH_TESTLOOP_REQ: - break; - default: - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "foreign_l1cmd unknown %4x", msg); - debugl1(cs, tmp); - } - break; - } -} - -static void -foreign_new_ph(struct IsdnCardState *cs) -{ - switch (cs->hw.foreign->get_liu_state(0)) { - case 3: - manl1_msg(cs, PH_POWERUP_CNF, NULL); - break; - - case 7: - manl1_msg(cs, PH_I4_P8_IND, NULL); - break; - - case 8: - manl1_msg(cs, PH_RSYNC_IND, NULL); - break; - } -} - -/* LIU state change callback */ - -static void -foreign_liu_callback(struct IsdnCardState *cs) -{ - static struct tq_struct task = {0, 0, (void *) &foreign_new_ph, 0}; - - if (!cs) - return; - - if (cs->debug & L1_DEB_ISAC) { - char tmp[32]; - sprintf(tmp, "foreign LIU state %d", - cs->hw.foreign->get_liu_state(0)); - debugl1(cs, tmp); - } - - task.data = (void *) cs; - queue_task(&task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static void init_foreign(struct IsdnCardState *cs) -{ - Bchan_init(&cs->bcs[0]); - Bchan_init(&cs->bcs[1]); - cs->bcs[0].BC_SetStack = setstack_foreign; - cs->bcs[1].BC_SetStack = setstack_foreign; - cs->bcs[0].BC_Close = Bchan_close; - cs->bcs[1].BC_Close = Bchan_close; - Bchan_mode(cs->bcs, 0, 0); - Bchan_mode(cs->bcs + 1, 0, 0); -} - -static int -foreign_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - return(0); - case CARD_RELEASE: - return(0); - case CARD_SETIRQ: - return(0); - case CARD_INIT: - cs->l1cmd = foreign_l1cmd; - cs->setstack_d = setDstack_foreign; - cs->hw.foreign->liu_init(0, &foreign_liu_callback, - (void *)cs); - init_foreign(cs); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -#if CARD_AMD7930 -extern struct foreign_interface amd7930_foreign_interface; -#endif - -#if CARD_DBRI -extern struct foreign_interface dbri_foreign_interface; -#endif - -__initfunc(int -setup_foreign(struct IsdnCard *card)) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, foreign_revision); - printk(KERN_INFO "HiSax: Foreign chip driver Rev. %s\n", - HiSax_getrev(tmp)); - -#if CARD_AMD7930 - if (cs->typ == ISDN_CTYPE_AMD7930) { - cs->hw.foreign = &amd7930_foreign_interface; - cs->irq = cs->hw.foreign->get_irqnum(0); - if (cs->irq == 0) - return (0); - cs->cardmsg = &foreign_card_msg; - return (1); - } -#endif - -#if CARD_DBRI - if (cs->typ == ISDN_CTYPE_DBRI) { - cs->hw.foreign = &dbri_foreign_interface; - cs->irq = cs->hw.foreign->get_irqnum(0); - if (cs->irq == 0) - return (0); - cs->cardmsg = &foreign_card_msg; - return (1); - } -#endif - - return(0); -} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/foreign.h linux/drivers/isdn/hisax/foreign.h --- v2.2.10/linux/drivers/isdn/hisax/foreign.h Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/foreign.h Wed Dec 31 16:00:00 1969 @@ -1,193 +0,0 @@ -/* $Id: foreign.h,v 1.1 1998/11/09 07:48:57 baccala Exp $ - * - * HiSax ISDN driver - foreign chipset interface - * - * Author Brent Baccala (baccala@FreeSoft.org) - * - * - * - * $Log: foreign.h,v $ - * Revision 1.1 1998/11/09 07:48:57 baccala - * Initial DBRI ISDN code. Sometimes works (brings up the link and you - * can telnet through it), sometimes doesn't (crashes the machine) - * - */ - -/* - * ISDN operations - * - * Many of these routines take an "int dev" argument, which is simply - * an index into the drivers[] array. Currently, we only support a - * single foreign chip, so the value should always be 0. B channel - * operations require an "int chan", which should be 0 for channel B1 - * and 1 for channel B2 - * - * int get_irqnum(int dev) - * - * returns the interrupt number being used by the chip. ISDN4linux - * uses this number to watch the interrupt during initialization and - * make sure something is happening. - * - * int get_liu_state(int dev) - * - * returns the current state of the ISDN Line Interface Unit (LIU) - * as a number between 2 (state F2) and 7 (state F7). 0 may also be - * returned if the chip doesn't exist or the LIU hasn't been - * activated. The meanings of the states are defined in I.430, ISDN - * BRI Physical Layer Interface. The most important two states are - * F3 (shutdown) and F7 (syncronized). - * - * void liu_init(int dev, void (*callback)(void *), void *callback_arg) - * - * initializes the LIU and optionally registers a callback to be - * signaled upon a change of LIU state. The callback will be called - * with a single opaque callback_arg. Once the callback has been - * triggered, get_liu_state can be used to determine the LIU - * current state. - * - * void liu_activate(int dev, int priority) - * - * requests LIU activation at a given D-channel priority. - * Successful activatation is achieved upon entering state F7, which - * will trigger any callback previously registered with - * liu_init. - * - * void liu_deactivate(int dev) - * - * deactivates LIU. Outstanding D and B channel transactions are - * terminated rudely and without callback notification. LIU change - * of state callback will be triggered, however. - * - * void dxmit(int dev, __u8 *buffer, unsigned int count, - * void (*callback)(void *, int), void *callback_arg) - * - * transmits a packet - specified with buffer, count - over the D-channel - * interface. Buffer should begin with the LAPD address field and - * end with the information field. FCS and flag sequences should not - * be included, nor is bit-stuffing required - all these functions are - * performed by the chip. The callback function will be called - * DURING THE TOP HALF OF AN INTERRUPT HANDLER and will be passed - * both the arbitrary callback_arg and an integer error indication: - * - * 0 - successful transmission; ready for next packet - * non-0 - error value - * - * The callback routine should defer any time-consuming operations - * to a bottom-half handler; however, dxmit may be called - * from within the callback to request back-to-back transmission of - * a second packet (without repeating the priority/collision mechanism) - * - * A comment about the "collision detect" error, which is signalled - * whenever the echoed D-channel data didn't match the transmitted - * data. This is part of ISDN's normal multi-drop T-interface - * operation, indicating that another device has attempted simultaneous - * transmission, but can also result from line noise. An immediate - * requeue via dxmit is suggested, but repeated collision - * errors may indicate a more serious problem. - * - * void drecv(int dev, __u8 *buffer, unsigned int size, - * void (*callback)(void *, int, unsigned int), - * void *callback_arg) - * - * register a buffer - buffer, size - into which a D-channel packet - * can be received. The callback function will be called DURING - * THE TOP HALF OF AN INTERRUPT HANDLER and will be passed an - * arbitrary callback_arg, an integer error indication and the length - * of the received packet, which will start with the address field, - * end with the information field, and not contain flag or FCS - * bytes. Bit-stuffing will already have been corrected for. - * Possible values of second callback argument "error": - * - * 0 - successful reception - * non-0 - error value - * - * int bopen(int dev, int chan, int hdlcmode, u_char xmit_idle_char) - * - * This function should be called before any other operations on a B - * channel. mode is either non-0 to (de)encapsulate using HDLC or 0 - * for transparent operation. In addition to arranging for interrupt - * handling and channel multiplexing, it sets the xmit_idle_char - * which is transmitted on the interface when no data buffer is - * available. Suggested values are: 0 for ISDN audio; FF for HDLC - * mark idle; 7E for HDLC flag idle. Returns 0 on a successful - * open; -1 on error. - * - * If the chip doesn't support HDLC encapsulation (the Am7930 - * doesn't), an error will be returned opening L1_MODE_HDLC; the - * HiSax driver should retry with L1_MODE_TRANS, then be prepared to - * bit-stuff the data before shipping it to the driver. - * - * void bclose(int dev, int chan) - * - * Shuts down a B channel when no longer in use. - * - * void bxmit(int dev, int chan, __u8 *buffer, unsigned int count, - * void (*callback)(void *, int), void *callback_arg) - * - * transmits a data block - specified with buffer, count - over the - * B channel interface specified by dev/chan. In mode L1_MODE_HDLC, - * a complete HDLC frames should be relayed with a single bxmit. - * The callback function will be called DURING THE TOP HALF OF AN - * INTERRUPT HANDLER and will be passed the arbitrary callback_arg - * and an integer error indication: - * - * 0 - successful transmission; ready for next packet - * non-0 - error - * - * The callback routine should defer any time-consuming operations - * to a bottom-half handler; however, bxmit may be called - * from within the callback to request back-to-back transmission of - * another data block - * - * void brecv(int dev, int chan, __u8 *buffer, unsigned int size, - * void (*callback)(void *, int, unsigned int), void *callback_arg) - * - * receive a raw data block - specified with buffer, size - over the - * B channel interface specified by dev/chan. The callback function - * will be called DURING THE TOP HALF OF AN INTERRUPT HANDLER and - * will be passed the arbitrary callback_arg, an integer error - * indication and the length of the received packet. In HDLC mode, - * the packet will start with the address field, end with the - * information field, and will not contain flag or FCS bytes. - * Bit-stuffing will already have been corrected for. - * - * Possible values of second callback argument "error": - * - * 0 - successful reception - * non-0 - error value - * - * The callback routine should defer any time-consuming operations - * to a bottom-half handler; however, brecv may be called - * from within the callback to register another buffer and ensure - * continuous B channel reception without loss of data - * */ - -struct foreign_interface { - int (*get_irqnum)(int dev); - int (*get_liu_state)(int dev); - void (*liu_init)(int dev, void (*callback)(void *), void *callback_arg); - void (*liu_activate)(int dev, int priority); - void (*liu_deactivate)(int dev); - void (*dxmit)(int dev, __u8 *buffer, unsigned int count, - void (*callback)(void *, int), - void *callback_arg); - void (*drecv)(int dev, __u8 *buffer, unsigned int size, - void (*callback)(void *, int, unsigned int), - void *callback_arg); - int (*bopen)(int dev, unsigned int chan, - int hdlcmode, u_char xmit_idle_char); - void (*bclose)(int dev, unsigned int chan); - void (*bxmit)(int dev, unsigned int chan, - __u8 *buffer, unsigned long count, - void (*callback)(void *, int), - void *callback_arg); - void (*brecv)(int dev, unsigned int chan, - __u8 *buffer, unsigned long size, - void (*callback)(void *, int, unsigned int), - void *callback_arg); - - struct foreign_interface *next; -}; - -extern struct foreign_interface amd7930_foreign_interface; -extern struct foreign_interface dbri_foreign_interface; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c --- v2.2.10/linux/drivers/isdn/hisax/fsm.c Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/fsm.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: fsm.c,v 1.7 1997/11/06 17:09:13 keil Exp $ +/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $ * Author Karsten Keil (keil@temic-ech.spacenet.de) * based on the teles driver from Jan den Ouden @@ -7,6 +7,18 @@ * Fritz Elfert * * $Log: fsm.c,v $ + * Revision 1.10 1998/11/15 23:54:39 keil + * changes from 2.0 + * + * Revision 1.9 1998/03/26 07:10:02 paul + * The jumpmatrix table in struct Fsm was an array of "int". This is not + * large enough for pointers to functions on Linux/Alpha (instant crash + * on "insmod hisax). Now there is a typedef for the pointer to function. + * This also prevents warnings about "incompatible pointer types". + * + * Revision 1.8 1998/03/07 22:56:59 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.7 1997/11/06 17:09:13 keil * New 2.1 init code * @@ -41,18 +53,18 @@ { int i; - fsm->jumpmatrix = (int *) - kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL); - memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count); + fsm->jumpmatrix = (FSMFNPTR *) + kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL); + memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count); for (i = 0; i < fncount; i++) if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) { - printk(KERN_ERR "FsmNew Error line %d st(%d/%d) ev(%d/%d)\n", - i,fnlist[i].state,fsm->state_count, - fnlist[i].event,fsm->event_count); + printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n", + i,(long)fnlist[i].state,(long)fsm->state_count, + (long)fnlist[i].event,(long)fsm->event_count); } else fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (int) fnlist[i].routine; + fnlist[i].state] = (FSMFNPTR) fnlist[i].routine; } void @@ -64,31 +76,26 @@ int FsmEvent(struct FsmInst *fi, int event, void *arg) { - void (*r) (struct FsmInst *, int, void *); - char str[80]; + FSMFNPTR r; if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) { - printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n", - fi->state,fi->fsm->state_count,event,fi->fsm->event_count); + printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", + (long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count); return(1); } - r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; + r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; if (r) { - if (fi->debug) { - sprintf(str, "State %s Event %s", + if (fi->debug) + fi->printdebug(fi, "State %s Event %s", fi->fsm->strState[fi->state], fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } r(fi, event, arg); return (0); } else { - if (fi->debug) { - sprintf(str, "State %s Event %s no routine", + if (fi->debug) + fi->printdebug(fi, "State %s Event %s no routine", fi->fsm->strState[fi->state], fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } return (!0); } } @@ -96,25 +103,18 @@ void FsmChangeState(struct FsmInst *fi, int newstate) { - char str[80]; - fi->state = newstate; - if (fi->debug) { - sprintf(str, "ChangeState %s", + if (fi->debug) + fi->printdebug(fi, "ChangeState %s", fi->fsm->strState[newstate]); - fi->printdebug(fi, str); - } } static void FsmExpireTimer(struct FsmTimer *ft) { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmExpireTimer %lx", (long) ft); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); #endif FsmEvent(ft->fi, ft->event, ft->arg); } @@ -126,11 +126,8 @@ ft->tl.function = (void *) FsmExpireTimer; ft->tl.data = (long) ft; #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmInitTimer %lx", (long) ft); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft); #endif init_timer(&ft->tl); } @@ -139,11 +136,8 @@ FsmDelTimer(struct FsmTimer *ft, int where) { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmDelTimer %lx %d", (long) ft, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where); #endif del_timer(&ft->tl); } @@ -154,11 +148,9 @@ { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d", + (long) ft, millisec, where); #endif if (ft->tl.next || ft->tl.prev) { @@ -180,11 +172,9 @@ { #if FSM_TIMER_DEBUG - if (ft->fi->debug) { - char str[40]; - sprintf(str, "FsmRestartTimer %lx %d %d", (long) ft, millisec, where); - ft->fi->printdebug(ft->fi, str); - } + if (ft->fi->debug) + ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d", + (long) ft, millisec, where); #endif if (ft->tl.next || ft->tl.prev) @@ -194,25 +184,4 @@ ft->arg = arg; ft->tl.expires = jiffies + (millisec * HZ) / 1000; add_timer(&ft->tl); -} - -void -jiftime(char *s, long mark) -{ - s += 8; - - *s-- = '\0'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = '.'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 6 + '0'; - mark /= 6; - *s-- = ':'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.2.10/linux/drivers/isdn/hisax/gazel.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/gazel.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,745 @@ +/* $Id: gazel.c,v 2.3 1999/07/12 21:05:09 keil Exp $ + + * gazel.c low level stuff for Gazel isdn cards + * + * Author BeWan Systems + * based on source code from Karsten Keil + * + * $Log: gazel.c,v $ + * Revision 2.3 1999/07/12 21:05:09 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.1 1999/07/08 21:26:17 keil + * new card + * + * Revision 1.0 1999/28/06 + * Initial revision + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "isdnl1.h" +#include "ipac.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif + +extern const char *CardType[]; +const char *gazel_revision = "$Revision: 2.3 $"; + +#define R647 1 +#define R685 2 +#define R753 3 +#define R742 4 + +/* Gazel R685 stuff */ +#define GAZEL_MANUFACTURER 0x10b5 +#define GAZEL_R685 0x1030 +#define GAZEL_R753 0x1152 +#define GAZEL_DJINN_ITOO 0x1151 + +#define PLX_CNTRL 0x50 /* registre de controle PLX */ +#define RESET_GAZEL 0x4 +#define RESET_9050 0x40000000 +#define PLX_INCSR 0x4C /* registre d'IT du 9050 */ +#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */ +#define INT_ISAC 0x20 /* 1 = IT isac en cours */ +#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */ +#define INT_HSCX 0x4 /* 1 = IT hscx en cours */ +#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */ +#define INT_IPAC_EN 0x3 /* enable IT ipac */ + + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +static inline u_char +readreg(unsigned int adr, u_short off) +{ + return bytein(adr + off); +} + +static inline void +writereg(unsigned int adr, u_short off, u_char data) +{ + byteout(adr + off, data); +} + + +static inline void +read_fifo(unsigned int adr, u_char * data, int size) +{ + insb(adr, data, size); +} + +static void +write_fifo(unsigned int adr, u_char * data, int size) +{ + outsb(adr, data, size); +} + +static inline u_char +readreg_ipac(unsigned int adr, u_short off) +{ + register u_char ret; + long flags; + + save_flags(flags); + cli(); + byteout(adr, off); + ret = bytein(adr + 4); + restore_flags(flags); + return ret; +} + +static inline void +writereg_ipac(unsigned int adr, u_short off, u_char data) +{ + long flags; + + save_flags(flags); + cli(); + byteout(adr, off); + byteout(adr + 4, data); + restore_flags(flags); +} + + +static inline void +read_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size) +{ + byteout(adr, off); + insb(adr + 4, data, size); +} + +static void +write_fifo_ipac(unsigned int adr, u_short off, u_char * data, int size) +{ + byteout(adr, off); + outsb(adr + 4, data, size); +} + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + return (readreg(cs->hw.gazel.isac, off2)); + case R753: + case R742: + return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2)); + } + return 0; +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + writereg(cs->hw.gazel.isac, off2, value); + break; + case R753: + case R742: + writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value); + break; + } +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + switch (cs->subtyp) { + case R647: + case R685: + read_fifo(cs->hw.gazel.isacfifo, data, size); + break; + case R753: + case R742: + read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); + break; + } +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + switch (cs->subtyp) { + case R647: + case R685: + write_fifo(cs->hw.gazel.isacfifo, data, size); + break; + case R753: + case R742: + write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); + break; + } +} + +static void +ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) +{ + switch (cs->subtyp) { + case R647: + case R685: + read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + break; + case R753: + case R742: + read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); + break; + } +} + +static void +WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size) +{ + switch (cs->subtyp) { + case R647: + case R685: + write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); + break; + case R753: + case R742: + write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); + break; + } +} + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + return (readreg(cs->hw.gazel.hscx[hscx], off2)); + case R753: + case R742: + return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2)); + } + return 0; +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + u_short off2 = offset; + + switch (cs->subtyp) { + case R647: + off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); + case R685: + writereg(cs->hw.gazel.hscx[hscx], off2, value); + break; + case R753: + case R742: + writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value); + break; + } +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) + +#include "hscx_irq.c" + +static void +gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 5 + struct IsdnCardState *cs = dev_id; + u_char valisac, valhscx; + int count = 0; + + if (!cs) { + printk(KERN_WARNING "Gazel: Spurious interrupt!\n"); + return; + } + do { + valhscx = ReadHSCX(cs, 1, HSCX_ISTA); + if (valhscx) + hscx_int_main(cs, valhscx); + valisac = ReadISAC(cs, ISAC_ISTA); + if (valisac) + isac_interrupt(cs, valisac); + count++; + } while ((valhscx || valisac) && (count < MAXCOUNT)); + + WriteHSCX(cs, 0, HSCX_MASK, 0xFF); + WriteHSCX(cs, 1, HSCX_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0x0); + WriteHSCX(cs, 0, HSCX_MASK, 0x0); + WriteHSCX(cs, 1, HSCX_MASK, 0x0); +} + + +static void +gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val; + int count = 0; + + if (!cs) { + printk(KERN_WARNING "Gazel: Spurious interrupt!\n"); + return; + } + ista = ReadISAC(cs, IPAC_ISTA - 0x80); + do { + if (ista & 0x0f) { + val = ReadHSCX(cs, 1, HSCX_ISTA); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) { + hscx_int_main(cs, val); + } + } + if (ista & 0x20) { + val = 0xfe & ReadISAC(cs, ISAC_ISTA); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); + } + ista = ReadISAC(cs, IPAC_ISTA - 0x80); + count++; + } + while ((ista & 0x3f) && (count < MAXCOUNT)); + + WriteISAC(cs, IPAC_MASK - 0x80, 0xFF); + WriteISAC(cs, IPAC_MASK - 0x80, 0xC0); +} +void +release_io_gazel(struct IsdnCardState *cs) +{ + unsigned int i; + + switch (cs->subtyp) { + case R647: + for (i = 0x0000; i < 0xC000; i += 0x1000) + release_region(i + cs->hw.gazel.hscx[0], 16); + release_region(0xC000 + cs->hw.gazel.hscx[0], 1); + break; + + case R685: + release_region(cs->hw.gazel.hscx[0], 0x100); + release_region(cs->hw.gazel.cfg_reg, 0x80); + break; + + case R753: + release_region(cs->hw.gazel.ipac, 0x8); + release_region(cs->hw.gazel.cfg_reg, 0x80); + break; + + case R742: + release_region(cs->hw.gazel.ipac, 8); + break; + } +} + +static int +reset_gazel(struct IsdnCardState *cs) +{ + long flags; + unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; + + switch (cs->subtyp) { + case R647: + save_flags(flags); + cli(); + writereg(addr, 0, 0); + HZDELAY(10); + writereg(addr, 0, 1); + HZDELAY(2); + restore_flags(flags); + break; + case R685: + plxcntrl = inl(addr + PLX_CNTRL); + plxcntrl |= (RESET_9050 + RESET_GAZEL); + outl(plxcntrl, addr + PLX_CNTRL); + plxcntrl &= ~(RESET_9050 + RESET_GAZEL); + HZDELAY(4); + outl(plxcntrl, addr + PLX_CNTRL); + HZDELAY(10); + outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); + break; + case R753: + plxcntrl = inl(addr + PLX_CNTRL); + plxcntrl |= (RESET_9050 + RESET_GAZEL); + outl(plxcntrl, addr + PLX_CNTRL); + plxcntrl &= ~(RESET_9050 + RESET_GAZEL); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); + HZDELAY(4); + outl(plxcntrl, addr + PLX_CNTRL); + HZDELAY(10); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); + WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); + WriteISAC(cs, IPAC_AOE - 0x80, 0x0); + WriteISAC(cs, IPAC_MASK - 0x80, 0xff); + WriteISAC(cs, IPAC_CONF - 0x80, 0x1); + outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); + WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); + break; + case R742: + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); + HZDELAY(4); + WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); + WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); + WriteISAC(cs, IPAC_AOE - 0x80, 0x0); + WriteISAC(cs, IPAC_MASK - 0x80, 0xff); + WriteISAC(cs, IPAC_CONF - 0x80, 0x1); + WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); + break; + } + return (0); +} + +static int +Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_gazel(cs); + return (0); + case CARD_RELEASE: + release_io_gazel(cs); + return (0); + case CARD_INIT: + inithscxisac(cs, 1); + if ((cs->subtyp==R647)||(cs->subtyp==R685)) { + int i; + for (i=0;i<(2+MAX_WAITING_CALLS);i++) { + cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; + cs->bcs[i].hw.hscx.tsaxr1 = 0x23; + } + } + return (0); + case CARD_TEST: + return (0); + } + return (0); +} + +static int +reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) +{ + unsigned int i, base = 0, adr = 0, len = 0; + long flags; + + save_flags(flags); + cli(); + + switch (cs->subtyp) { + case R647: + base = cs->hw.gazel.hscx[0]; + for (i = 0x0000; i < 0xC000; i += 0x1000) { + if (check_region(adr = (i + base), len = 16)) + goto error; + } + if (check_region(adr = (0xC000 + base), len = 1)) + goto error; + + for (i = 0x0000; i < 0xC000; i += 0x1000) + request_region(i + base, 16, "gazel"); + request_region(0xC000 + base, 1, "gazel"); + + break; + + case R685: + if (check_region(adr = cs->hw.gazel.hscx[0], len = 0x100)) + goto error; + if (check_region(adr = cs->hw.gazel.cfg_reg, len = 0x80)) + goto error; + + request_region(cs->hw.gazel.hscx[0], 0x100, "gazel"); + request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel"); + break; + + case R753: + if (check_region(adr = cs->hw.gazel.ipac, len = 0x8)) + goto error; + if (check_region(adr = cs->hw.gazel.cfg_reg, len = 0x80)) + goto error; + + request_region(cs->hw.gazel.ipac, 0x8, "gazel"); + request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel"); + break; + + case R742: + if (check_region(adr = cs->hw.gazel.ipac, len = 0x8)) + goto error; + request_region(cs->hw.gazel.ipac, 0x8, "gazel"); + break; + } + + restore_flags(flags); + return 0; + + error: + restore_flags(flags); + printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n", + CardType[cs->typ], adr, adr + len); + return 1; +} + +static int +setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) +{ + printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n"); + // we got an irq parameter, assume it is an ISA card + // R742 decodes address even in not started... + // R647 returns FF if not present or not started + // eventually needs improvment + if (readreg_ipac(card->para[1], IPAC_ID) == 1) + cs->subtyp = R742; + else + cs->subtyp = R647; + + cs->hw.gazel.cfg_reg = card->para[1] + 0xC000; + cs->hw.gazel.ipac = card->para[1]; + cs->hw.gazel.isac = card->para[1] + 0x8000; + cs->hw.gazel.hscx[0] = card->para[1]; + cs->hw.gazel.hscx[1] = card->para[1] + 0x4000; + cs->irq = card->para[0]; + cs->hw.gazel.isacfifo = cs->hw.gazel.isac; + cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; + cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; + + switch (cs->subtyp) { + case R647: + printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n"); + cs->dc.isac.adf2 = 0x87; + printk(KERN_INFO + "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); + printk(KERN_INFO + "Gazel: hscx A:0x%X hscx B:0x%X\n", + cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); + + break; + case R742: + printk(KERN_INFO "Gazel: Card ISA R742 found\n"); + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + printk(KERN_INFO + "Gazel: config irq:%d ipac:0x%X\n", + cs->irq, cs->hw.gazel.ipac); + break; + } + + return (0); +} + +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_tel __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +static int +setup_gazelpci(struct IsdnCardState *cs) +{ + u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0; + u_char pci_irq = 0, found; + u_int nbseek, seekcard; + + printk(KERN_WARNING "Gazel: PCI card automatic recognition\n"); + + found = 0; +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_WARNING "Gazel: No PCI bus present\n"); + return 1; + } +#endif + seekcard = GAZEL_R685; + for (nbseek = 0; nbseek < 3; nbseek++) { +#ifdef COMPAT_HAS_NEW_PCI + if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) { + + pci_irq = dev_tel->irq; + pci_ioaddr0 = dev_tel->base_address[1]; + pci_ioaddr1 = dev_tel->base_address[2]; + found = 1; + } +#else + for (; pci_index < 0xff; pci_index++) { + u_char pci_bus, pci_device_fn; + + if (pcibios_find_device(GAZEL_MANUFACTURER, seekcard, + pci_index, &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + /* get IRQ */ + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq); + /* get IO address */ + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &pci_ioaddr0); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_2, &pci_ioaddr1); + found = 1; + break; + } +#endif /* COMPAT_HAS_NEW_PCI */ + if (found) + break; + else { + switch (seekcard) { + case GAZEL_R685: + seekcard = GAZEL_R753; + break; + case GAZEL_R753: + seekcard = GAZEL_DJINN_ITOO; + break; + } +#ifndef COMPAT_HAS_NEW_PCI + pci_index = 0; +#endif + } + } + if (!found) { + printk(KERN_WARNING "Gazel: No PCI card found\n"); + return (1); + } + if (!pci_irq) { + printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n"); + return 1; + } + cs->hw.gazel.pciaddr[0] = pci_ioaddr0; + cs->hw.gazel.pciaddr[1] = pci_ioaddr1; + + pci_ioaddr1 &= 0xfffe; + cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe; + cs->hw.gazel.ipac = pci_ioaddr1; + cs->hw.gazel.isac = pci_ioaddr1 + 0x80; + cs->hw.gazel.hscx[0] = pci_ioaddr1; + cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40; + cs->hw.gazel.isacfifo = cs->hw.gazel.isac; + cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; + cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; + cs->irq = pci_irq; + cs->irq_flags |= SA_SHIRQ; + + switch (seekcard) { + case GAZEL_R685: + printk(KERN_INFO "Gazel: Card PCI R685 found\n"); + cs->subtyp = R685; + cs->dc.isac.adf2 = 0x87; + printk(KERN_INFO + "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); + printk(KERN_INFO + "Gazel: hscx A:0x%X hscx B:0x%X\n", + cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); + break; + case GAZEL_R753: + case GAZEL_DJINN_ITOO: + printk(KERN_INFO "Gazel: Card PCI R753 found\n"); + cs->subtyp = R753; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + printk(KERN_INFO + "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n", + cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg); + break; + } + + return (0); +} + +__initfunc(int + setup_gazel(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + u_char val; + + strcpy(tmp, gazel_revision); + printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_GAZEL) + return (0); + + if (card->para[0]) { + if (setup_gazelisa(card, cs)) + return (0); + } else { + +#if CONFIG_PCI + if (setup_gazelpci(cs)) + return (0); +#else + printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n"); + return (0); +#endif /* CONFIG_PCI */ + } + + if (reserve_regions(card, cs)) { + return (0); + } + if (reset_gazel(cs)) { + printk(KERN_WARNING "Gazel: wrong IRQ\n"); + release_io_gazel(cs); + return (0); + } + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &Gazel_card_msg; + + switch (cs->subtyp) { + case R647: + case R685: + cs->irq_func = &gazel_interrupt; + ISACVersion(cs, "Gazel:"); + if (HscxVersion(cs, "Gazel:")) { + printk(KERN_WARNING + "Gazel: wrong HSCX versions check IO address\n"); + release_io_gazel(cs); + return (0); + } + break; + case R742: + case R753: + cs->irq_func = &gazel_interrupt_ipac; + val = ReadISAC(cs, IPAC_ID - 0x80); + printk(KERN_INFO "Gazel: IPAC version %x\n", val); + break; + } + + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.2.10/linux/drivers/isdn/hisax/hfc_2bds0.c Thu May 14 18:42:23 1998 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.3 1998/02/12 23:07:22 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.9 1999/07/01 08:11:35 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -6,6 +6,25 @@ * * * $Log: hfc_2bds0.c,v $ + * Revision 1.9 1999/07/01 08:11:35 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.8 1998/11/15 23:54:40 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:45 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:26 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/06/27 22:52:58 keil + * make 16.3c working with 3.0 + * + * Revision 1.4 1998/05/25 12:57:52 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.3 1998/02/12 23:07:22 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -46,11 +65,8 @@ } ret = bytein(cs->hw.hfcD.addr); #if HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "t3c RD %02x %02x", reg, ret); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "t3c RD %02x %02x", reg, ret); #endif } else ret = bytein(cs->hw.hfcD.addr | 1); @@ -67,11 +83,8 @@ if (data) byteout(cs->hw.hfcD.addr, value); #if HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) { - char tmp[16]; - sprintf(tmp, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) + debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); #endif } @@ -227,7 +240,6 @@ int chksum; long flags; u_char stat, cip; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -255,6 +267,7 @@ } else if (!(skb = dev_alloc_skb(count - 3))) printk(KERN_WARNING "HFC: receive out of memory\n"); else { + SET_SKB_FREE(skb); ptr = skb_put(skb, count - 3); idx = 0; cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); @@ -272,7 +285,7 @@ sti(); debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); skb = NULL; } else { cli(); @@ -283,14 +296,12 @@ WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); skb = NULL; } } @@ -315,14 +326,11 @@ int idx, fcnt; int count; u_char cip; - char tmp[64]; - - if (!bcs->hw.hfc.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hfc.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; - save_flags(flags); cli(); SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); @@ -335,12 +343,10 @@ bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); sti(); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); - debugl1(cs, tmp); - } fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; @@ -351,13 +357,11 @@ return; } count = GetFreeFifoBytes_B(bcs); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d count(%d/%d),%lx", - bcs->channel, bcs->hw.hfc.tx_skb->len, + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx", + bcs->channel, bcs->tx_skb->len, count, current->state); - debugl1(cs, tmp); - } - if (count < bcs->hw.hfc.tx_skb->len) { + if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); restore_flags(flags); @@ -368,26 +372,26 @@ cli(); WaitForBusy(cs); WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]); - while (idx < bcs->hw.hfc.tx_skb->len) { + WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); + while (idx < bcs->tx_skb->len) { cli(); if (!WaitNoBusy(cs)) break; - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx]); + WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]); sti(); idx++; } - if (idx != bcs->hw.hfc.tx_skb->len) { + if (idx != bcs->tx_skb->len) { sti(); debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { - bcs->tx_cnt -= bcs->hw.hfc.tx_skb->len; + bcs->tx_cnt -= bcs->tx_skb->len; if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.hfc.tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hfc.tx_skb->len); - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; } WaitForBusy(cs); cli(); @@ -404,15 +408,12 @@ hfc_send_data(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; - char tmp[32]; if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"send_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"send_data %d blocked", bcs->channel); } void @@ -424,15 +425,13 @@ u_char f1, f2, cip; int receive, count = 5; struct sk_buff *skb; - char tmp[64]; save_flags(flags); Begin: count--; cli(); if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - sprintf(tmp,"rec_data %d blocked", bcs->channel); - debugl1(cs, tmp); + debugl1(cs,"rec_data %d blocked", bcs->channel); restore_flags(flags); return; } @@ -445,11 +444,9 @@ f2 = ReadReg(cs, HFCD_DATA, cip); sti(); if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } cli(); z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); @@ -458,11 +455,9 @@ if (rcnt < 0) rcnt += cs->hw.hfcD.bfifosize; rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } if ((skb = hfc_empty_fifo(bcs, rcnt))) { cli(); skb_queue_tail(&bcs->rqueue, skb); @@ -490,12 +485,9 @@ { struct IsdnCardState *cs = bcs->cs; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "HFCD bchannel mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFCD bchannel mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; bcs->channel = bc; switch (mode) { @@ -543,122 +535,99 @@ long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hfc.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; /* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); /* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); -*/ st->l1.bcs->hw.hfc.tx_skb = skb; +*/ st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_2bs0(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } void close_2bs0(struct BCState *bcs) { - struct sk_buff *skb; - - mode_2bs0(bcs, 0, 0); + mode_2bs0(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.hfc.tx_skb) { - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } static int -open_hfcstate(struct IsdnCardState *cs, - int bc) +open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hfc.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->tx_cnt = 0; return (0); } -static void -hfc_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_2bs0(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_2b(struct PStack *st, struct BCState *bcs) { - if (open_hfcstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hfc_l2l1; - st->ma.manl1 = hfc_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } static void -manl1_msg(struct IsdnCardState *cs, int msg, void *arg) { - struct PStack *st; - - st = cs->stlist; - while (st) { - st->ma.manl1(st, msg, arg); - st = st->next; - } -} - -static void hfcd_bh(struct IsdnCardState *cs) { /* struct PStack *stptr; @@ -671,27 +640,27 @@ debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } #endif if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - switch (cs->ph_state) { + switch (cs->dc.hfcd.ph_state) { case (0): - manl1_msg(cs, PH_RESET_IND, NULL); + l1_msg(cs, HW_RESET | INDICATION, NULL); break; case (3): - manl1_msg(cs, PH_DEACT_IND, NULL); + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); break; case (8): - manl1_msg(cs, PH_RSYNC_IND, NULL); + l1_msg(cs, HW_RSYNC | INDICATION, NULL); break; case (6): - manl1_msg(cs, PH_INFO2_IND, NULL); + l1_msg(cs, HW_INFO2 | INDICATION, NULL); break; case (7): - manl1_msg(cs, PH_I4_P8_IND, NULL); + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; default: break; @@ -722,7 +691,6 @@ int chksum; int count=5; u_char *ptr; - char tmp[64]; save_flags(flags); cli(); @@ -745,11 +713,9 @@ if (rcnt < 0) rcnt += cs->hw.hfcD.dfifosize; rcnt++; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", f1, f2, z1, z2, rcnt); - debugl1(cs, tmp); - } sti(); idx = 0; cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC; @@ -771,6 +737,7 @@ while ((idx++ < rcnt) && WaitNoBusy(cs)) ReadReg(cs, HFCD_DATA_NODEB, cip); } else if ((skb = dev_alloc_skb(rcnt - 3))) { + SET_SKB_FREE(skb); ptr = skb_put(skb, rcnt - 3); while (idx < (rcnt - 3)) { cli(); @@ -785,7 +752,7 @@ sti(); debugl1(cs, "RFIFO D BUSY error"); printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); skb = NULL; } else { cli(); @@ -796,14 +763,12 @@ WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "empty_dfifo chksum %x stat %x", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "empty_dfifo chksum %x stat %x", chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); skb = NULL; } else { skb_queue_tail(&cs->rq, skb); @@ -837,7 +802,6 @@ int idx, fcnt; int count; u_char cip; - char tmp[64]; if (!cs->tx_skb) return; @@ -855,12 +819,10 @@ cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf; cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND); sti(); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", cs->hw.hfcD.f1, cs->hw.hfcD.f2, cs->hw.hfcD.send[cs->hw.hfcD.f1]); - debugl1(cs, tmp); - } fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2; if (fcnt < 0) fcnt += 16; @@ -871,11 +833,9 @@ return; } count = GetFreeFifoBytes_D(cs); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "hfc_fill_Dfifo count(%d/%d)", + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)", cs->tx_skb->len, count); - debugl1(cs, tmp); - } if (count < cs->tx_skb->len) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfc_fill_Dfifo no fifo mem"); @@ -905,7 +865,7 @@ cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb(cs->tx_skb); + idev_kfree_skb(cs->tx_skb, FREE_WRITE); cs->tx_skb = NULL; sti(); WaitForBusy(cs); @@ -929,25 +889,20 @@ { u_char exval; struct BCState *bcs; - char tmp[32]; int count=15; long flags; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "HFCD irq %x %s", val, + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCD irq %x %s", val, test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? "locked" : "unlocked"); - debugl1(cs, tmp); - } val &= cs->hw.hfcD.int_m1; if (val & 0x40) { /* TE state machine irq */ exval = cs->readisac(cs, HFCD_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ph_state chg %d->%d", cs->ph_state, + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state, exval); - debugl1(cs, tmp); - } - cs->ph_state = exval; + cs->dc.hfcd.ph_state = exval; sched_event_D(cs, D_L1STATECHANGE); val &= ~0x40; } @@ -983,23 +938,19 @@ if (cs->debug) debugl1(cs, "hfcd spurious 0x01 IRQ"); } else { - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } @@ -1011,23 +962,19 @@ if (cs->debug) debugl1(cs, "hfcd spurious 0x02 IRQ"); } else { - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - sprintf(tmp,"fill_data %d blocked", bcs->channel); - debugl1(cs, tmp); - } + } else + debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } @@ -1052,7 +999,7 @@ } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + idev_kfree_skb(cs->tx_skb, FREE_WRITE); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1072,10 +1019,8 @@ if (cs->hw.hfcD.int_s1 && count--) { val = cs->hw.hfcD.int_s1; cs->hw.hfcD.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "HFCD irq %x loop %d", val, 15-count); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCD irq %x loop %d", val, 15-count); } else val = 0; restore_flags(flags); @@ -1083,13 +1028,17 @@ } static void -HFCD_l2l1(struct PStack *st, int pr, void *arg) +HFCD_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - char str[64]; + switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ @@ -1097,12 +1046,6 @@ Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -1117,19 +1060,17 @@ } break; - case (PH_PULL_IND): + case (PH_PULL | INDICATION): if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); break; } - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -1142,47 +1083,39 @@ } else debugl1(cs, "hfc_fill_dfifo blocked"); break; - case (PH_PULL_REQ): + case (PH_PULL | REQUEST): #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); #endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; - } -} - -void -hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg) -{ - char tmp[32]; - switch(msg) { - case PH_RESET_REQ: + case (HW_RESET | REQUEST): cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - manl1_msg(cs, PH_POWERUP_CNF, NULL); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; - case PH_ENABLE_REQ: + case (HW_ENABLE | REQUEST): cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); break; - case PH_DEACT_ACK: + case (HW_DEACTIVATE | REQUEST): cs->hw.hfcD.mst_m &= ~HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; - case PH_INFO3_REQ: + case (HW_INFO3 | REQUEST): cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; #if 0 - case PH_TESTLOOP_REQ: + case (HW_TESTLOOP | REQUEST): u_char val = 0; if (1 & (int) arg) val |= 0x0c; @@ -1208,10 +1141,8 @@ break; #endif default: - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "hfcd_l1cmd unknown %4x", msg); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcd_l1hw unknown pr %4x", pr); break; } } @@ -1219,7 +1150,7 @@ void setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) { - st->l2.l2l1 = HFCD_l2l1; + st->l1.l1hw = HFCD_l1hw; } static void @@ -1234,7 +1165,7 @@ stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } @@ -1260,7 +1191,6 @@ init2bds0(struct IsdnCardState *cs)) { cs->setstack_d = setstack_hfcd; - cs->l1cmd = hfcd_l1cmd; cs->dbusytimer.function = (void *) hfc_dbusy_timer; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.2.10/linux/drivers/isdn/hisax/hfc_2bs0.c Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,27 @@ -/* $Id: hfc_2bs0.c,v 1.4 1998/02/12 23:07:29 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.9 1999/07/01 08:11:36 keil Exp $ * specific routines for CCD's HFC 2BS0 * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hfc_2bs0.c,v $ + * Revision 1.9 1999/07/01 08:11:36 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.8 1998/11/15 23:54:43 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:46 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:28 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/05/25 12:57:54 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.4 1998/02/12 23:07:29 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -109,7 +125,6 @@ int idx, cnt; int rcnt, z1, z2; u_char cip, f1, f2; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_clear_fifo"); @@ -129,21 +144,17 @@ z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); cnt = 32; while (((f1 != f2) || (z1 != z2)) && cnt--) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc clear %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc clear %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; if (rcnt) rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc clear %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); idx = 0; while ((idx < rcnt) && WaitNoBusy(cs)) { @@ -180,7 +191,6 @@ int idx; int chksum; u_char stat, cip; - char tmp[64]; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); @@ -212,6 +222,7 @@ if (!(skb = dev_alloc_skb(count - 3))) printk(KERN_WARNING "HFC: receive out of memory\n"); else { + SET_SKB_FREE(skb); ptr = skb_put(skb, count - 3); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); @@ -222,7 +233,7 @@ if (idx != count - 3) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); @@ -235,14 +246,12 @@ chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_empty_fifo %d chksum %x stat %x", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); - debugl1(cs, tmp); - } if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); skb = NULL; } WaitNoBusy(cs); @@ -261,11 +270,10 @@ int idx, fcnt; int count; u_char cip; - char tmp[64]; - if (!bcs->hw.hfc.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hfc.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; save_flags(flags); @@ -281,12 +289,10 @@ WaitNoBusy(cs); bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); - debugl1(cs, tmp); - } fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; @@ -297,13 +303,11 @@ return; } count = GetFreeFifoBytes(bcs); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc_fill_fifo %d count(%d/%d)", - bcs->channel, bcs->hw.hfc.tx_skb->len, + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)", + bcs->channel, bcs->tx_skb->len, count); - debugl1(cs, tmp); - } - if (count < bcs->hw.hfc.tx_skb->len) { + if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); restore_flags(flags); @@ -311,18 +315,18 @@ } cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); idx = 0; - while ((idx < bcs->hw.hfc.tx_skb->len) && WaitNoBusy(cs)) - cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx++]); - if (idx != bcs->hw.hfc.tx_skb->len) { + while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) + cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); + if (idx != bcs->tx_skb->len) { debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { - count = bcs->hw.hfc.tx_skb->len; + count = bcs->tx_skb->len; bcs->tx_cnt -= count; - if (PACKET_NOACK == bcs->hw.hfc.tx_skb->pkt_type) + if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; WaitForBusy(cs); WaitNoBusy(cs); cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); @@ -343,7 +347,6 @@ u_char f1, f2, cip; int receive, transmit, count = 5; struct sk_buff *skb; - char tmp[64]; save_flags(flags); Begin: @@ -360,11 +363,9 @@ WaitNoBusy(cs); f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d f1(%d) f2(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); - debugl1(cs, tmp); - } WaitForBusy(cs); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); @@ -372,11 +373,9 @@ if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; rcnt++; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "hfc rec %d z1(%x) z2(%x) cnt(%d)", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); - debugl1(cs, tmp); - } /* sti(); */ if ((skb = hfc_empty_fifo(bcs, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); @@ -388,14 +387,14 @@ restore_flags(flags); udelay(1); cli(); - if (bcs->hw.hfc.tx_skb) { + if (bcs->tx_skb) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); if (test_bit(BC_FLG_BUSY, &bcs->Flag)) transmit = 0; } else { - if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); @@ -417,13 +416,11 @@ { struct IsdnCardState *cs = bcs->cs; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "HFC 2BS0 mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; + bcs->channel = bc; switch (mode) { case (L1_MODE_NULL): @@ -468,57 +465,66 @@ long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hfc.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - st->l1.bcs->hw.hfc.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hfc.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_hfc(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } + void close_hfcstate(struct BCState *bcs) { - struct sk_buff *skb; - - mode_hfc(bcs, 0, 0); + mode_hfc(bcs, 0, bcs->channel); if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.hfc.tx_skb) { - dev_kfree_skb(bcs->hw.hfc.tx_skb); - bcs->hw.hfc.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } @@ -526,50 +532,30 @@ } static int -open_hfcstate(struct IsdnCardState *cs, - int bc) +open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hfc.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->tx_cnt = 0; return (0); } -static void -hfc_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_hfc(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_hfc(struct PStack *st, struct BCState *bcs) { - if (open_hfcstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hfcstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hfc_l2l1; - st->ma.manl1 = hfc_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.2.10/linux/drivers/isdn/hisax/hfc_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/hfc_pci.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1498 @@ +/* $Id: hfc_pci.c,v 1.7 1999/07/14 21:24:20 werner Exp $ + + * hfc_pci.c low level driver for CCD´s hfc-pci based cards + * + * Author Werner Cornelius (werner@isdn4linux.de) + * based on existing driver for CCD hfc ISA cards + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * Copyright 1999 by Karsten Keil (keil@isdn4linux.de) + * + * 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, 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. + * + * $Log: hfc_pci.c,v $ + * Revision 1.7 1999/07/14 21:24:20 werner + * fixed memcpy problem when using E-channel feature + * + * Revision 1.6 1999/07/13 21:08:08 werner + * added echo channel logging feature. + * + * Revision 1.5 1999/07/12 21:05:10 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.4 1999/07/04 21:51:39 werner + * Changes to solve problems with irq sharing and smp machines + * Thanks to Karsten Keil and Alex Holden for giving aid with + * testing and debugging + * + * Revision 1.3 1999/07/01 09:43:19 keil + * removed additional schedules in timeouts + * + * Revision 1.2 1999/07/01 08:07:51 keil + * Initial version + * + * + * + */ + +#define __NO_VERSION__ +#include "hisax.h" +#include "hfc_pci.h" +#include "isdnl1.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif +#include + +extern const char *CardType[]; + +static const char *hfcpci_revision = "$Revision: 1.7 $"; + +#if CONFIG_PCI +/*****************************/ +/* release D- and B-channels */ +/*****************************/ +void +releasehfcpci(struct IsdnCardState *cs) +{ + if (cs->bcs[0].hw.hfc.send) { + kfree(cs->bcs[0].hw.hfc.send); + cs->bcs[0].hw.hfc.send = NULL; + } + if (cs->bcs[1].hw.hfc.send) { + kfree(cs->bcs[1].hw.hfc.send); + cs->bcs[1].hw.hfc.send = NULL; + } +} + +/******************************************/ +/* free hardware resources used by driver */ +/******************************************/ +void +release_io_hfcpci(struct IsdnCardState *cs) +{ +#if CONFIG_PCI + pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disabe memory mapped ports + busmaster */ +#endif /* CONFIG_PCI */ + releasehfcpci(cs); + del_timer(&cs->hw.hfcpci.timer); + kfree(cs->hw.hfcpci.share_start); + cs->hw.hfcpci.share_start = NULL; + vfree(cs->hw.hfcpci.pci_io); +} + +/********************************************************************************/ +/* function called to reset the HFC PCI chip. A complete software reset of chip */ +/* and fifos is done. */ +/********************************************************************************/ +static void +reset_hfcpci(struct IsdnCardState *cs) +{ + long flags; + + pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ + printk(KERN_INFO "HFC_PCI: resetting card\n"); + pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ + Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */ + Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */ + if (Read_hfc(cs, HFCPCI_STATUS) & 2) + printk(KERN_WARNING "HFC-PCI init bit busy\n"); + + cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */ + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); + + cs->hw.hfcpci.trm = 0; /* no echo connect */ + Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); + + Write_hfc(cs, HFCPCI_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ + cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; + Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ + cs->hw.hfcpci.bswapped = 0; /* no exchange */ + cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; + Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); + + cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE; + cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | + HFCPCI_INTS_L1STATE | HFCPCI_CLTIMER; + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); + + /* Clear already pending ints */ + if (Read_hfc(cs, HFCPCI_INT_S1)); + if (Read_hfc(cs, HFCPCI_INT_S2)); + + Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */ + udelay(10); + Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */ + cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */ + + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + cs->hw.hfcpci.sctrl = 0; + Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); + cs->hw.hfcpci.sctrl_r = 0; + Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); + restore_flags(flags); +} + +/***************************************************/ +/* Timer function called when kernel timer expires */ +/***************************************************/ +static void +hfcpci_Timer(struct IsdnCardState *cs) +{ + cs->hw.hfcpci.timer.expires = jiffies + 75; + /* WD RESET */ +/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80); + add_timer(&cs->hw.hfcpci.timer); + */ +} + + +/*********************************/ +/* schedule a new D-channel task */ +/*********************************/ +static void +sched_event_D_pci(struct IsdnCardState *cs, int event) +{ + test_and_set_bit(event, &cs->event); + queue_task(&cs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/*********************************/ +/* schedule a new b_channel task */ +/*********************************/ +static void +hfcpci_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + queue_task(&bcs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +/************************************************/ +/* select a b-channel entry matching and active */ +/************************************************/ +static +struct BCState * +Sel_BCS(struct IsdnCardState *cs, int channel) +{ + if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) + return (&cs->bcs[0]); + else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) + return (&cs->bcs[1]); + else + return (NULL); +} + +/*********************************************/ +/* read a complete B-frame out of the buffer */ +/*********************************************/ +static struct sk_buff +* +hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count) +{ + u_char *ptr, *ptr1, new_f2; + struct sk_buff *skb; + struct IsdnCardState *cs = bcs->cs; + int flags, total, maxlen, new_z2; + z_type *zp; + + save_flags(flags); + sti(); + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "hfcpci_empty_fifo"); + zp = &bz->za[bz->f2]; /* point to Z-Regs */ + new_z2 = zp->z2 + count; /* new position in fifo */ + if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z2 -= B_FIFO_SIZE; /* buffer wrap */ + new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; + if ((count > HSCX_BUFMAX + 3) || (count < 4) || + (*(bdata + (zp->z1 - B_SUB_VAL)))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); + bz->za[new_f2].z2 = new_z2; + bz->f2 = new_f2; /* next buffer */ + skb = NULL; + } else if (!(skb = dev_alloc_skb(count - 3))) + printk(KERN_WARNING "HFCPCI: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + total = count; + count -= 3; + ptr = skb_put(skb, count); + + if (zp->z1 >= zp->z2) + maxlen = count; /* complete transfer */ + else + maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ + + ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ + memcpy(ptr, ptr1, maxlen); /* copy data */ + count -= maxlen; + + if (count) { /* rest remaining */ + ptr += maxlen; + ptr1 = bdata; /* start of buffer */ + memcpy(ptr, ptr1, count); /* rest */ + } + bz->za[new_f2].z2 = new_z2; + bz->f2 = new_f2; /* next buffer */ + + } + restore_flags(flags); + return (skb); +} + +/*******************************/ +/* D-channel receive procedure */ +/*******************************/ +static +int +receive_dmsg(struct IsdnCardState *cs) +{ + struct sk_buff *skb; + int maxlen; + int rcnt, total; + int count = 5; + u_char *ptr, *ptr1; + dfifo_type *df; + z_type *zp; + + df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx; + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_dmsg blocked"); + return (1); + } + while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { + zp = &df->za[df->f2 & D_FREG_MASK]; + rcnt = zp->z1 - zp->z2; + if (rcnt < 0) + rcnt += D_FIFO_SIZE; + rcnt++; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", + df->f1, df->f2, zp->z1, zp->z2, rcnt); + + if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || + (df->data[zp->z1])) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]); + df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ + df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); + } else if ((skb = dev_alloc_skb(rcnt - 3))) { + SET_SKB_FREE(skb); + total = rcnt; + rcnt -= 3; + ptr = skb_put(skb, rcnt); + + if (zp->z1 >= zp->z2) + maxlen = rcnt; /* complete transfer */ + else + maxlen = D_FIFO_SIZE - zp->z2; /* maximum */ + + ptr1 = df->data + zp->z2; /* start of data */ + memcpy(ptr, ptr1, maxlen); /* copy data */ + rcnt -= maxlen; + + if (rcnt) { /* rest remaining */ + ptr += maxlen; + ptr1 = df->data; /* start of buffer */ + memcpy(ptr, ptr1, rcnt); /* rest */ + } + df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ + df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1); + + skb_queue_tail(&cs->rq, skb); + sched_event_D_pci(cs, D_RCVBUFREADY); + } else + printk(KERN_WARNING "HFC-PCI: D receive out of memory\n"); + } + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + return (1); +} + +/**********************************/ +/* B-channel main receive routine */ +/**********************************/ +void +main_rec_hfcpci(struct BCState *bcs) +{ + long flags; + struct IsdnCardState *cs = bcs->cs; + int rcnt; + int receive, count = 5; + struct sk_buff *skb; + bzfifo_type *bz; + u_char *bdata; + z_type *zp; + + + save_flags(flags); + if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { + bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; + bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; + } else { + bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; + bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1; + } + Begin: + count--; + cli(); + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "rec_data %d blocked", bcs->channel); + restore_flags(flags); + return; + } + sti(); + if (bz->f1 != bz->f2) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)", + bcs->channel, bz->f1, bz->f2); + zp = &bz->za[bz->f2]; + + rcnt = zp->z1 - zp->z2; + if (rcnt < 0) + rcnt += B_FIFO_SIZE; + rcnt++; + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)", + bcs->channel, zp->z1, zp->z2, rcnt); + if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) { + cli(); + skb_queue_tail(&bcs->rqueue, skb); + sti(); + hfcpci_sched_event(bcs, B_RCVBUFREADY); + } + rcnt = bz->f1 - bz->f2; + if (rcnt < 0) + rcnt += MAX_B_FRAMES + 1; + if (rcnt > 1) + receive = 1; + else + receive = 0; + } else + receive = 0; + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + if (count && receive) + goto Begin; + restore_flags(flags); + return; +} + +/**************************/ +/* D-channel send routine */ +/**************************/ +static void +hfcpci_fill_dfifo(struct IsdnCardState *cs) +{ + long flags; + int fcnt; + int count, new_z1, maxlen; + dfifo_type *df; + u_char *src, *dst, new_f1; + + if (!cs->tx_skb) + return; + if (cs->tx_skb->len <= 0) + return; + + df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)", + df->f1, df->f2, + df->za[df->f1 & D_FREG_MASK].z1); + fcnt = df->f1 - df->f2; /* frame count actually buffered */ + if (fcnt < 0) + fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ + if (fcnt > (MAX_D_FRAMES - 1)) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); + return; + } + /* now determine free bytes in FIFO buffer */ + count = df->za[df->f1 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1; + if (count <= 0) + count += D_FIFO_SIZE; /* count now contains available bytes */ + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci_fill_Dfifo count(%ld/%d)", + cs->tx_skb->len, count); + if (count < cs->tx_skb->len) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci_fill_Dfifo no fifo mem"); + return; + } + count = cs->tx_skb->len; /* get frame len */ + new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1); + new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); + src = cs->tx_skb->data; /* source pointer */ + dst = df->data + df->za[df->f1 & D_FREG_MASK].z1; + maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */ + if (maxlen > count) + maxlen = count; /* limit size */ + memcpy(dst, src, maxlen); /* first copy */ + + count -= maxlen; /* remaining bytes */ + if (count) { + dst = df->data; /* start of buffer */ + src += maxlen; /* new position */ + memcpy(dst, src, count); + } + save_flags(flags); + cli(); + df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */ + df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */ + df->f1 = new_f1; /* next frame */ + restore_flags(flags); + + idev_kfree_skb(cs->tx_skb, FREE_WRITE); + cs->tx_skb = NULL; + return; +} + +/**************************/ +/* B-channel send routine */ +/**************************/ +static void +hfcpci_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int flags, maxlen, fcnt; + int count, new_z1; + bzfifo_type *bz; + u_char *bdata; + u_char new_f1, *src, *dst; + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + save_flags(flags); + sti(); + + if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { + bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; + bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2; + } else { + bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; + bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1; + } + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_fifo %d f1(%d) f2(%d) z1(f1)(%x)", + bcs->channel, bz->f1, bz->f2, + bz->za[bz->f1].z1); + + fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ + if (fcnt < 0) + fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ + if (fcnt > (MAX_B_FRAMES - 1)) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames"); + restore_flags(flags); + return; + } + /* now determine free bytes in FIFO buffer */ + count = bz->za[bz->f1].z2 - bz->za[bz->f1].z1; + if (count <= 0) + count += B_FIFO_SIZE; /* count now contains available bytes */ + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_fifo %d count(%ld/%d),%lx", + bcs->channel, bcs->tx_skb->len, + count, current->state); + + if (count < bcs->tx_skb->len) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hfcpci_fill_fifo no fifo mem"); + restore_flags(flags); + return; + } + count = bcs->tx_skb->len; /* get frame len */ + new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */ + if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z1 -= B_FIFO_SIZE; /* buffer wrap */ + + new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); + src = bcs->tx_skb->data; /* source pointer */ + dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */ + if (maxlen > count) + maxlen = count; /* limit size */ + memcpy(dst, src, maxlen); /* first copy */ + + count -= maxlen; /* remaining bytes */ + if (count) { + dst = bdata; /* start of buffer */ + src += maxlen; /* new position */ + memcpy(dst, src, count); + } + bcs->tx_cnt -= bcs->tx_skb->len; + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + + cli(); + bz->za[new_f1].z1 = new_z1; /* for next buffer */ + bz->f1 = new_f1; /* next frame */ + restore_flags(flags); + + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + return; +} + +/***********************/ +/* set/reset echo mode */ +/***********************/ +int hfcpci_set_echo(struct IsdnCardState *cs, int i) +{ + if (cs->chanlimit > 1) + return(-EINVAL); + if (i) { + cs->logecho = 1; + cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */ + cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC; + cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX; + } + else { + cs->logecho = 0; + cs->hw.hfcpci.trm &= ~0x20; /* enable echo chan */ + cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC; + cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX; + } + cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; + cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; + cs->hw.hfcpci.conn &= ~0x18; + cs->hw.hfcpci.ctmt &= ~2; + Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); + Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); + Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); + Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); + Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + return(0); +} /* hfcpci_set_echo */ + +/*****************************/ +/* E-channel receive routine */ +/*****************************/ +static void receive_emsg(struct IsdnCardState *cs) +{ + long flags; + int rcnt; + int receive, count = 5; + bzfifo_type *bz; + u_char *bdata; + z_type *zp; + u_char *ptr, *ptr1, new_f2; + int total, maxlen, new_z2; + u_char e_buffer[256]; + + save_flags(flags); + bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; + bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; + Begin: + count--; + cli(); + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + debugl1(cs, "echo_rec_data blocked"); + restore_flags(flags); + return; + } + sti(); + if (bz->f1 != bz->f2) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)", + bz->f1, bz->f2); + zp = &bz->za[bz->f2]; + + rcnt = zp->z1 - zp->z2; + if (rcnt < 0) + rcnt += B_FIFO_SIZE; + rcnt++; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)", + zp->z1, zp->z2, rcnt); + new_z2 = zp->z2 + rcnt; /* new position in fifo */ + if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z2 -= B_FIFO_SIZE; /* buffer wrap */ + new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; + if ((rcnt > 256 + 3) || (count < 4) || + (*(bdata + (zp->z1 - B_SUB_VAL)))) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt); + bz->za[new_f2].z2 = new_z2; + bz->f2 = new_f2; /* next buffer */ + } else { + total = rcnt; + rcnt -= 3; + ptr = e_buffer; + + if (zp->z1 >= zp->z2) + maxlen = rcnt; /* complete transfer */ + else + maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ + + ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ + memcpy(ptr, ptr1, maxlen); /* copy data */ + rcnt -= maxlen; + + if (rcnt) { /* rest remaining */ + ptr += maxlen; + ptr1 = bdata; /* start of buffer */ + memcpy(ptr, ptr1, rcnt); /* rest */ + } + bz->za[new_f2].z2 = new_z2; + bz->f2 = new_f2; /* next buffer */ + if (cs->debug & DEB_DLOG_HEX) { + ptr = cs->dlog; + if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) { + *ptr++ = 'E'; + *ptr++ = 'C'; + *ptr++ = 'H'; + *ptr++ = 'O'; + *ptr++ = ':'; + ptr += QuickHex(ptr, e_buffer, total - 3); + ptr--; + *ptr++ = '\n'; + *ptr = 0; + HiSax_putstatus(cs, NULL, cs->dlog); + } else + HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3); + } + + } + + rcnt = bz->f1 - bz->f2; + if (rcnt < 0) + rcnt += MAX_B_FRAMES + 1; + if (rcnt > 1) + receive = 1; + else + receive = 0; + } else + receive = 0; + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + if (count && receive) + goto Begin; + restore_flags(flags); + return; +} /* receive_emsg */ + +/*********************/ +/* Interrupt handler */ +/*********************/ +static void +hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char exval; + struct BCState *bcs; + int count = 15; + long flags; + u_char val, stat; + + if (!cs) { + printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n"); + return; + } + if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) { + val = Read_hfc(cs, HFCPCI_INT_S1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val); + } else + return; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-PCI irq %x %s", val, + test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? + "locked" : "unlocked"); + val &= cs->hw.hfcpci.int_m1; + if (val & 0x40) { /* TE state machine irq */ + exval = Read_hfc(cs, HFCPCI_STATES) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state, + exval); + cs->dc.hfcpci.ph_state = exval; + sched_event_D_pci(cs, D_L1STATECHANGE); + val &= ~0x40; + } + while (val) { + save_flags(flags); + cli(); + if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + cs->hw.hfcpci.int_s1 |= val; + restore_flags(flags); + return; + } + if (cs->hw.hfcpci.int_s1 & 0x18) { + exval = val; + val = cs->hw.hfcpci.int_s1; + cs->hw.hfcpci.int_s1 = exval; + } + if (val & 0x08) { + if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) { + if (cs->debug) + debugl1(cs, "hfcpci spurious 0x08 IRQ"); + } else + main_rec_hfcpci(bcs); + } + if (val & 0x10) { + if (cs->logecho) + receive_emsg(cs); + else + if (!(bcs = Sel_BCS(cs, 1))) { + if (cs->debug) + debugl1(cs, "hfcpci spurious 0x10 IRQ"); + } else + main_rec_hfcpci(bcs); + } + if (val & 0x01) { + if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) { + if (cs->debug) + debugl1(cs, "hfcpci spurious 0x01 IRQ"); + } else { + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcpci_sched_event(bcs, B_XMTBUFREADY); + } + } + } + } + if (val & 0x02) { + if (!(bcs = Sel_BCS(cs, 1))) { + if (cs->debug) + debugl1(cs, "hfcpci spurious 0x02 IRQ"); + } else { + if (bcs->tx_skb) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "fill_data %d blocked", bcs->channel); + } else { + hfcpci_sched_event(bcs, B_XMTBUFREADY); + } + } + } + } + if (val & 0x20) { /* receive dframe */ + receive_dmsg(cs); + } + if (val & 0x04) { /* dframe transmitted */ + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + sched_event_D_pci(cs, D_CLEARBUSY); + if (cs->tx_skb) { + if (cs->tx_skb->len) { + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcpci_fill_dfifo irq blocked"); + } + goto afterXPR; + } else { + idev_kfree_skb(cs->tx_skb, FREE_WRITE); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } + } + if ((cs->tx_skb = skb_dequeue(&cs->sq))) { + cs->tx_cnt = 0; + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else { + debugl1(cs, "hfcpci_fill_dfifo irq blocked"); + } + } else + sched_event_D_pci(cs, D_XMTBUFREADY); + } + afterXPR: + if (cs->hw.hfcpci.int_s1 && count--) { + val = cs->hw.hfcpci.int_s1; + cs->hw.hfcpci.int_s1 = 0; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count); + } else + val = 0; + restore_flags(flags); + } +} + +/********************************************************************/ +/* timer callback for D-chan busy resolution. Currently no function */ +/********************************************************************/ +static void +hfcpci_dbusy_timer(struct IsdnCardState *cs) +{ +#if 0 + struct PStack *stptr; + if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy"); + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } +#endif +} + +/*************************************/ +/* Layer 1 D-channel hardware access */ +/*************************************/ +static void +HFCPCI_l1hw(struct PStack *st, int pr, void *arg) +{ + struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; + struct sk_buff *skb = arg; + + switch (pr) { + case (PH_DATA | REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + if (cs->tx_skb) { + skb_queue_tail(&cs->sq, skb); +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA Queued", 0); +#endif + } else { + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcpci_fill_dfifo blocked"); + + } + break; + case (PH_PULL | INDICATION): + if (cs->tx_skb) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); + skb_queue_tail(&cs->sq, skb); + break; + } + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); + cs->tx_skb = skb; + cs->tx_cnt = 0; +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); +#endif + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_dfifo(cs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "hfcpci_fill_dfifo blocked"); + break; + case (PH_PULL | REQUEST): +#ifdef L2FRAME_DEBUG /* psa */ + if (cs->debug & L1_DEB_LAPD) + debugl1(cs, "-> PH_REQUEST_PULL"); +#endif + if (!cs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (HW_RESET | REQUEST): + Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ + udelay(6); + Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */ + cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); + break; + case (HW_ENABLE | REQUEST): + Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); + break; + case (HW_DEACTIVATE | REQUEST): + cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER; + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + break; + case (HW_INFO3 | REQUEST): + cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + break; +#if 0 + case (HW_TESTLOOP | REQUEST): + u_char val = 0; + if (1 & (int) arg) + val |= 0x0c; + if (2 & (int) arg) + val |= 0x3; + if (test_bit(HW_IOM1, &cs->HW_Flags)) { + /* IOM 1 Mode */ + if (!val) { + cs->writeisac(cs, ISAC_SPCR, 0xa); + cs->writeisac(cs, ISAC_ADF1, 0x2); + } else { + cs->writeisac(cs, ISAC_SPCR, val); + cs->writeisac(cs, ISAC_ADF1, 0xa); + } + } else { + /* IOM 2 Mode */ + cs->writeisac(cs, ISAC_SPCR, val); + if (val) + cs->writeisac(cs, ISAC_ADF1, 0x8); + else + cs->writeisac(cs, ISAC_ADF1, 0x0); + } + break; +#endif + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr); + break; + } +} + +/***********************************************/ +/* called during init setting l1 stack pointer */ +/***********************************************/ +void +setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs) +{ + st->l1.l1hw = HFCPCI_l1hw; +} + +/**************************************/ +/* send B-channel data if not blocked */ +/**************************************/ +static void +hfcpci_send_data(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + + if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + hfcpci_fill_fifo(bcs); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + debugl1(cs, "send_data %d blocked", bcs->channel); +} + +/***************************************************************/ +/* activate/deactivate hardware for selected channels and mode */ +/***************************************************************/ +void +mode_hfcpci(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int flags; + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d", + mode, bc, bcs->channel); + bcs->mode = mode; + bcs->channel = bc; + if (cs->chanlimit > 1) { + cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ + cs->hw.hfcpci.sctrl_e &= ~0x80; + } + else { + if (bc) { + cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */ + cs->hw.hfcpci.sctrl_e |= 0x80; + bc = 0; /* B1 controller used */ + } + else { + cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ + cs->hw.hfcpci.sctrl_e &= ~0x80; + } + } + save_flags(flags); + cli(); + switch (mode) { + case (L1_MODE_NULL): + if (bc) { + cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; + cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; + cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2; + cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC); + } else { + cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA; + cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA; + cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1; + cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC); + } + break; + case (L1_MODE_TRANS): + if (bc) { + cs->hw.hfcpci.ctmt |= 2; + cs->hw.hfcpci.conn &= ~0x18; + cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; + cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; + cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; + cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC); + } else { + cs->hw.hfcpci.ctmt |= 1; + cs->hw.hfcpci.conn &= ~0x3; + cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; + cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; + cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; + cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC); + } + break; + case (L1_MODE_HDLC): + if (bc) { + cs->hw.hfcpci.ctmt &= ~2; + cs->hw.hfcpci.conn &= ~0x18; + cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; + cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; + cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; + cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC); + } else { + cs->hw.hfcpci.ctmt &= ~1; + cs->hw.hfcpci.conn &= ~0x3; + cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; + cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; + cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; + cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC); + } + break; + } + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + restore_flags(flags); + Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); + Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); + Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); + Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); + Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); +} + +/******************************/ +/* Layer2 -> Layer 1 Transfer */ +/******************************/ +static void +hfcpci_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; +/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + */ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + restore_flags(flags); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); + break; + } + save_flags(flags); + cli(); +/* test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + */ st->l1.bcs->tx_skb = skb; + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + restore_flags(flags); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_hfcpci(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_hfcpci(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +/******************************************/ +/* deactivate B-channel access and queues */ +/******************************************/ +static void +close_hfcpci(struct BCState *bcs) +{ + mode_hfcpci(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +/*************************************/ +/* init B-channel queues and control */ +/*************************************/ +static int +open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->tx_cnt = 0; + return (0); +} + +/*********************************/ +/* inits the stack for B-channel */ +/*********************************/ +static int +setstack_2b(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (open_hfcpcistate(st->l1.hardware, bcs)) + return (-1); + st->l1.bcs = bcs; + st->l2.l2l1 = hfcpci_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +/***************************/ +/* handle L1 state changes */ +/***************************/ +static void +hfcpci_bh(struct IsdnCardState *cs) +{ +/* struct PStack *stptr; + */ + if (!cs) + return; +#if 0 + if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { + if (cs->debug) + debugl1(cs, "D-Channel Busy cleared"); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); + stptr = stptr->next; + } + } +#endif + if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { + switch (cs->dc.hfcpci.ph_state) { + case (0): + l1_msg(cs, HW_RESET | INDICATION, NULL); + break; + case (3): + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); + break; + case (8): + l1_msg(cs, HW_RSYNC | INDICATION, NULL); + break; + case (6): + l1_msg(cs, HW_INFO2 | INDICATION, NULL); + break; + case (7): + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); + break; + default: + break; + } + } + if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) + DChannel_proc_rcv(cs); + if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) + DChannel_proc_xmt(cs); +} + + +/*************************************/ +/* Alloc memory send data for queues */ +/*************************************/ +__initfunc(unsigned int + *init_send_hfcpci(int cnt)) +{ + int i, *send; + + if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hfcpci.send\n"); + return (NULL); + } + for (i = 0; i < cnt; i++) + send[i] = 0x1fff; + return (send); +} + +/********************************/ +/* called for card init message */ +/********************************/ +__initfunc(void + inithfcpci(struct IsdnCardState *cs)) +{ + cs->setstack_d = setstack_hfcpci; + cs->dbusytimer.function = (void *) hfcpci_dbusy_timer; + cs->dbusytimer.data = (long) cs; + init_timer(&cs->dbusytimer); + cs->tqueue.routine = (void *) (void *) hfcpci_bh; +#if 0 + if (!cs->hw.hfcpci.send) + cs->hw.hfcpci.send = init_send_hfcpci(16); +#endif + if (!cs->bcs[0].hw.hfc.send) + cs->bcs[0].hw.hfc.send = init_send_hfcpci(32); + if (!cs->bcs[1].hw.hfc.send) + cs->bcs[1].hw.hfc.send = init_send_hfcpci(32); + cs->BC_Send_Data = &hfcpci_send_data; + cs->bcs[0].BC_SetStack = setstack_2b; + cs->bcs[1].BC_SetStack = setstack_2b; + cs->bcs[0].BC_Close = close_hfcpci; + cs->bcs[1].BC_Close = close_hfcpci; + mode_hfcpci(cs->bcs, 0, 0); + mode_hfcpci(cs->bcs + 1, 0, 1); +} + + + +/*******************************************/ +/* handle card messages from control layer */ +/*******************************************/ +static int +hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCPCI: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + reset_hfcpci(cs); + return (0); + case CARD_RELEASE: + release_io_hfcpci(cs); + return (0); + case CARD_INIT: + inithfcpci(cs); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ + /* now switch timer interrupt off */ + cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + /* reinit mode reg */ + Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); + restore_flags(flags); + return (0); + case CARD_TEST: + return (0); + } + return (0); +} + + +/* this variable is used as card index when more than one cards are present */ +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_hfcpci __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +#endif /* CONFIG_PCI */ + +__initfunc(int + setup_hfcpci(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, hfcpci_revision); + printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); +#if CONFIG_PCI + cs->hw.hfcpci.int_s1 = 0; +#if 0 + cs->hw.hfcpci.send = NULL; +#endif + cs->bcs[0].hw.hfc.send = NULL; + cs->bcs[1].hw.hfc.send = NULL; + cs->dc.hfcpci.ph_state = 0; + cs->hw.hfcpci.fifo = 255; + if (cs->typ == ISDN_CTYPE_HFC_PCI) { +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "HFC-PCI: no PCI bus present\n"); + return (0); + } + if ((dev_hfcpci = pci_find_device(PCI_VENDOR_CCD, + PCI_CCD_PCI_ID, dev_hfcpci))) { + cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number; + cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn; + cs->irq = dev_hfcpci->irq; + if (!cs->irq) { + printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); + return (0); + } + cs->hw.hfcpci.pci_io = (char *) + dev_hfcpci->base_address[1]; + } else { + printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); + return (0); + } +#else + for (; pci_index < 255; pci_index++) { + unsigned char irq; + + if (pcibios_find_device(PCI_VENDOR_CCD, + PCI_CCD_PCI_ID, pci_index, + &cs->hw.hfcpci.pci_bus, &cs->hw.hfcpci.pci_device_fn) != 0) { + continue; + } + pcibios_read_config_byte(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, + PCI_INTERRUPT_LINE, &irq); + cs->irq = irq; + + pcibios_read_config_dword(cs->hw.hfcpci.pci_bus, + cs->hw.hfcpci.pci_device_fn, PCI_BASE_ADDRESS_1, + (void *) &cs->hw.hfcpci.pci_io); + break; + } + if (pci_index == 255) { + printk(KERN_WARNING "HFC-PCI: No card found\n"); + return (0); + } + pci_index++; +#endif /* COMPAT_HAS_NEW_PCI */ + if (!cs->hw.hfcpci.pci_io) { + printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); + return (0); + } + /* Allocate memory for FIFOS */ + /* Because the HFC-PCI needs a 32K physical alignment, we */ + /* need to allocate the double mem and align the address */ + if (!((void *) cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { + printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); + return 0; + } + (ulong) cs->hw.hfcpci.fifos = + (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; + pcibios_write_config_dword(cs->hw.hfcpci.pci_bus, + cs->hw.hfcpci.pci_device_fn, 0x80, + (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); + cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); + printk(KERN_INFO + "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n", + (u_int) cs->hw.hfcpci.pci_io, + (u_int) cs->hw.hfcpci.fifos, + (u_int) virt_to_bus(cs->hw.hfcpci.fifos), + cs->irq, HZ); + pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ + cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */ + cs->hw.hfcpci.int_m1 = 0; + Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); + Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); + /* At this point the needed PCI config is done */ + /* fifos are still not enabled */ + } else + return (0); /* no valid card type */ + + + cs->readisac = NULL; + cs->writeisac = NULL; + cs->readisacfifo = NULL; + cs->writeisacfifo = NULL; + cs->BC_Read_Reg = NULL; + cs->BC_Write_Reg = NULL; + cs->irq_func = &hfcpci_interrupt; + cs->irq_flags |= SA_SHIRQ; + + cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer; + cs->hw.hfcpci.timer.data = (long) cs; + init_timer(&cs->hw.hfcpci.timer); + + reset_hfcpci(cs); + cs->cardmsg = &hfcpci_card_msg; + return (1); +#else + printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n"); + return (0); +#endif /* CONFIG_PCI */ +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hfc_pci.h linux/drivers/isdn/hisax/hfc_pci.h --- v2.2.10/linux/drivers/isdn/hisax/hfc_pci.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/hfc_pci.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,250 @@ +/* $Id: hfc_pci.h,v 1.3 1999/07/14 12:39:34 werner Exp $ + + * specific defines for CCD's HFC 2BDS0 PCI chips + * + * Author Werner Cornelius (werner@isdn4linux.de) + * + * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) + * + * 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, 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. + * + * $Log: hfc_pci.h,v $ + * Revision 1.3 1999/07/14 12:39:34 werner + * Added changes for echo handling. + * + * Revision 1.2 1999/07/01 08:07:52 keil + * Initial version + * + * + * + */ + + +/* defines for PCI config */ + +#define PCI_VENDOR_CCD 0x1397 +#define PCI_CCD_PCI_ID 0x2BD0 +// #define PCI_VENDOR_CCD 0x1043 +// #define PCI_CCD_PCI_ID 0x675 +#define PCI_ENA_MEMIO 0x02 +#define PCI_ENA_MASTER 0x04 + + +/* GCI/IOM bus monitor registers */ + +#define HCFPCI_C_I 0x08 +#define HFCPCI_TRxR 0x0C +#define HFCPCI_MON1_D 0x28 +#define HFCPCI_MON2_D 0x2C + + +/* GCI/IOM bus timeslot registers */ + +#define HFCPCI_B1_SSL 0x80 +#define HFCPCI_B2_SSL 0x84 +#define HFCPCI_AUX1_SSL 0x88 +#define HFCPCI_AUX2_SSL 0x8C +#define HFCPCI_B1_RSL 0x90 +#define HFCPCI_B2_RSL 0x94 +#define HFCPCI_AUX1_RSL 0x98 +#define HFCPCI_AUX2_RSL 0x9C + +/* GCI/IOM bus data registers */ + +#define HFCPCI_B1_D 0xA0 +#define HFCPCI_B2_D 0xA4 +#define HFCPCI_AUX1_D 0xA8 +#define HFCPCI_AUX2_D 0xAC + +/* GCI/IOM bus configuration registers */ + +#define HFCPCI_MST_EMOD 0xB4 +#define HFCPCI_MST_MODE 0xB8 +#define HFCPCI_CONNECT 0xBC + + +/* Interrupt and status registers */ + +#define HFCPCI_FIFO_EN 0x44 +#define HFCPCI_TRM 0x48 +#define HFCPCI_B_MODE 0x4C +#define HFCPCI_CHIP_ID 0x58 +#define HFCPCI_CIRM 0x60 +#define HFCPCI_CTMT 0x64 +#define HFCPCI_INT_M1 0x68 +#define HFCPCI_INT_M2 0x6C +#define HFCPCI_INT_S1 0x78 +#define HFCPCI_INT_S2 0x7C +#define HFCPCI_STATUS 0x70 + +/* S/T section registers */ + +#define HFCPCI_STATES 0xC0 +#define HFCPCI_SCTRL 0xC4 +#define HFCPCI_SCTRL_E 0xC8 +#define HFCPCI_SCTRL_R 0xCC +#define HFCPCI_SQ 0xD0 +#define HFCPCI_CLKDEL 0xDC +#define HFCPCI_B1_REC 0xF0 +#define HFCPCI_B1_SEND 0xF0 +#define HFCPCI_B2_REC 0xF4 +#define HFCPCI_B2_SEND 0xF4 +#define HFCPCI_D_REC 0xF8 +#define HFCPCI_D_SEND 0xF8 +#define HFCPCI_E_REC 0xFC + + +/* bits in status register (READ) */ +#define HFCPCI_PCI_PROC 0x02 +#define HFCPCI_NBUSY 0x04 +#define HFCPCI_TIMER_ELAP 0x10 +#define HFCPCI_STATINT 0x20 +#define HFCPCI_FRAMEINT 0x40 +#define HFCPCI_ANYINT 0x80 + +/* bits in CTMT (Write) */ +#define HFCPCI_CLTIMER 0x80 +#define HFCPCI_TIM3_125 0x00 +#define HFCPCI_TIM25 0x10 +#define HFCPCI_TIM50 0x14 +#define HFCPCI_TIM400 0x18 +#define HFCPCI_TIM800 0x1C +#define HFCPCI_AUTO_TIMER 0x20 +#define HFCPCI_TRANSB2 0x02 +#define HFCPCI_TRANSB1 0x01 + +/* bits in CIRM (Write) */ +#define HFCPCI_AUX_MSK 0x07 +#define HFCPCI_RESET 0x08 +#define HFCPCI_B1_REV 0x40 +#define HFCPCI_B2_REV 0x80 + +/* bits in INT_M1 and INT_S1 */ +#define HFCPCI_INTS_B1TRANS 0x01 +#define HFCPCI_INTS_B2TRANS 0x02 +#define HFCPCI_INTS_DTRANS 0x04 +#define HFCPCI_INTS_B1REC 0x08 +#define HFCPCI_INTS_B2REC 0x10 +#define HFCPCI_INTS_DREC 0x20 +#define HFCPCI_INTS_L1STATE 0x40 +#define HFCPCI_INTS_TIMER 0x80 + +/* bits in INT_M2 */ +#define HFCPCI_PROC_TRANS 0x01 +#define HFCPCI_GCI_I_CHG 0x02 +#define HFCPCI_GCI_MON_REC 0x04 +#define HFCPCI_IRQ_ENABLE 0x08 +#define HFCPCI_PMESEL 0x80 + +/* bits in STATES */ +#define HFCPCI_STATE_MSK 0x0F +#define HFCPCI_LOAD_STATE 0x10 +#define HFCPCI_ACTIVATE 0x20 +#define HFCPCI_DO_ACTION 0x40 +#define HFCPCI_NT_G2_G3 0x80 + +/* bits in HFCD_MST_MODE */ +#define HFCPCI_MASTER 0x01 +#define HFCPCI_SLAVE 0x00 +/* remaining bits are for codecs control */ + +/* bits in HFCD_SCTRL */ +#define SCTRL_B1_ENA 0x01 +#define SCTRL_B2_ENA 0x02 +#define SCTRL_MODE_TE 0x00 +#define SCTRL_MODE_NT 0x04 +#define SCTRL_LOW_PRIO 0x08 +#define SCTRL_SQ_ENA 0x10 +#define SCTRL_TEST 0x20 +#define SCTRL_NONE_CAP 0x40 +#define SCTRL_PWR_DOWN 0x80 + +/* bits in SCTRL_E */ +#define HFCPCI_AUTO_AWAKE 0x01 +#define HFCPCI_DBIT_1 0x04 +#define HFCPCI_IGNORE_COL 0x08 +#define HFCPCI_CHG_B1_B2 0x80 + +/****************************/ +/* bits in FIFO_EN register */ +/****************************/ +#define HFCPCI_FIFOEN_B1 0x03 +#define HFCPCI_FIFOEN_B2 0x0C +#define HFCPCI_FIFOEN_DTX 0x10 +#define HFCPCI_FIFOEN_B2RX 0x08 + + +/***********************************/ +/* definitions of fifo memory area */ +/***********************************/ +#define MAX_D_FRAMES 15 +#define MAX_B_FRAMES 31 +#define B_SUB_VAL 0x200 +#define B_FIFO_SIZE (0x2000 - B_SUB_VAL) +#define D_FIFO_SIZE 512 +#define D_FREG_MASK 0xF + +typedef struct { + unsigned short z1; /* Z1 pointer 16 Bit */ + unsigned short z2; /* Z2 pointer 16 Bit */ + } z_type; + +typedef struct { + u_char data[D_FIFO_SIZE]; /* FIFO data space */ + u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */ + u_char f1,f2; /* f pointers */ + u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */ + z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */ + u_char fill3[0x4000-0x2100]; /* align 16K */ + } dfifo_type; + +typedef struct { + z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */ + u_char f1,f2; /* f pointers */ + u_char fill[0x2100-0x2082]; /* alignment */ + } bzfifo_type; + + +typedef union { + struct { + dfifo_type d_tx; /* D-send channel */ + dfifo_type d_rx; /* D-receive channel */ + } d_chan; + struct { + u_char fill1[0x200]; + u_char txdat_b1[B_FIFO_SIZE]; + bzfifo_type txbz_b1; + + bzfifo_type txbz_b2; + u_char txdat_b2[B_FIFO_SIZE]; + + u_char fill2[D_FIFO_SIZE]; + + u_char rxdat_b1[B_FIFO_SIZE]; + bzfifo_type rxbz_b1; + + bzfifo_type rxbz_b2; + u_char rxdat_b2[B_FIFO_SIZE]; + } b_chans; + u_char fill[32768]; + } fifo_area; + + +#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c) +#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b)) + +extern void main_irq_hcpci(struct BCState *bcs); +extern void inithfcpci(struct IsdnCardState *cs); +extern void releasehfcpci(struct IsdnCardState *cs); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c --- v2.2.10/linux/drivers/isdn/hisax/hfcscard.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/hfcscard.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,203 @@ +/* $Id: hfcscard.c,v 1.3 1999/07/12 21:05:12 keil Exp $ + + * hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10) + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * + * $Log: hfcscard.c,v $ + * Revision 1.3 1999/07/12 21:05:12 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.2 1999/07/01 08:16:03 keil + * teles3c ---> hfcscard + * + * + * + */ + +#define __NO_VERSION__ +#include "hisax.h" +#include "hfc_2bds0.h" +#include "isdnl1.h" + +extern const char *CardType[]; + +static const char *hfcs_revision = "$Revision: 1.3 $"; + +static void +hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val, stat; + + if (!cs) { + printk(KERN_WARNING "HFCS: Spurious interrupt!\n"); + return; + } + if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & + (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { + val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); + hfc2bds0_interrupt(cs, val); + } else { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); + } +} + +static void +hfcs_Timer(struct IsdnCardState *cs) +{ + cs->hw.hfcD.timer.expires = jiffies + 75; + /* WD RESET */ +/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); + add_timer(&cs->hw.hfcD.timer); +*/ +} + +void +release_io_hfcs(struct IsdnCardState *cs) +{ + release2bds0(cs); + del_timer(&cs->hw.hfcD.timer); + if (cs->hw.hfcD.addr) + release_region(cs->hw.hfcD.addr, 2); +} + +static void +reset_hfcs(struct IsdnCardState *cs) +{ + long flags; + + printk(KERN_INFO "HFCS: resetting card\n"); + cs->hw.hfcD.cirm = HFCD_RESET; + if (cs->typ == ISDN_CTYPE_TELES3C) + cs->hw.hfcD.cirm |= HFCD_MEM8K; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((30*HZ)/1000); + cs->hw.hfcD.cirm = 0; + if (cs->typ == ISDN_CTYPE_TELES3C) + cs->hw.hfcD.cirm |= HFCD_MEM8K; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + if (cs->typ == ISDN_CTYPE_TELES3C) + cs->hw.hfcD.cirm |= HFCD_INTB; + else if (cs->typ == ISDN_CTYPE_ACERP10) + cs->hw.hfcD.cirm |= HFCD_INTA; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ + cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); + cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; + cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | + HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | + HFCD_INTS_DREC | HFCD_INTS_L1STATE; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ + udelay(10); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ + cs->hw.hfcD.mst_m = 0; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, HFCD_MASTER); /* HFC Master */ + cs->hw.hfcD.sctrl = 0; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); + restore_flags(flags); +} + +static int +hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + long flags; + + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "HFCS: card_msg %x", mt); + switch (mt) { + case CARD_RESET: + reset_hfcs(cs); + return(0); + case CARD_RELEASE: + release_io_hfcs(cs); + return(0); + case CARD_INIT: + cs->hw.hfcD.timer.expires = jiffies + 75; + add_timer(&cs->hw.hfcD.timer); + init2bds0(cs); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((80*HZ)/1000); + cs->hw.hfcD.ctmt |= HFCD_TIM800; + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); + cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); + restore_flags(flags); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +__initfunc(int +setup_hfcs(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, hfcs_revision); + printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); + cs->hw.hfcD.addr = card->para[1] & 0xfffe; + cs->irq = card->para[0]; + cs->hw.hfcD.cip = 0; + cs->hw.hfcD.int_s1 = 0; + cs->hw.hfcD.send = NULL; + cs->bcs[0].hw.hfc.send = NULL; + cs->bcs[1].hw.hfc.send = NULL; + cs->hw.hfcD.dfifosize = 512; + cs->dc.hfcd.ph_state = 0; + cs->hw.hfcD.fifo = 255; + if (cs->typ == ISDN_CTYPE_TELES3C) { + cs->hw.hfcD.bfifosize = 1024 + 512; + } else if (cs->typ == ISDN_CTYPE_ACERP10) { + cs->hw.hfcD.bfifosize = 7*1024 + 512; + } else + return (0); + if (check_region((cs->hw.hfcD.addr), 2)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.hfcD.addr, + cs->hw.hfcD.addr + 2); + return (0); + } else { + request_region(cs->hw.hfcD.addr, 2, "HFCS isdn"); + } + printk(KERN_INFO + "HFCS: defined at 0x%x IRQ %d HZ %d\n", + cs->hw.hfcD.addr, + cs->irq, HZ); + if (cs->typ == ISDN_CTYPE_TELES3C) { + /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ + outb(0x00, cs->hw.hfcD.addr); + outb(0x56, cs->hw.hfcD.addr | 1); + } else if (cs->typ == ISDN_CTYPE_ACERP10) { + /* Acer P10 IO ADR is 0x300 */ + outb(0x00, cs->hw.hfcD.addr); + outb(0x57, cs->hw.hfcD.addr | 1); + } + set_cs_func(cs); + cs->hw.hfcD.timer.function = (void *) hfcs_Timer; + cs->hw.hfcD.timer.data = (long) cs; + init_timer(&cs->hw.hfcD.timer); + reset_hfcs(cs); + cs->cardmsg = &hfcs_card_msg; + cs->irq_func = &hfcs_interrupt; + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.2.10/linux/drivers/isdn/hisax/hisax.h Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/hisax.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,62 @@ -/* $Id: hisax.h,v 2.14 1998/02/11 17:28:04 keil Exp $ +/* $Id: hisax.h,v 2.30 1999/07/14 12:38:38 werner Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.30 1999/07/14 12:38:38 werner + * Added changes for echo channel handling + * + * Revision 2.29 1999/07/12 21:05:14 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.28 1999/07/05 23:51:46 werner + * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl + * hisaxctrl id 10 + * + * Revision 2.27 1999/07/01 08:11:38 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.26 1998/11/15 23:54:45 keil + * changes from 2.0 + * + * Revision 2.25 1998/09/30 22:28:42 keil + * More work for ISAR support + * + * Revision 2.24 1998/08/20 13:50:39 keil + * More support for hybrid modem (not working yet) + * + * Revision 2.23 1998/08/13 23:36:31 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.22 1998/07/15 15:01:28 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.21 1998/05/25 14:10:05 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.20 1998/05/25 12:57:57 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.19 1998/04/15 16:39:15 keil + * Add S0Box and Teles PCI support + * + * Revision 2.18 1998/03/26 07:10:04 paul + * The jumpmatrix table in struct Fsm was an array of "int". This is not + * large enough for pointers to functions on Linux/Alpha (instant crash + * on "insmod hisax). Now there is a typedef for the pointer to function. + * This also prevents warnings about "incompatible pointer types". + * + * Revision 2.17 1998/03/19 13:18:43 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 2.16 1998/03/09 23:19:25 keil + * Changes for PCMCIA + * * Revision 2.14 1998/02/11 17:28:04 keil * Niccy PnP/PCI support * @@ -71,121 +125,104 @@ #include #include #include -#include +#include + +#define REQUEST 0 +#define CONFIRM 1 +#define INDICATION 2 +#define RESPONSE 3 + +#define HW_ENABLE 0x0000 +#define HW_RESET 0x0004 +#define HW_POWERUP 0x0008 +#define HW_ACTIVATE 0x0010 +#define HW_DEACTIVATE 0x0018 +#define HW_INFO2 0x0020 +#define HW_INFO3 0x0030 +#define HW_INFO4_P8 0x0040 +#define HW_INFO4_P10 0x0048 +#define HW_RSYNC 0x0060 +#define HW_TESTLOOP 0x0070 +#define CARD_RESET 0x00F0 +#define CARD_INIT 0x00F2 +#define CARD_RELEASE 0x00F3 +#define CARD_TEST 0x00F4 +#define CARD_AUX_IND 0x00F5 +#define CARD_LOAD_FIRM 0x00F6 + +#define PH_ACTIVATE 0x0100 +#define PH_DEACTIVATE 0x0110 +#define PH_DATA 0x0120 +#define PH_PULL 0x0130 +#define PH_TESTLOOP 0x0140 +#define PH_PAUSE 0x0150 +#define MPH_ACTIVATE 0x0180 +#define MPH_DEACTIVATE 0x0190 +#define MPH_INFORMATION 0x01A0 + +#define DL_ESTABLISH 0x0200 +#define DL_RELEASE 0x0210 +#define DL_DATA 0x0220 +#define DL_FLUSH 0x0224 +#define DL_UNIT_DATA 0x0230 +#define MDL_ASSIGN 0x0280 +#define MDL_REMOVE 0x0284 +#define MDL_ERROR 0x0288 +#define MDL_INFO_SETUP 0x02E0 +#define MDL_INFO_CONN 0x02E4 +#define MDL_INFO_REL 0x02E8 + +#define CC_SETUP 0x0300 +#define CC_RESUME 0x0304 +#define CC_MORE_INFO 0x0310 +#define CC_IGNORE 0x0320 +#define CC_REJECT 0x0324 +#define CC_SETUP_COMPL 0x0330 +#define CC_PROCEEDING 0x0340 +#define CC_ALERTING 0x0344 +#define CC_PROGRESS 0x0348 +#define CC_CONNECT 0x0350 +#define CC_CHARGE 0x0354 +#define CC_NOTIFY 0x0358 +#define CC_DISCONNECT 0x0360 +#define CC_RELEASE 0x0368 +#define CC_SUSPEND 0x0370 +#define CC_PROCEED_SEND 0x0374 +#define CC_REDIR 0x0378 +#define CC_T303 0x0383 +#define CC_T304 0x0384 +#define CC_T305 0x0385 +#define CC_T308_1 0x0388 +#define CC_T308_2 0x038A +#define CC_T309 0x0309 +#define CC_T310 0x0390 +#define CC_T313 0x0393 +#define CC_T318 0x0398 +#define CC_T319 0x0399 +#define CC_NOSETUP_RSP 0x03E0 +#define CC_SETUP_ERR 0x03E1 +#define CC_SUSPEND_ERR 0x03E2 +#define CC_RESUME_ERR 0x03E3 +#define CC_CONNECT_ERR 0x03E4 +#define CC_RELEASE_ERR 0x03E5 +#define CC_RESTART 0x03F4 +#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ + +/* define maximum number of possible waiting incoming calls */ +#define MAX_WAITING_CALLS 2 -#define PH_ACTIVATE_REQ 0x0010 -#define PH_ACTIVATE_CNF 0x0011 -#define PH_ACTIVATE_IND 0x0012 -#define PH_DEACTIVATE_REQ 0x0020 -#define PH_DEACTIVATE_CNF 0x0021 -#define PH_DEACTIVATE_IND 0x0022 -#define PH_DEACT_REQ 0x0024 -#define PH_DEACT_CNF 0x0025 -#define PH_DEACT_IND 0x0026 -#define PH_DEACT_ACK 0x0027 -#define PH_TESTLOOP_REQ 0x0030 -#define PH_PAUSE_CNF 0x0035 -#define PH_PAUSE_IND 0x0036 -#define PH_PULL_REQ 0x0038 -#define PH_PULL_CNF 0x0039 -#define PH_PULL_IND 0x003A -#define PH_DATA_REQ 0x0040 -#define PH_DATA_IND 0x0042 - -#define PH_INFO3_REQ 0x0008 -#define PH_INFO2_IND 0x000A -#define PH_ENABLE_REQ 0x0004 -#define PH_RSYNC_IND 0x0006 -#define PH_RESET_REQ 0x0000 -#define PH_RESET_IND 0x0002 -#define PH_POWERUP_CNF 0x0003 -#define PH_ACTIV_REQ 0x000C -#define PH_I4_P8_IND 0x000D -#define PH_I4_P10_IND 0x000F - -#define MDL_ASSIGN_REQ 0x0050 -#define MDL_ASSIGN_IND 0x0052 -#define MDL_REMOVE_REQ 0x0054 -#define MDL_ERROR_REQ 0x0058 -#define MDL_ERROR_IND 0x005A -#define CARD_AUX_IND 0x005E - -#define DL_UNIT_DATA 6 -#define CC_ESTABLISH 7 -#define DL_ESTABLISH 8 -#define DL_DATA 9 - -#define CC_CONNECT 15 -#define DL_RELEASE 20 -#define DL_FLUSH 21 - -#define CC_REJECT 23 - -#define CC_SETUP_REQ 24 -#define CC_SETUP_CNF 25 -#define CC_SETUP_IND 26 -#define CC_SETUP_RSP 27 -#define CC_SETUP_COMPLETE_IND 28 - -#define CC_DISCONNECT_REQ 29 -#define CC_DISCONNECT_IND 30 - -#define CC_RELEASE_CNF 31 -#define CC_RELEASE_IND 32 -#define CC_RELEASE_REQ 33 - -#define CC_REJECT_REQ 34 - -#define CC_PROCEEDING_IND 35 - -#define CC_DLRL 36 -#define CC_DLEST 37 - -#define CC_ALERTING_REQ 38 -#define CC_ALERTING_IND 39 - -#define DL_STOP 40 -#define DL_START 41 - -#define MDL_INFO_SETUP 42 -#define MDL_INFO_CONN 43 -#define MDL_INFO_REL 44 -#define MDL_NOTEIPROC 46 - -#define LC_ESTABLISH 47 -#define LC_RELEASE 48 - -#define CC_INFO_CHARGE 52 - -#define CC_MORE_INFO 53 -#define CC_IGNORE 54 -#define CC_RESTART 55 - - -#define CC_T303 60 -#define CC_T304 61 -#define CC_T305 62 -#define CC_T308_1 64 -#define CC_T308_2 65 -#define CC_T310 66 -#define CC_T313 67 -#define CC_T318 68 -#define CC_T319 69 - -#define CC_NOSETUP_RSP_ERR 70 -#define CC_SETUP_ERR 71 -#define CC_CONNECT_ERR 72 -#define CC_RELEASE_ERR 73 - -#define CARD_RESET 0x1001 -#define CARD_SETIRQ 0x1002 -#define CARD_INIT 0x1003 -#define CARD_RELEASE 0x1004 -#define CARD_TEST 0x1005 #ifdef __KERNEL__ +/* include only l3dss1 specific process structures, but no other defines */ +#ifdef CONFIG_HISAX_EURO + #define l3dss1_process + #include "l3dss1.h" + #undef l3dss1_process +#endif CONFIG_HISAX_EURO + #define MAX_DFRAME_LEN 260 +#define MAX_DFRAME_LEN_L1 300 #define HSCX_BUFMAX 4096 #define MAX_DATA_SIZE (HSCX_BUFMAX - 4) #define MAX_DATA_MEM (HSCX_BUFMAX + 64) @@ -193,6 +230,8 @@ #define MAX_HEADER_LEN 4 #define MAX_WINDOW 8 #define MAX_MON_FRAME 32 +#define MAX_DLOG_SPACE 2048 +#define MAX_BLOG_SPACE 256 /* #define I4L_IRQ_FLAG SA_INTERRUPT */ #define I4L_IRQ_FLAG 0 @@ -201,8 +240,12 @@ * Statemachine */ +struct FsmInst; + +typedef void (* FSMFNPTR)(struct FsmInst *, int, void *); + struct Fsm { - int *jumpmatrix; + FSMFNPTR *jumpmatrix; int state_count, event_count; char **strEvent, **strState; }; @@ -213,7 +256,7 @@ int debug; void *userdata; int userint; - void (*printdebug) (struct FsmInst *, char *); + void (*printdebug) (struct FsmInst *, char *, ...); }; struct FsmNode { @@ -249,9 +292,10 @@ struct FsmInst l1m; struct FsmTimer timer; void (*l1l2) (struct PStack *, int, void *); - void (*l1man) (struct PStack *, int, void *); + void (*l1hw) (struct PStack *, int, void *); void (*l1tei) (struct PStack *, int, void *); int mode, bc; + int delay; }; #define GROUP_TEI 127 @@ -266,49 +310,57 @@ #define FLG_ORIG 2 #define FLG_MOD128 3 #define FLG_PEND_REL 4 -#define FLG_L3_INIT 5 -#define FLG_T200_RUN 6 +#define FLG_L3_INIT 5 +#define FLG_T200_RUN 6 #define FLG_ACK_PEND 7 #define FLG_REJEXC 8 #define FLG_OWN_BUSY 9 #define FLG_PEER_BUSY 10 #define FLG_DCHAN_BUSY 11 +#define FLG_L1_ACTIV 12 +#define FLG_ESTAB_PEND 13 +#define FLG_PTP 14 +#define FLG_FIXED_TEI 15 struct Layer2 { int tei; - int tei_wanted; int sap; int maxlen; unsigned int flag; - int vs, va, vr; + unsigned int vs, va, vr; int rc; - int window; - int sow; + unsigned int window; + unsigned int sow; struct sk_buff *windowar[MAX_WINDOW]; struct sk_buff_head i_queue; struct sk_buff_head ui_queue; void (*l2l1) (struct PStack *, int, void *); - void (*l2man) (struct PStack *, int, void *); void (*l2l3) (struct PStack *, int, void *); void (*l2tei) (struct PStack *, int, void *); struct FsmInst l2m; struct FsmTimer t200, t203; int T200, N200, T203; int debug; - char debug_id[32]; + char debug_id[16]; }; struct Layer3 { - void (*l3l4) (struct l3_process *, int, void *); + void (*l3l4) (struct PStack *, int, void *); + void (*l3ml3) (struct PStack *, int, void *); void (*l3l2) (struct PStack *, int, void *); + struct FsmInst l3m; + struct FsmTimer l3m_timer; + struct sk_buff_head squeue; struct l3_process *proc; struct l3_process *global; int N303; int debug; + char debug_id[8]; }; struct LLInterface { void (*l4l3) (struct PStack *, int, void *); + int (*l4l3_proto) (struct PStack *, isdn_ctrl *); void *userdata; void (*l1writewakeup) (struct PStack *, int); void (*l2writewakeup) (struct PStack *, int); @@ -321,20 +373,19 @@ struct FsmTimer t202; int T202, N202, debug; void (*layer) (struct PStack *, int, void *); - void (*manl1) (struct PStack *, int, void *); - void (*manl2) (struct PStack *, int, void *); }; +#define NO_CAUSE 254 struct Param { - int cause; - int loc; + u_char cause; + u_char loc; + u_char diag[6]; int bchannel; - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - int chargeinfo; /* Charge Info - only for 1tr6 in - * the moment - */ + int chargeinfo; int spv; /* SPV Flag */ + setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ + u_char moderate; /* transfer mode and rate (bearer octet 4) */ }; @@ -343,9 +394,17 @@ struct Layer1 l1; struct Layer2 l2; struct Layer3 l3; - struct LLInterface lli; + struct LLInterface lli; struct Management ma; int protocol; /* EDSS1 or 1TR6 */ + + /* protocol specific data fields */ + union + { u_char uuuu; /* only as dummy */ +#ifdef CONFIG_HISAX_EURO + dss1_stk_priv dss1; /* private dss1 data */ +#endif CONFIG_HISAX_EURO + } prot; }; struct l3_process { @@ -358,24 +417,69 @@ struct Channel *chan; struct PStack *st; struct l3_process *next; + ulong redir_result; + + /* protocol specific data fields */ + union + { u_char uuuu; /* only when euro not defined, avoiding empty union */ +#ifdef CONFIG_HISAX_EURO + dss1_proc_priv dss1; /* private dss1 data */ +#endif CONFIG_HISAX_EURO + } prot; }; struct hscx_hw { + int hscx; + int rcvidx; + int count; /* Current skb sent count */ + u_char *rcvbuf; /* B-Channel receive Buffer */ + u_char tsaxr0; + u_char tsaxr1; +}; + +struct isar_reg { + unsigned int Flags; + volatile u_char bstat; + volatile u_char iis; + volatile u_char cmsb; + volatile u_char clsb; + volatile u_char par[8]; +}; + +struct isar_hw { + int dpath; + int rcvidx; + int txcnt; + int mml; + u_char *rcvbuf; /* B-Channel receive Buffer */ + struct isar_reg *reg; +}; + +struct hdlc_stat_reg { + u_char cmd __attribute__((packed)); + u_char xml __attribute__((packed)); + u_char mode __attribute__((packed)); + u_char fill __attribute__((packed)); +}; + +struct hdlc_hw { + union { + u_int ctrl; + struct hdlc_stat_reg sr; + } ctrl; + u_int stat; int rcvidx; int count; /* Current skb sent count */ u_char *rcvbuf; /* B-Channel receive Buffer */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; struct hfcB_hw { unsigned int *send; int f1; int f2; - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; struct tiger_hw { - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ u_int *send; u_int *s_irq; u_int *s_end; @@ -397,8 +501,7 @@ u_char s_state; }; -struct foreign_hw { - int doHDLCprocessing; +struct amd7930_hw { u_char *tx_buff; u_char *rv_buff; int rv_buff_in; @@ -407,9 +510,9 @@ struct hdlc_state *hdlc_state; struct tq_struct tq_rcv; struct tq_struct tq_xmt; - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ }; + #define BC_FLG_INIT 1 #define BC_FLG_ACTIV 2 #define BC_FLG_BUSY 3 @@ -420,6 +523,7 @@ #define L1_MODE_NULL 0 #define L1_MODE_TRANS 1 #define L1_MODE_HDLC 2 +#define L1_MODE_MODEM 7 struct BCState { int channel; @@ -427,34 +531,26 @@ int Flag; struct IsdnCardState *cs; int tx_cnt; /* B-Channel transmit counter */ + struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ struct sk_buff_head rqueue; /* B-Channel receive Queue */ struct sk_buff_head squeue; /* B-Channel send Queue */ struct PStack *st; + u_char *blog; + struct timer_list transbusy; struct tq_struct tqueue; int event; int (*BC_SetStack) (struct PStack *, struct BCState *); void (*BC_Close) (struct BCState *); union { struct hscx_hw hscx; + struct hdlc_hw hdlc; + struct isar_hw isar; struct hfcB_hw hfc; struct tiger_hw tiger; - struct foreign_hw foreign; + struct amd7930_hw amd7930; } hw; }; -struct LcFsm { - int type; - int delay; - struct FsmInst lcfi; - struct Channel *ch; - void (*lccall) (struct LcFsm *, int, void *); - struct PStack *st; - int l2_establish; - int l2_start; - struct FsmTimer act_timer; - char debug_id[32]; -}; - struct Channel { struct PStack *b_st, *d_st; struct IsdnCardState *cs; @@ -462,11 +558,10 @@ int chan; int incoming; struct FsmInst fi; - struct LcFsm *lc_d; - struct LcFsm *lc_b; struct FsmTimer drel_timer, dial_timer; int debug; int l2_protocol, l2_active_protocol; + int l3_protocol; int data_open; struct l3_process *proc; setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ @@ -487,21 +582,33 @@ unsigned int counter; unsigned int status; struct timer_list tl; + unsigned int MFlag; + struct BCState *bcs; + u_char *transbuf; + u_char *rcvbuf; + unsigned int transp; + unsigned int rcvp; + unsigned int transcnt; + unsigned int rcvcnt; + u_char IER; + u_char FCR; + u_char LCR; + u_char MCR; u_char ctrl_reg; -}; +}; struct teles3_hw { unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned int isacfifo; - unsigned int hscxfifo[2]; -}; + signed int isac; + signed int hscx[2]; + signed int isacfifo; + signed int hscxfifo[2]; +}; struct teles0_hw { unsigned int cfg_reg; unsigned int membase; -}; +}; struct avm_hw { unsigned int cfg_reg; @@ -510,7 +617,7 @@ unsigned int isacfifo; unsigned int hscxfifo[2]; unsigned int counter; -}; +}; struct ix1_hw { unsigned int cfg_reg; @@ -521,7 +628,8 @@ }; struct diva_hw { - unsigned int cfg_reg; + unsigned long cfg_reg; + unsigned long pci_cfg; unsigned int ctrl; unsigned int isac_adr; unsigned int isac; @@ -530,7 +638,7 @@ unsigned int status; struct timer_list tl; u_char ctrl_reg; -}; +}; struct asus_hw { unsigned int cfg_reg; @@ -559,6 +667,9 @@ unsigned int hscx; unsigned int reset_on; unsigned int reset_off; + struct isar_reg isar; + unsigned int chip; + unsigned int bus; }; struct spt_hw { @@ -566,7 +677,7 @@ unsigned int isac; unsigned int hscx[2]; unsigned char res_irq; -}; +}; struct mic_hw { unsigned int cfg_reg; @@ -587,6 +698,31 @@ unsigned char last_is0; }; +struct hfcPCI_hw { + unsigned char cirm; + unsigned char ctmt; + unsigned char conn; + unsigned char mst_m; + unsigned char int_m1; + unsigned char int_m2; + unsigned char int_s1; + unsigned char sctrl; + unsigned char sctrl_r; + unsigned char sctrl_e; + unsigned char trm; + unsigned char stat; + unsigned char fifo; + unsigned char fifo_en; + unsigned char bswapped; + /* unsigned int *send; */ + unsigned char pci_bus; + unsigned char pci_device_fn; + unsigned char *pci_io; /* start of PCI IO memory */ + void *share_start; /* shared memory for Fifos start */ + void *fifos; /* FIFO memory */ + struct timer_list timer; +}; + struct hfcD_hw { unsigned int addr; unsigned int bfifosize; @@ -608,24 +744,118 @@ struct timer_list timer; }; -#define HW_IOM1 0 -#define HW_IPAC 1 -#define FLG_TWO_DCHAN 4 -#define FLG_L1_DBUSY 5 -#define FLG_DBUSY_TIMER 6 -#define FLG_LOCK_ATOMIC 7 -#define HW_MON0_RX_END 8 -#define HW_MON1_RX_END 9 -#define HW_MON0_TX_END 10 -#define HW_MON1_TX_END 11 +struct isurf_hw { + unsigned int reset; + unsigned int isac; + unsigned int isar; + struct isar_reg isar_r; +}; + +struct saphir_hw { + unsigned int cfg_reg; + unsigned int ale; + unsigned int isac; + unsigned int hscx; + struct timer_list timer; +}; + +struct bkm_hw { + unsigned int base; + /* A4T stuff */ + unsigned int isac_adr; + unsigned int isac_ale; + unsigned int jade_adr; + unsigned int jade_ale; + /* Scitel Quadro stuff */ + unsigned int plx_adr; + unsigned int data_adr; +}; + +struct gazel_hw { + unsigned int cfg_reg; + unsigned int pciaddr[2]; + signed int ipac; + signed int isac; + signed int hscx[2]; + signed int isacfifo; + signed int hscxfifo[2]; + unsigned char timeslot; + unsigned char iom2; +}; + +#ifdef CONFIG_HISAX_TESTEMU +struct te_hw { + unsigned char *sfifo; + unsigned char *sfifo_w; + unsigned char *sfifo_r; + unsigned char *sfifo_e; + int sfifo_cnt; + unsigned int stat; +#ifdef COMPAT_HAS_NEW_WAITQ + wait_queue_head_t rwaitq; + wait_queue_head_t swaitq; +#else + struct wait_queue *rwaitq; + struct wait_queue *swaitq; +#endif +}; +#endif + +struct arcofi_msg { + struct arcofi_msg *next; + u_char receive; + u_char len; + u_char msg[10]; +}; + +struct isac_chip { + int ph_state; + u_char *mon_tx; + u_char *mon_rx; + int mon_txp; + int mon_txc; + int mon_rxp; + struct arcofi_msg *arcofi_list; + struct timer_list arcofitimer; +#ifdef COMPAT_HAS_NEW_WAITQ + wait_queue_head_t arcofi_wait; +#else + struct wait_queue *arcofi_wait; +#endif + u_char arcofi_bc; + u_char arcofi_state; + u_char mocr; + u_char adf2; +}; + +struct hfcd_chip { + int ph_state; +}; + +struct hfcpci_chip { + int ph_state; +}; + +#define HW_IOM1 0 +#define HW_IPAC 1 +#define HW_ISAR 2 +#define FLG_TWO_DCHAN 4 +#define FLG_L1_DBUSY 5 +#define FLG_DBUSY_TIMER 6 +#define FLG_LOCK_ATOMIC 7 +#define FLG_ARCOFI_TIMER 8 +#define FLG_ARCOFI_ERROR 9 struct IsdnCardState { unsigned char typ; unsigned char subtyp; int protocol; unsigned int irq; - int HW_Flags; + unsigned long irq_flags; + int HW_Flags; int *busy_flag; + int chanlimit; /* limited number of B-chans to use */ + int logecho; /* log echo if supported by card */ union { struct elsa_hw elsa; struct teles0_hw teles0; @@ -640,8 +870,15 @@ struct mic_hw mic; struct njet_hw njet; struct hfcD_hw hfcD; + struct hfcPCI_hw hfcpci; struct ix1_hw niccy; - struct foreign_interface *foreign; + struct isurf_hw isurf; + struct saphir_hw saphir; +#ifdef CONFIG_HISAX_TESTEMU + struct te_hw te; +#endif + struct bkm_hw ax; + struct gazel_hw gazel; } hw; int myid; isdn_if iif; @@ -657,10 +894,21 @@ void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char); void (*BC_Send_Data) (struct BCState *); int (*cardmsg) (struct IsdnCardState *, int, void *); - void (*l1cmd) (struct IsdnCardState *, int, void *); - struct Channel channel[2]; - struct BCState bcs[2]; + void (*setstack_d) (struct PStack *, struct IsdnCardState *); + void (*DC_Close) (struct IsdnCardState *); + void (*irq_func) (int, void *, struct pt_regs *); + struct Channel channel[2+MAX_WAITING_CALLS]; + struct BCState bcs[2+MAX_WAITING_CALLS]; struct PStack *stlist; + struct sk_buff_head rq, sq; /* D-channel queues */ + int cardnr; + char *dlog; + int debug; + union { + struct isac_chip isac; + struct hfcd_chip hfcd; + struct hfcpci_chip hfcpci; + } dc; u_char *rcvbuf; int rcvidx; struct sk_buff *tx_skb; @@ -668,19 +916,6 @@ int event; struct tq_struct tqueue; struct timer_list dbusytimer; - struct sk_buff_head rq, sq; /* D-channel queues */ - int ph_state; - int cardnr; - int dlogflag; - char *dlogspace; - int debug; - u_char *mon_tx; - u_char *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - u_char mocr; - void (*setstack_d) (struct PStack *, struct IsdnCardState *); }; #define MON0_RX 1 @@ -688,6 +923,8 @@ #define MON0_TX 4 #define MON1_TX 8 +#define HISAX_MAX_CARDS 8 + #define ISDN_CTYPE_16_0 1 #define ISDN_CTYPE_8_0 2 #define ISDN_CTYPE_16_3 3 @@ -712,19 +949,37 @@ #define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 #define ISDN_CTYPE_AMD7930 23 #define ISDN_CTYPE_NICCY 24 -#define ISDN_CTYPE_DBRI 25 +#define ISDN_CTYPE_S0BOX 25 +#define ISDN_CTYPE_A1_PCMCIA 26 +#define ISDN_CTYPE_FRITZPCI 27 +#define ISDN_CTYPE_SEDLBAUER_FAX 28 +#define ISDN_CTYPE_ISURF 29 +#define ISDN_CTYPE_ACERP10 30 +#define ISDN_CTYPE_HSTSAPHIR 31 +#define ISDN_CTYPE_BKM_A4T 32 +#define ISDN_CTYPE_SCT_QUADRO 33 +#define ISDN_CTYPE_GAZEL 34 +#define ISDN_CTYPE_HFC_PCI 35 +#define ISDN_CTYPE_COUNT 35 -#define ISDN_CTYPE_COUNT 25 #ifdef ISDN_CHIP_ISAC #undef ISDN_CHIP_ISAC #endif +#ifndef __initfunc +#define __initfunc(__arginit) __arginit +#endif + +#ifndef __initdata +#define __initdata +#endif + #define HISAX_INITFUNC(__arginit) __initfunc(__arginit) #define HISAX_INITDATA __initdata #ifdef CONFIG_HISAX_16_0 -#define CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0) +#define CARD_TELES0 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -733,8 +988,7 @@ #endif #ifdef CONFIG_HISAX_16_3 -#define CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP) | \ - (1<< ISDN_CTYPE_TELESPCMCIA) | (1<< ISDN_CTYPE_COMPAQ_ISA) +#define CARD_TELES3 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -742,18 +996,44 @@ #define CARD_TELES3 0 #endif +#ifdef CONFIG_HISAX_TELESPCI +#define CARD_TELESPCI 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_TELESPCI 0 +#endif + #ifdef CONFIG_HISAX_AVM_A1 -#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1) -#ifndef ISDN_CHIP_ISAC +#define CARD_AVM_A1 1 +#ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif #else #define CARD_AVM_A1 0 #endif +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#define CARD_AVM_A1_PCMCIA 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_AVM_A1_PCMCIA 0 +#endif + +#ifdef CONFIG_HISAX_FRITZPCI +#define CARD_FRITZPCI 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_FRITZPCI 0 +#endif + #ifdef CONFIG_HISAX_ELSA -#define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_PNP) | \ - (1<< ISDN_CTYPE_ELSA_PCMCIA) | (1<< ISDN_CTYPE_ELSA_PCI) +#define CARD_ELSA 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -765,9 +1045,8 @@ #define CARD_ELSA 0 #endif - #ifdef CONFIG_HISAX_IX1MICROR2 -#define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2) +#define CARD_IX1MICROR2 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -776,7 +1055,7 @@ #endif #ifdef CONFIG_HISAX_DIEHLDIVA -#define CARD_DIEHLDIVA (1 << ISDN_CTYPE_DIEHLDIVA) +#define CARD_DIEHLDIVA 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -785,7 +1064,7 @@ #endif #ifdef CONFIG_HISAX_ASUSCOM -#define CARD_ASUSCOM (1 << ISDN_CTYPE_ASUSCOM) +#define CARD_ASUSCOM 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -794,7 +1073,7 @@ #endif #ifdef CONFIG_HISAX_TELEINT -#define CARD_TELEINT (1 << ISDN_CTYPE_TELEINT) +#define CARD_TELEINT 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -803,7 +1082,7 @@ #endif #ifdef CONFIG_HISAX_SEDLBAUER -#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA) +#define CARD_SEDLBAUER 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -812,7 +1091,7 @@ #endif #ifdef CONFIG_HISAX_SPORTSTER -#define CARD_SPORTSTER (1 << ISDN_CTYPE_SPORTSTER) +#define CARD_SPORTSTER 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -821,7 +1100,7 @@ #endif #ifdef CONFIG_HISAX_MIC -#define CARD_MIC (1 << ISDN_CTYPE_MIC) +#define CARD_MIC 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -830,7 +1109,7 @@ #endif #ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET (1 << ISDN_CTYPE_NETJET) +#define CARD_NETJET 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -838,20 +1117,27 @@ #define CARD_NETJET 0 #endif -#ifdef CONFIG_HISAX_TELES3C -#define CARD_TELES3C (1<< ISDN_CTYPE_TELES3C) +#ifdef CONFIG_HISAX_HFCS +#define CARD_HFCS 1 #else -#define CARD_TELES3C 0 +#define CARD_HFCS 0 +#endif + +#ifdef CONFIG_HISAX_HFC_PCI +#define CARD_HFC_PCI 1 +extern int hfcpci_set_echo(struct IsdnCardState *, int); +#else +#define CARD_HFC_PCI 0 #endif #ifdef CONFIG_HISAX_AMD7930 -#define CARD_AMD7930 (1 << ISDN_CTYPE_AMD7930) +#define CARD_AMD7930 1 #else #define CARD_AMD7930 0 #endif #ifdef CONFIG_HISAX_NICCY -#define CARD_NICCY (1 << ISDN_CTYPE_NICCY) +#define CARD_NICCY 1 #ifndef ISDN_CHIP_ISAC #define ISDN_CHIP_ISAC 1 #endif @@ -859,18 +1145,68 @@ #define CARD_NICCY 0 #endif -#ifdef CONFIG_HISAX_DBRI -#define CARD_DBRI (1 << ISDN_CTYPE_DBRI) +#ifdef CONFIG_HISAX_ISURF +#define CARD_ISURF 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_ISURF 0 +#endif + +#ifdef CONFIG_HISAX_S0BOX +#define CARD_S0BOX 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_S0BOX 0 +#endif + +#ifdef CONFIG_HISAX_HSTSAPHIR +#define CARD_HSTSAPHIR 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif #else -#define CARD_DBRI 0 +#define CARD_HSTSAPHIR 0 #endif +#ifdef CONFIG_HISAX_TESTEMU +#define CARD_TESTEMU 1 +#define ISDN_CTYPE_TESTEMU 99 +#undef ISDN_CTYPE_COUNT +#define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU +#else +#define CARD_TESTEMU 0 +#endif -#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \ - | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \ - | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \ - | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \ - | CARD_NICCY | CARD_DBRI) +#ifdef CONFIG_HISAX_BKM_A4T +#define CARD_BKM_A4T 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_BKM_A4T 0 +#endif + +#ifdef CONFIG_HISAX_SCT_QUADRO +#define CARD_SCT_QUADRO 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_SCT_QUADRO 0 +#endif + +#ifdef CONFIG_HISAX_GAZEL +#define CARD_GAZEL 1 +#ifndef ISDN_CHIP_ISAC +#define ISDN_CHIP_ISAC 1 +#endif +#else +#define CARD_GAZEL 0 +#endif #define TEI_PER_CARD 0 @@ -883,25 +1219,38 @@ #undef TEI_PER_CARD #define TEI_PER_CARD 1 #define HISAX_EURO_SENDCOMPLETE 1 -#ifdef CONFIG_HISAX_ML +#define EXT_BEARER_CAPS 1 +#define HISAX_SEND_STD_LLC_IE 1 +#ifdef CONFIG_HISAX_NO_SENDCOMPLETE #undef HISAX_EURO_SENDCOMPLETE #endif +#ifdef CONFIG_HISAX_NO_LLC +#undef HISAX_SEND_STD_LLC_IE +#endif #undef HISAX_DE_AOC #ifdef CONFIG_DE_AOC #define HISAX_DE_AOC 1 #endif #endif -#if TEI_PER_CARD -#undef TEI_FIXED -#endif +/* L1 Debug */ +#define L1_DEB_WARN 0x01 +#define L1_DEB_INTSTAT 0x02 +#define L1_DEB_ISAC 0x04 +#define L1_DEB_ISAC_FIFO 0x08 +#define L1_DEB_HSCX 0x10 +#define L1_DEB_HSCX_FIFO 0x20 +#define L1_DEB_LAPD 0x40 +#define L1_DEB_IPAC 0x80 +#define L1_DEB_RECEIVE_FRAME 0x100 +#define L1_DEB_MONITOR 0x200 +#define DEB_DLOG_HEX 0x400 +#define DEB_DLOG_VERBOSE 0x800 -#undef PTP_DATA_LINK +#define L2FRAME_DEBUG -#ifdef PTP_DATA_LINK -#undef TEI_FIXED -#define TEI_FIXED 0 -#define LAYER2_WATCHING +#ifdef L2FRAME_DEBUG +extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif struct IsdnCard { @@ -911,17 +1260,26 @@ struct IsdnCardState *cs; }; -void setstack_isdnl2(struct PStack *st, char *debug_id); -int HiSax_inithardware(int *); -void HiSax_closehardware(void); +void init_bcstate(struct IsdnCardState *cs, int bc); void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs); unsigned int random_ri(void); -void setstack_isdnl3(struct PStack *st, struct Channel *chanp); void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); +void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); + +void setstack_l1_B(struct PStack *st); + +void setstack_tei(struct PStack *st); +void setstack_manager(struct PStack *st); + +void setstack_isdnl2(struct PStack *st, char *debug_id); void releasestack_isdnl2(struct PStack *st); +void setstack_transl2(struct PStack *st); +void releasestack_transl2(struct PStack *st); + +void setstack_l3dc(struct PStack *st, struct Channel *chanp); +void setstack_l3bc(struct PStack *st, struct Channel *chanp); void releasestack_isdnl3(struct PStack *st); -void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); u_char *findie(u_char * p, int size, u_char ie, int wanted_set); int getcallref(u_char * p); @@ -937,20 +1295,18 @@ void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, void *arg, int where); void FsmDelTimer(struct FsmTimer *ft, int where); -void jiftime(char *s, long mark); +int jiftime(char *s, long mark); int HiSax_command(isdn_ctrl * ic); int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); -void HiSax_putstatus(struct IsdnCardState *csta, char *buf); +void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...); +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args); void HiSax_reportcard(int cardnr); int QuickHex(char *txt, u_char * p, int cnt); -void LogFrame(struct IsdnCardState *sp, u_char * p, int size); -void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment); +void LogFrame(struct IsdnCardState *cs, u_char * p, int size); +void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); void iecpy(u_char * dest, u_char * iestart, int ieoffset); -void setstack_transl2(struct PStack *st); -void releasestack_transl2(struct PStack *st); -void setstack_tei(struct PStack *st); -void setstack_manager(struct PStack *st); +int discard_queue(struct sk_buff_head *q); #ifdef ISDN_CHIP_ISAC void setstack_isac(struct PStack *st, struct IsdnCardState *cs); #endif /* ISDN_CHIP_ISAC */ @@ -958,18 +1314,21 @@ #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} -int ll_run(struct IsdnCardState *csta); -void ll_stop(struct IsdnCardState *csta); +int ll_run(struct IsdnCardState *cs); +void ll_stop(struct IsdnCardState *cs); void CallcNew(void); void CallcFree(void); -int CallcNewChan(struct IsdnCardState *csta); -void CallcFreeChan(struct IsdnCardState *csta); +int CallcNewChan(struct IsdnCardState *cs); +void CallcFreeChan(struct IsdnCardState *cs); void Isdnl1New(void); void Isdnl1Free(void); void Isdnl2New(void); void Isdnl2Free(void); -void init_tei(struct IsdnCardState *sp, int protocol); -void release_tei(struct IsdnCardState *sp); +void Isdnl3New(void); +void Isdnl3Free(void); +void init_tei(struct IsdnCardState *cs, int protocol); +void release_tei(struct IsdnCardState *cs); char *HiSax_getrev(const char *revision); void TeiNew(void); void TeiFree(void); +int certification_check(int output); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c --- v2.2.10/linux/drivers/isdn/hisax/hscx.c Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/hscx.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,43 @@ -/* $Id: hscx.c,v 1.7 1998/02/12 23:07:36 keil Exp $ +/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $ * hscx.c HSCX specific routines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: hscx.c,v $ + * Revision 1.17 1999/07/01 08:11:41 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.16 1998/11/15 23:54:48 keil + * changes from 2.0 + * + * Revision 1.15 1998/08/20 13:50:42 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.14 1998/08/13 23:36:33 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.13 1998/06/26 22:03:28 keil + * send flags between hdlc frames + * + * Revision 1.12 1998/06/09 18:26:01 keil + * PH_DEACTIVATE B-channel every time signaled to higher layer + * + * Revision 1.11 1998/05/25 14:10:07 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 1.10 1998/05/25 12:57:59 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.9 1998/04/15 16:45:33 keil + * new init code + * + * Revision 1.8 1998/03/19 13:16:24 keil + * fix the correct release of the hscx + * * Revision 1.7 1998/02/12 23:07:36 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -30,6 +62,7 @@ #define __NO_VERSION__ #include "hisax.h" #include "hscx.h" +#include "isac.h" #include "isdnl1.h" #include @@ -56,21 +89,20 @@ modehscx(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->channel; + int hscx = bcs->hw.hscx.hscx; - if (cs->debug & L1_DEB_HSCX) { - char tmp[40]; - sprintf(tmp, "hscx %c mode %d ichan %d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "hscx %c mode %d ichan %d", 'A' + hscx, mode, bc); - debugl1(cs, tmp); - } bcs->mode = mode; - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, 0x85); + bcs->channel = bc; cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF); cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0); cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0); + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, + test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85); cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30); cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7); cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7); @@ -81,23 +113,25 @@ if (bc == 0) { cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f); + test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : 0x2f); + test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); } else { - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x3); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x3); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1); } switch (mode) { case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0xff); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0xff); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f); + cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f); cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84); break; case (L1_MODE_TRANS): cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4); break; case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, + test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c); break; } @@ -114,89 +148,106 @@ mark_bh(IMMEDIATE_BH); } -static void +void hscx_l2l1(struct PStack *st, int pr, void *arg) { struct sk_buff *skb = arg; long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.hscx.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.hscx.tx_skb = skb; + st->l1.bcs->tx_skb = skb; test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); st->l1.bcs->hw.hscx.count = 0; restore_flags(flags); st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.hscx.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); break; } test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); - st->l1.bcs->hw.hscx.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->hw.hscx.count = 0; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.hscx.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + modehscx(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + modehscx(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } - } void close_hscxstate(struct BCState *bcs) { - struct sk_buff *skb; - - modehscx(bcs, 0, 0); + modehscx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { if (bcs->hw.hscx.rcvbuf) { kfree(bcs->hw.hscx.rcvbuf); bcs->hw.hscx.rcvbuf = NULL; } - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; } - if (bcs->hw.hscx.tx_skb) { - dev_kfree_skb(bcs->hw.hscx.tx_skb); - bcs->hw.hscx.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } -static int -open_hscxstate(struct IsdnCardState *cs, - int bc) +int +open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); + "HiSax: No memory for hscx.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); return (1); } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.hscx.tx_skb = NULL; + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; bcs->hw.hscx.rcvidx = 0; @@ -204,77 +255,78 @@ return (0); } -static void -hscx_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - modehscx(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - modehscx(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_hscx(struct PStack *st, struct BCState *bcs) { - if (open_hscxstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_hscxstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = hscx_l2l1; - st->ma.manl1 = hscx_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } HISAX_INITFUNC(void clear_pending_hscx_ints(struct IsdnCardState *cs)) { - int val; - char tmp[64]; + int val, eval; val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA); - sprintf(tmp, "HSCX B ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX B ISTA %x", val); if (val & 0x01) { - val = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); - sprintf(tmp, "HSCX B EXIR %x", val); - debugl1(cs, tmp); - } else if (val & 0x02) { - val = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); - sprintf(tmp, "HSCX A EXIR %x", val); - debugl1(cs, tmp); + eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); + debugl1(cs, "HSCX B EXIR %x", eval); + } + if (val & 0x02) { + eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); + debugl1(cs, "HSCX A EXIR %x", eval); } val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA); - sprintf(tmp, "HSCX A ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX A ISTA %x", val); val = cs->BC_Read_Reg(cs, 1, HSCX_STAR); - sprintf(tmp, "HSCX B STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX B STAR %x", val); val = cs->BC_Read_Reg(cs, 0, HSCX_STAR); - sprintf(tmp, "HSCX A STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "HSCX A STAR %x", val); + /* disable all IRQ */ cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF); cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); } -HISAX_INITFUNC(void +HISAX_INITFUNC(void inithscx(struct IsdnCardState *cs)) { cs->bcs[0].BC_SetStack = setstack_hscx; cs->bcs[1].BC_SetStack = setstack_hscx; cs->bcs[0].BC_Close = close_hscxstate; cs->bcs[1].BC_Close = close_hscxstate; + cs->bcs[0].hw.hscx.hscx = 0; + cs->bcs[1].hw.hscx.hscx = 1; + cs->bcs[0].hw.hscx.tsaxr0 = 0x2f; + cs->bcs[0].hw.hscx.tsaxr1 = 3; + cs->bcs[1].hw.hscx.tsaxr0 = 0x2f; + cs->bcs[1].hw.hscx.tsaxr1 = 3; modehscx(cs->bcs, 0, 0); modehscx(cs->bcs + 1, 0, 0); +} + +HISAX_INITFUNC(void +inithscxisac(struct IsdnCardState *cs, int part)) +{ + if (part & 1) { + clear_pending_isac_ints(cs); + clear_pending_hscx_ints(cs); + initisac(cs); + inithscx(cs); + } + if (part & 2) { + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); + cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + } } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hscx.h linux/drivers/isdn/hisax/hscx.h --- v2.2.10/linux/drivers/isdn/hisax/hscx.h Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/hscx.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: hscx.h,v 1.3 1997/07/27 21:38:35 keil Exp $ +/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $ * hscx.h HSCX specific defines * @@ -6,6 +6,9 @@ * * * $Log: hscx.h,v $ + * Revision 1.4 1998/04/15 16:45:34 keil + * new init code + * * Revision 1.3 1997/07/27 21:38:35 keil * new B-channel interface * @@ -44,3 +47,4 @@ extern void modehscx(struct BCState *bcs, int mode, int bc); extern void clear_pending_hscx_ints(struct IsdnCardState *cs); extern void inithscx(struct IsdnCardState *cs); +extern void inithscxisac(struct IsdnCardState *cs, int part); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c --- v2.2.10/linux/drivers/isdn/hisax/hscx_irq.c Thu May 14 18:42:40 1998 +++ linux/drivers/isdn/hisax/hscx_irq.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,27 @@ -/* $Id: hscx_irq.c,v 1.7 1998/02/12 23:07:37 keil Exp $ +/* $Id: hscx_irq.c,v 1.12 1999/07/01 08:11:42 keil Exp $ * hscx_irq.c low level b-channel stuff for Siemens HSCX * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * This is an include file for fast inline IRQ stuff * * $Log: hscx_irq.c,v $ + * Revision 1.12 1999/07/01 08:11:42 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.11 1998/11/15 23:54:49 keil + * changes from 2.0 + * + * Revision 1.10 1998/08/13 23:36:35 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.9 1998/06/24 14:44:51 keil + * Fix recovery of TX IRQ loss + * + * Revision 1.8 1998/04/10 10:35:22 paul + * fixed (silly?) warnings from egcs on Alpha. + * * Revision 1.7 1998/02/12 23:07:37 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -85,7 +100,7 @@ if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - WriteHSCXCMDR(cs, bcs->channel, 0x80); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); bcs->hw.hscx.rcvidx = 0; return; } @@ -93,17 +108,16 @@ bcs->hw.hscx.rcvidx += count; save_flags(flags); cli(); - READHSCXFIFO(cs, bcs->channel, ptr, count); - WriteHSCXCMDR(cs, bcs->channel, 0x80); + READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256]; - char *t = tmp; + char *t = bcs->blog; t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); + bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, bcs->blog); } } @@ -120,36 +134,35 @@ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hscx_fill_fifo"); - if (!bcs->hw.hscx.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->hw.hscx.tx_skb->len <= 0) + if (bcs->tx_skb->len <= 0) return; more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->hw.hscx.tx_skb->len > fifo_size) { + if (bcs->tx_skb->len > fifo_size) { more = !0; count = fifo_size; } else - count = bcs->hw.hscx.tx_skb->len; + count = bcs->tx_skb->len; - waitforXFW(cs, bcs->channel); + waitforXFW(cs, bcs->hw.hscx.hscx); save_flags(flags); cli(); - ptr = bcs->hw.hscx.tx_skb->data; - skb_pull(bcs->hw.hscx.tx_skb, count); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); bcs->tx_cnt -= count; bcs->hw.hscx.count += count; - WRITEHSCXFIFO(cs, bcs->channel, ptr, count); - WriteHSCXCMDR(cs, bcs->channel, more ? 0x8 : 0xa); + WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); restore_flags(flags); if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256]; - char *t = tmp; + char *t = bcs->blog; t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); + bcs->hw.hscx.hscx ? 'B' : 'A', count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, bcs->blog); } } @@ -161,7 +174,6 @@ struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; - char tmp[32]; if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; @@ -173,11 +185,9 @@ if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX invalid frame"); if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX RDO mode=%d", + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX RDO mode=%d", bcs->mode); - debugl1(cs, tmp); - } if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX CRC error"); @@ -189,13 +199,12 @@ count = fifo_size; hscx_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) { - sprintf(tmp, "HX Frame %d", count); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { + SET_SKB_FREE(skb); memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } @@ -211,6 +220,7 @@ if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { + SET_SKB_FREE(skb); memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); skb_queue_tail(&bcs->rqueue, skb); } @@ -219,20 +229,20 @@ } } if (val & 0x10) { /* XPR */ - if (bcs->hw.hscx.tx_skb) { - if (bcs->hw.hscx.tx_skb->len) { + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { hscx_fill_fifo(bcs); return; } else { if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.hscx.tx_skb->pkt_type)) + (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->hw.hscx.tx_skb); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); bcs->hw.hscx.count = 0; - bcs->hw.hscx.tx_skb = NULL; + bcs->tx_skb = NULL; } } - if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hscx_fill_fifo(bcs); @@ -249,73 +259,60 @@ u_char exval; struct BCState *bcs; - char tmp[32]; if (val & 0x01) { bcs = cs->bcs + 1; exval = READHSCX(cs, 1, HSCX_EXIR); - if (exval == 0x40) { + if (exval & 0x40) { if (bcs->mode == 1) hscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - if (bcs->hw.hscx.tx_skb) { - skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count); + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } - WriteHSCXCMDR(cs, bcs->channel, 0x01); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX B EXIR %x Lost TX", exval); - debugl1(cs, tmp); - } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX B EXIR %x Lost TX", exval); } - } else if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX B EXIR %x", exval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B EXIR %x", exval); } if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX B interrupt %x", val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX B interrupt %x", val); hscx_interrupt(cs, val, 1); } if (val & 0x02) { bcs = cs->bcs; exval = READHSCX(cs, 0, HSCX_EXIR); - if (exval == 0x40) { + if (exval & 0x40) { if (bcs->mode == L1_MODE_TRANS) hscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ - if (bcs->hw.hscx.tx_skb) { - skb_push(bcs->hw.hscx.tx_skb, bcs->hw.hscx.count); + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } - WriteHSCXCMDR(cs, bcs->channel, 0x01); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "HSCX A EXIR %x Lost TX", exval); - debugl1(cs, tmp); - } + WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "HSCX A EXIR %x Lost TX", exval); } - } else if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX A EXIR %x", exval); - debugl1(cs, tmp); - } + } else if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A EXIR %x", exval); } if (val & 0x04) { exval = READHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "HSCX A interrupt %x", exval); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX A interrupt %x", exval); hscx_interrupt(cs, exval, 0); } } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/ipac.h linux/drivers/isdn/hisax/ipac.h --- v2.2.10/linux/drivers/isdn/hisax/ipac.h Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/ipac.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: ipac.h,v 1.2 1997/10/29 18:51:21 keil Exp $ +/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $ * ipac.h IPAC specific defines * @@ -6,6 +6,9 @@ * * * $Log: ipac.h,v $ + * Revision 1.3 1998/04/15 16:48:09 keil + * IPAC_ATX added + * * Revision 1.2 1997/10/29 18:51:21 keil * New files * @@ -26,6 +29,7 @@ #define IPAC_ACFG 0xC3 #define IPAC_AOE 0xC4 #define IPAC_ARX 0xC5 +#define IPAC_ATX 0xC5 #define IPAC_PITA1 0xC6 #define IPAC_PITA2 0xC7 #define IPAC_POTA1 0xC8 diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c --- v2.2.10/linux/drivers/isdn/hisax/isac.c Thu May 14 18:43:27 1998 +++ linux/drivers/isdn/hisax/isac.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,43 @@ -/* $Id: isac.c,v 1.12 1998/02/12 23:07:40 keil Exp $ +/* $Id: isac.c,v 1.21 1999/07/12 21:05:17 keil Exp $ * isac.c ISAC specific routines * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.21 1999/07/12 21:05:17 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.20 1999/07/09 08:23:06 keil + * Fix ISAC lost TX IRQ handling + * + * Revision 1.19 1999/07/01 08:11:43 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.18 1998/11/15 23:54:51 keil + * changes from 2.0 + * + * Revision 1.17 1998/08/13 23:36:37 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.16 1998/05/25 12:58:01 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.15 1998/04/15 16:45:32 keil + * new init code + * + * Revision 1.14 1998/04/10 10:35:26 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 1.13 1998/03/07 22:57:01 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.12 1998/02/12 23:07:40 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -47,6 +79,7 @@ #define __NO_VERSION__ #include "hisax.h" #include "isac.h" +#include "arcofi.h" #include "isdnl1.h" #include @@ -63,60 +96,47 @@ int val; val = cs->readisac(cs, ISAC_RBCH); - printk(KERN_INFO "%s ISAC version : %s\n", s, ISACVer[(val >> 5) & 3]); + printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]); } static void ph_command(struct IsdnCardState *cs, unsigned int command) { - if (cs->debug & L1_DEB_ISAC) { - char tmp[32]; - sprintf(tmp, "ph_command %x", command); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_command %x", command); cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3); } -static void -manl1_msg(struct IsdnCardState *cs, int msg, void *arg) { - struct PStack *st; - - st = cs->stlist; - while (st) { - st->ma.manl1(st, msg, arg); - st = st->next; - } -} static void isac_new_ph(struct IsdnCardState *cs) { - switch (cs->ph_state) { + switch (cs->dc.isac.ph_state) { case (ISAC_IND_RS): case (ISAC_IND_EI): ph_command(cs, ISAC_CMD_DUI); - manl1_msg(cs, PH_RESET_IND, NULL); + l1_msg(cs, HW_RESET | INDICATION, NULL); break; case (ISAC_IND_DID): - manl1_msg(cs, PH_DEACT_CNF, NULL); + l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); break; case (ISAC_IND_DR): - manl1_msg(cs, PH_DEACT_IND, NULL); + l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); break; case (ISAC_IND_PU): - manl1_msg(cs, PH_POWERUP_CNF, NULL); + l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (ISAC_IND_RSY): - manl1_msg(cs, PH_RSYNC_IND, NULL); + l1_msg(cs, HW_RSYNC | INDICATION, NULL); break; case (ISAC_IND_ARD): - manl1_msg(cs, PH_INFO2_IND, NULL); + l1_msg(cs, HW_INFO2 | INDICATION, NULL); break; case (ISAC_IND_AI8): - manl1_msg(cs, PH_I4_P8_IND, NULL); + l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; case (ISAC_IND_AI10): - manl1_msg(cs, PH_I4_P10_IND, NULL); + l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); break; default: break; @@ -130,13 +150,12 @@ if (!cs) return; - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); stptr = cs->stlist; while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); stptr = stptr->next; } } @@ -146,14 +165,10 @@ DChannel_proc_rcv(cs); if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) DChannel_proc_xmt(cs); - if (test_and_clear_bit(D_RX_MON0, &cs->event)) - test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags); if (test_and_clear_bit(D_RX_MON1, &cs->event)) - test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags); - if (test_and_clear_bit(D_TX_MON0, &cs->event)) - test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags); + arcofi_fsm(cs, ARCOFI_RX_END, NULL); if (test_and_clear_bit(D_TX_MON1, &cs->event)) - test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags); + arcofi_fsm(cs, ARCOFI_TX_END, NULL); } void @@ -165,13 +180,10 @@ if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) debugl1(cs, "isac_empty_fifo"); - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN) { - if (cs->debug & L1_DEB_WARN) { - char tmp[40]; - sprintf(tmp, "isac_empty_fifo overrun %d", + if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isac_empty_fifo overrun %d", cs->rcvidx + count); - debugl1(cs, tmp); - } cs->writeisac(cs, ISAC_CMDR, 0x80); cs->rcvidx = 0; return; @@ -184,12 +196,11 @@ cs->writeisac(cs, ISAC_CMDR, 0x80); restore_flags(flags); if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; + char *t = cs->dlog; t += sprintf(t, "isac_empty_fifo cnt %d", count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, cs->dlog); } } @@ -231,12 +242,11 @@ cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&cs->dbusytimer); if (cs->debug & L1_DEB_ISAC_FIFO) { - char tmp[128]; - char *t = tmp; + char *t = cs->dlog; t += sprintf(t, "isac_fill_fifo cnt %d", count); QuickHex(t, ptr, count); - debugl1(cs, tmp); + debugl1(cs, cs->dlog); } } @@ -255,12 +265,9 @@ struct sk_buff *skb; unsigned int count; long flags; - char tmp[32]; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ISAC interrupt %x", val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC interrupt %x", val); if (val & 0x80) { /* RME */ exval = cs->readisac(cs, ISAC_RSTA); if ((exval & 0x70) != 0x20) { @@ -283,6 +290,7 @@ if (!(skb = alloc_skb(count, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { + SET_SKB_FREE(skb); memcpy(skb_put(skb, count), cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } @@ -310,7 +318,7 @@ isac_fill_fifo(cs); goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + idev_kfree_skb(cs->tx_skb, FREE_WRITE); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -323,12 +331,20 @@ } afterXPR: if (val & 0x04) { /* CISQ */ - cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "ph_state change %x", cs->ph_state); - debugl1(cs, tmp); + exval = cs->readisac(cs, ISAC_CIR0); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC CIR0 %02X", exval ); + if (exval & 2) { + cs->dc.isac.ph_state = (exval >> 2) & 0xf; + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state); + isac_sched_event(cs, D_L1STATECHANGE); + } + if (exval & 1) { + exval = cs->readisac(cs, ISAC_CIR1); + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC CIR1 %02X", exval ); } - isac_sched_event(cs, D_L1STATECHANGE); } if (val & 0x02) { /* SIN */ /* never */ @@ -337,131 +353,149 @@ } if (val & 0x01) { /* EXI */ exval = cs->readisac(cs, ISAC_EXIR); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC EXIR %02x", exval); - debugl1(cs, tmp); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "ISAC EXIR %02x", exval); + if (exval & 0x80) { /* XMR */ + debugl1(cs, "ISAC XMR"); + printk(KERN_WARNING "HiSax: ISAC XMR\n"); } - if (exval & 0x04) { - v1 = cs->readisac(cs, ISAC_MOSR); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOSR %02x", v1); - debugl1(cs, tmp); + if (exval & 0x40) { /* XDU */ + debugl1(cs, "ISAC XDU"); + printk(KERN_WARNING "HiSax: ISAC XDU\n"); + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + isac_sched_event(cs, D_CLEARBUSY); + if (cs->tx_skb) { /* Restart frame */ + skb_push(cs->tx_skb, cs->tx_cnt); + cs->tx_cnt = 0; + isac_fill_fifo(cs); + } else { + printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); + debugl1(cs, "ISAC XDU no skb"); } + } + if (exval & 0x04) { /* MOS */ + v1 = cs->readisac(cs, ISAC_MOSR); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOSR %02x", v1); #if ARCOFI_USE if (v1 & 0x08) { - if (!cs->mon_rx) { - if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (!cs->dc.isac.mon_rx) { + if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX out of memory!"); - cs->mocr &= 0xf0; - cs->mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + cs->dc.isac.mocr &= 0xf0; + cs->dc.isac.mocr |= 0x0a; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); goto afterMONR0; } else - cs->mon_rxp = 0; + cs->dc.isac.mon_rxp = 0; } - if (cs->mon_rxp >= MAX_MON_FRAME) { - cs->mocr &= 0xf0; - cs->mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); - cs->mon_rxp = 0; + if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { + cs->dc.isac.mocr &= 0xf0; + cs->dc.isac.mocr |= 0x0a; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX overflow!"); goto afterMONR0; } - cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR0); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]); - debugl1(cs, tmp); - } - if (cs->mon_rxp == 1) { - cs->mocr |= 0x04; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); + if (cs->dc.isac.mon_rxp == 1) { + cs->dc.isac.mocr |= 0x04; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); } } afterMONR0: if (v1 & 0x80) { - if (!cs->mon_rx) { - if (!(cs->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { + if (!cs->dc.isac.mon_rx) { + if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX out of memory!"); - cs->mocr &= 0x0f; - cs->mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + cs->dc.isac.mocr &= 0x0f; + cs->dc.isac.mocr |= 0xa0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); goto afterMONR1; } else - cs->mon_rxp = 0; + cs->dc.isac.mon_rxp = 0; } - if (cs->mon_rxp >= MAX_MON_FRAME) { - cs->mocr &= 0x0f; - cs->mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); - cs->mon_rxp = 0; + if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { + cs->dc.isac.mocr &= 0x0f; + cs->dc.isac.mocr |= 0xa0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mon_rxp = 0; if (cs->debug & L1_DEB_WARN) debugl1(cs, "ISAC MON RX overflow!"); goto afterMONR1; } - cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR1); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]); - debugl1(cs, tmp); - } - if (cs->mon_rxp == 1) { - cs->mocr |= 0x40; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); - } + cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]); + cs->dc.isac.mocr |= 0x40; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); } afterMONR1: if (v1 & 0x04) { - cs->mocr &= 0xf0; - cs->mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + cs->dc.isac.mocr &= 0xf0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mocr |= 0x0a; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); isac_sched_event(cs, D_RX_MON0); } if (v1 & 0x40) { - cs->mocr &= 0x0f; - cs->mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + cs->dc.isac.mocr &= 0x0f; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mocr |= 0xa0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); isac_sched_event(cs, D_RX_MON1); } if (v1 & 0x02) { - if (!cs->mon_tx) { - cs->mocr &= 0xf0; - cs->mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && + (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && + !(v1 & 0x08))) { + cs->dc.isac.mocr &= 0xf0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mocr |= 0x0a; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + if (cs->dc.isac.mon_txc && + (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) + isac_sched_event(cs, D_TX_MON0); goto AfterMOX0; } - if (cs->mon_txp >= cs->mon_txc) { - if (cs->mon_txc) - isac_sched_event(cs, D_TX_MON0); + if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { + isac_sched_event(cs, D_TX_MON0); goto AfterMOX0; } cs->writeisac(cs, ISAC_MOX0, - cs->mon_tx[cs->mon_txp++]); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]); - debugl1(cs, tmp); - } + cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); } AfterMOX0: if (v1 & 0x20) { - if (!cs->mon_tx) { - cs->mocr &= 0x0f; - cs->mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->mocr); + if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && + (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && + !(v1 & 0x80))) { + cs->dc.isac.mocr &= 0x0f; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + cs->dc.isac.mocr |= 0xa0; + cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); + if (cs->dc.isac.mon_txc && + (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) + isac_sched_event(cs, D_TX_MON1); goto AfterMOX1; } - if (cs->mon_txp >= cs->mon_txc) { - if (cs->mon_txc) - isac_sched_event(cs, D_TX_MON1); + if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { + isac_sched_event(cs, D_TX_MON1); goto AfterMOX1; } cs->writeisac(cs, ISAC_MOX1, - cs->mon_tx[cs->mon_txp++]); - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]); - debugl1(cs, tmp); - } + cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); + if (cs->debug & L1_DEB_MONITOR) + debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); } AfterMOX1: #endif @@ -470,14 +504,18 @@ } static void -ISAC_l2l1(struct PStack *st, int pr, void *arg) +ISAC_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; - char str[64]; + int val; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA |REQUEST): + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ @@ -485,12 +523,6 @@ Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ - LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -500,19 +532,17 @@ isac_fill_fifo(cs); } break; - case (PH_PULL_IND): + case (PH_PULL |INDICATION): if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); break; } - if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ + if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(cs, skb->data + 4, skb->len - 4, - str); - } + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ @@ -521,46 +551,36 @@ #endif isac_fill_fifo(cs); break; - case (PH_PULL_REQ): + case (PH_PULL | REQUEST): #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); #endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; - } -} - -void -isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg) -{ - u_char val; - char tmp[32]; - - switch(msg) { - case PH_RESET_REQ: - if ((cs->ph_state == ISAC_IND_EI) || - (cs->ph_state == ISAC_IND_DR) || - (cs->ph_state == ISAC_IND_RS)) + case (HW_RESET | REQUEST): + if ((cs->dc.isac.ph_state == ISAC_IND_EI) || + (cs->dc.isac.ph_state == ISAC_IND_DR) || + (cs->dc.isac.ph_state == ISAC_IND_RS)) ph_command(cs, ISAC_CMD_TIM); else ph_command(cs, ISAC_CMD_RS); break; - case PH_ENABLE_REQ: + case (HW_ENABLE | REQUEST): ph_command(cs, ISAC_CMD_TIM); break; - case PH_INFO3_REQ: + case (HW_INFO3 | REQUEST): ph_command(cs, ISAC_CMD_AR8); break; - case PH_TESTLOOP_REQ: + case (HW_TESTLOOP | REQUEST): val = 0; - if (1 & (int) arg) + if (1 & (long) arg) val |= 0x0c; - if (2 & (int) arg) + if (2 & (long) arg) val |= 0x3; if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ @@ -580,11 +600,21 @@ cs->writeisac(cs, ISAC_ADF1, 0x0); } break; - default: - if (cs->debug & L1_DEB_WARN) { - sprintf(tmp, "isac_l1cmd unknown %4x", msg); - debugl1(cs, tmp); + case (HW_DEACTIVATE | RESPONSE): + discard_queue(&cs->rq); + discard_queue(&cs->sq); + if (cs->tx_skb) { + idev_kfree_skb(cs->tx_skb, FREE_WRITE); + cs->tx_skb = NULL; } + if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) + del_timer(&cs->dbusytimer); + if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) + isac_sched_event(cs, D_CLEARBUSY); + break; + default: + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isac_l1hw unknown %04x", pr); break; } } @@ -592,23 +622,53 @@ void setstack_isac(struct PStack *st, struct IsdnCardState *cs) { - st->l2.l2l1 = ISAC_l2l1; + st->l1.l1hw = ISAC_l1hw; +} + +void +DC_Close_isac(struct IsdnCardState *cs) { + if (cs->dc.isac.mon_rx) { + kfree(cs->dc.isac.mon_rx); + cs->dc.isac.mon_rx = NULL; + } + if (cs->dc.isac.mon_tx) { + kfree(cs->dc.isac.mon_tx); + cs->dc.isac.mon_tx = NULL; + } } static void dbusy_timer_handler(struct IsdnCardState *cs) { struct PStack *stptr; + int rbch, star; if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy"); - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL); - stptr = stptr->next; + rbch = cs->readisac(cs, ISAC_RBCH); + star = cs->readisac(cs, ISAC_STAR); + if (cs->debug) + debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", + rbch, star); + if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */ + test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); + stptr = cs->stlist; + while (stptr != NULL) { + stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); + stptr = stptr->next; + } + } else { + /* discard frame; reset transceiver */ + test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); + if (cs->tx_skb) { + idev_kfree_skb(cs->tx_skb, FREE_WRITE); + cs->tx_cnt = 0; + cs->tx_skb = NULL; + } else { + printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); + debugl1(cs, "D-Channel Busy no skb"); + } + cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ + cs->irq_func(cs->irq, cs, NULL); } } } @@ -617,13 +677,15 @@ initisac(struct IsdnCardState *cs)) { cs->tqueue.routine = (void *) (void *) isac_bh; - cs->l1cmd = isac_l1cmd; cs->setstack_d = setstack_isac; + cs->DC_Close = DC_Close_isac; + cs->dc.isac.mon_tx = NULL; + cs->dc.isac.mon_rx = NULL; cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer); cs->writeisac(cs, ISAC_MASK, 0xff); - cs->mocr = 0xaa; + cs->dc.isac.mocr = 0xaa; if (test_bit(HW_IOM1, &cs->HW_Flags)) { /* IOM 1 Mode */ cs->writeisac(cs, ISAC_ADF2, 0x0); @@ -633,7 +695,9 @@ cs->writeisac(cs, ISAC_MODE, 0xc9); } else { /* IOM 2 Mode */ - cs->writeisac(cs, ISAC_ADF2, 0x80); + if (!cs->dc.isac.adf2) + cs->dc.isac.adf2 = 0x80; + cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2); cs->writeisac(cs, ISAC_SQXR, 0x2f); cs->writeisac(cs, ISAC_SPCR, 0x00); cs->writeisac(cs, ISAC_STCR, 0x70); @@ -648,35 +712,24 @@ HISAX_INITFUNC(void clear_pending_isac_ints(struct IsdnCardState *cs)) { - int val; - char tmp[64]; + int val, eval; val = cs->readisac(cs, ISAC_STAR); - sprintf(tmp, "ISAC STAR %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC STAR %x", val); val = cs->readisac(cs, ISAC_MODE); - sprintf(tmp, "ISAC MODE %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC MODE %x", val); val = cs->readisac(cs, ISAC_ADF2); - sprintf(tmp, "ISAC ADF2 %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC ADF2 %x", val); val = cs->readisac(cs, ISAC_ISTA); - sprintf(tmp, "ISAC ISTA %x", val); - debugl1(cs, tmp); + debugl1(cs, "ISAC ISTA %x", val); if (val & 0x01) { - val = cs->readisac(cs, ISAC_EXIR); - sprintf(tmp, "ISAC EXIR %x", val); - debugl1(cs, tmp); - } else if (val & 0x04) { - val = cs->readisac(cs, ISAC_CIR0); - sprintf(tmp, "ISAC CIR0 %x", val); - debugl1(cs, tmp); - cs->ph_state = (val >> 2) & 0xf; - } else { - cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf; + eval = cs->readisac(cs, ISAC_EXIR); + debugl1(cs, "ISAC EXIR %x", eval); } + val = cs->readisac(cs, ISAC_CIR0); + debugl1(cs, "ISAC CIR0 %x", val); + cs->dc.isac.ph_state = (val >> 2) & 0xf; isac_sched_event(cs, D_L1STATECHANGE); + /* Disable all IRQ */ cs->writeisac(cs, ISAC_MASK, 0xFF); - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isac.h linux/drivers/isdn/hisax/isac.h --- v2.2.10/linux/drivers/isdn/hisax/isac.h Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/isac.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isac.h,v 1.4 1997/10/29 19:09:34 keil Exp $ +/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $ * isac.h ISAC specific defines * @@ -6,6 +6,10 @@ * * * $Log: isac.h,v $ + * Revision 1.5 1998/05/25 12:58:03 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 1.4 1997/10/29 19:09:34 keil * new L1 * @@ -26,16 +30,18 @@ #define ISAC_STAR 0x21 #define ISAC_CMDR 0x21 #define ISAC_EXIR 0x24 -#define ISAC_RBCH 0x2a #define ISAC_ADF2 0x39 #define ISAC_SPCR 0x30 #define ISAC_ADF1 0x38 #define ISAC_CIR0 0x31 #define ISAC_CIX0 0x31 +#define ISAC_CIR1 0x33 +#define ISAC_CIX1 0x33 #define ISAC_STCR 0x37 #define ISAC_MODE 0x22 #define ISAC_RSTA 0x27 #define ISAC_RBCL 0x25 +#define ISAC_RBCH 0x2A #define ISAC_TIMR 0x23 #define ISAC_SQXR 0x3b #define ISAC_MOSR 0x3a @@ -44,6 +50,8 @@ #define ISAC_MOX0 0x32 #define ISAC_MOR1 0x34 #define ISAC_MOX1 0x34 + +#define ISAC_RBCH_XAC 0x80 #define ISAC_CMD_TIM 0x0 #define ISAC_CMD_RS 0x1 diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.2.10/linux/drivers/isdn/hisax/isar.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isar.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,942 @@ +/* $Id: isar.c,v 1.3 1999/07/01 08:11:45 keil Exp $ + + * isar.c ISAR (Siemens PSB 7110) specific routines + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * + * $Log: isar.c,v $ + * Revision 1.3 1999/07/01 08:11:45 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.2 1998/11/15 23:54:53 keil + * changes from 2.0 + * + * Revision 1.1 1998/08/13 23:33:47 keil + * First version, only init + * + * + */ + +#define __NO_VERSION__ +#include "hisax.h" +#include "isar.h" +#include "isdnl1.h" +#include + +#define DBG_LOADFIRM 0 +#define DUMP_MBOXFRAME 2 + +#define MIN(a,b) ((aBC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) + printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n"); + return(timeout); +} + + +int +sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, + u_char *msg) +{ + long flags; + int i; + + if (!waitforHIA(cs, 4000)) + return(0); +#if DUMP_MBOXFRAME + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len); +#endif + save_flags(flags); + cli(); + cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg); + cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len); + cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0); + if (msg && len) { + cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]); + for (i=1; iBC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]); +#if DUMP_MBOXFRAME>1 + if (cs->debug & L1_DEB_HSCX_FIFO) { + char tmp[256], *t; + + i = len; + while (i>0) { + t = tmp; + t += sprintf(t, "sendmbox cnt %d", len); + QuickHex(t, &msg[len-i], (i>64) ? 64:i); + debugl1(cs, tmp); + i -= 64; + } + } +#endif + } + cs->BC_Write_Reg(cs, 1, ISAR_HIS, his); + restore_flags(flags); + waitforHIA(cs, 10000); + return(1); +} + +/* Call only with IRQ disabled !!! */ +inline void +rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) +{ + int i; + + cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0); + if (msg && ireg->clsb) { + msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX); + for (i=1; i < ireg->clsb; i++) + msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX); +#if DUMP_MBOXFRAME>1 + if (cs->debug & L1_DEB_HSCX_FIFO) { + char tmp[256], *t; + + i = ireg->clsb; + while (i>0) { + t = tmp; + t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb); + QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i); + debugl1(cs, tmp); + i -= 64; + } + } +#endif + } + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); +} + +/* Call only with IRQ disabled !!! */ +inline void +get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) +{ + ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); + ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H); + ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L); +#if DUMP_MBOXFRAME + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb, + ireg->clsb); +#endif +} + +int +waitrecmsg(struct IsdnCardState *cs, u_char *len, + u_char *msg, int maxdelay) +{ + int timeout = 0; + long flags; + struct isar_reg *ir = cs->bcs[0].hw.isar.reg; + + + while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && + (timeout++ < maxdelay)) + udelay(1); + if (timeout >= maxdelay) { + printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); + return(0); + } + save_flags(flags); + cli(); + get_irq_infos(cs, ir); + rcv_mbox(cs, ir, msg); + *len = ir->clsb; + restore_flags(flags); + return(1); +} + +int +ISARVersion(struct IsdnCardState *cs, char *s) +{ + int ver; + u_char msg[] = ISAR_MSG_HWVER; + u_char tmp[64]; + u_char len; + int debug; + + cs->cardmsg(cs, CARD_RESET, NULL); + /* disable ISAR IRQ */ + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); + debug = cs->debug; + cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); + if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) + return(-1); + if (!waitrecmsg(cs, &len, tmp, 100000)) + return(-2); + cs->debug = debug; + if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) { + if (len == 1) { + ver = tmp[0] & 0xf; + printk(KERN_INFO "%s ISAR version %d\n", s, ver); + return(ver); + } + return(-3); + } + return(-4); +} + +int +isar_load_firmware(struct IsdnCardState *cs, u_char *buf) +{ + int ret, size, cnt, debug; + u_char len, nom, noc; + u_short sadr, left, *sp; + u_char *p = buf; + u_char *msg, *tmpmsg, *mp, tmp[64]; + long flags; + struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; + + struct {u_short sadr; + u_short len; + u_short d_key; + } blk_head; + +#define BLK_HEAD_SIZE 6 + if (1 != (ret = ISARVersion(cs, "Testing"))) { + printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret); + return(1); + } + debug = cs->debug; +#if DBG_LOADFIRM<2 + cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); +#endif + printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf); + if ((ret = verify_area(VERIFY_READ, (void *) p, sizeof(int)))) { + printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret); + return ret; + } + if ((ret = copy_from_user(&size, p, sizeof(int)))) { + printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); + return ret; + } + p += sizeof(int); + printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); + if ((ret = verify_area(VERIFY_READ, (void *) p, size))) { + printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret); + return ret; + } + cnt = 0; + /* disable ISAR IRQ */ + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); + if (!(msg = kmalloc(256, GFP_KERNEL))) { + printk(KERN_ERR"isar_load_firmware no buffer\n"); + return (1); + } + if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) { + printk(KERN_ERR"isar_load_firmware no tmp buffer\n"); + kfree(msg); + return (1); + } + while (cnt < size) { + if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) { + printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); + goto reterror; + } + cnt += BLK_HEAD_SIZE; + p += BLK_HEAD_SIZE; + printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", + blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); + sadr = blk_head.sadr; + left = blk_head.len; + if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) { + printk(KERN_ERR"isar sendmsg dkey failed\n"); + ret = 1;goto reterror; + } + if (!waitrecmsg(cs, &len, tmp, 100000)) { + printk(KERN_ERR"isar waitrecmsg dkey failed\n"); + ret = 1;goto reterror; + } + if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) { + printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n", + ireg->iis, ireg->cmsb, len); + ret = 1;goto reterror; + } + while (left>0) { + noc = MIN(126, left); + nom = 2*noc; + mp = msg; + *mp++ = sadr / 256; + *mp++ = sadr % 256; + left -= noc; + *mp++ = noc; + if ((ret = copy_from_user(tmpmsg, p, nom))) { + printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); + goto reterror; + } + p += nom; + cnt += nom; + nom += 3; + sp = (u_short *)tmpmsg; +#if DBG_LOADFIRM + printk(KERN_DEBUG"isar: load %3d words at %04x\n", + noc, sadr); +#endif + sadr += noc; + while(noc) { + *mp++ = *sp / 256; + *mp++ = *sp % 256; + sp++; + noc--; + } + if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) { + printk(KERN_ERR"isar sendmsg prog failed\n"); + ret = 1;goto reterror; + } + if (!waitrecmsg(cs, &len, tmp, 100000)) { + printk(KERN_ERR"isar waitrecmsg prog failed\n"); + ret = 1;goto reterror; + } + if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) { + printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n", + ireg->iis, ireg->cmsb, len); + ret = 1;goto reterror; + } + } + printk(KERN_DEBUG"isar firmware block %5d words loaded\n", + blk_head.len); + } + msg[0] = 0xff; + msg[1] = 0xfe; + ireg->bstat = 0; + if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) { + printk(KERN_ERR"isar sendmsg start dsp failed\n"); + ret = 1;goto reterror; + } + if (!waitrecmsg(cs, &len, tmp, 100000)) { + printk(KERN_ERR"isar waitrecmsg start dsp failed\n"); + ret = 1;goto reterror; + } + if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) { + printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n", + ireg->iis, ireg->cmsb, len); + ret = 1;goto reterror; + } else + printk(KERN_DEBUG"isar start dsp success\n"); + /* NORMAL mode entered */ + /* Enable IRQs of ISAR */ + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); + save_flags(flags); + sti(); + cnt = 1000; /* max 1s */ + while ((!ireg->bstat) && cnt) { + udelay(1000); + cnt--; + } + if (!cnt) { + printk(KERN_ERR"isar no general status event received\n"); + ret = 1;goto reterrflg; + } else { + printk(KERN_DEBUG"isar general status event %x\n", + ireg->bstat); + } + ireg->iis = 0; + if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { + printk(KERN_ERR"isar sendmsg self tst failed\n"); + ret = 1;goto reterrflg; + } + cnt = 1000; /* max 10 ms */ + while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + if (!cnt) { + printk(KERN_ERR"isar no self tst response\n"); + ret = 1;goto reterrflg; + } else if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) + && (ireg->par[0] == 0)) { + printk(KERN_DEBUG"isar selftest OK\n"); + } else { + printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", + ireg->cmsb, ireg->clsb, ireg->par[0]); + ret = 1;goto reterror; + } + ireg->iis = 0; + if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { + printk(KERN_ERR"isar RQST SVN failed\n"); + ret = 1;goto reterror; + } + cnt = 10000; /* max 100 ms */ + while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { + udelay(10); + cnt--; + } + if (!cnt) { + printk(KERN_ERR"isar no SVN response\n"); + ret = 1;goto reterrflg; + } else { + if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1)) + printk(KERN_DEBUG"isar software version %#x\n", + ireg->par[0]); + else { + printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n", + ireg->cmsb, ireg->clsb, cnt); + ret = 1;goto reterrflg; + } + } + cs->debug = debug; + isar_setup(cs); + ret = 0; +reterrflg: + restore_flags(flags); +reterror: + cs->debug = debug; + if (ret) + /* disable ISAR IRQ */ + cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); + kfree(msg); + kfree(tmpmsg); + return(ret); +} + +void +isar_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + queue_task(&bcs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void +isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) +{ + u_char *ptr; + struct sk_buff *skb; + struct isar_reg *ireg = bcs->hw.isar.reg; + + if (!ireg->clsb) { + debugl1(cs, "isar zero len frame"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + return; + } + switch (bcs->mode) { + case L1_MODE_NULL: + debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x", + ireg->iis, ireg->cmsb, ireg->clsb); + printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n", + ireg->iis, ireg->cmsb, ireg->clsb); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + break; + case L1_MODE_TRANS: + if ((skb = dev_alloc_skb(ireg->clsb))) { + SET_SKB_FREE(skb); + rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb)); + skb_queue_tail(&bcs->rqueue, skb); + isar_sched_event(bcs, B_RCVBUFREADY); + } else { + printk(KERN_WARNING "HiSax: skb out of memory\n"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } + break; + case L1_MODE_HDLC: + if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar_rcv_frame: incoming packet too large"); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + bcs->hw.isar.rcvidx = 0; + } else if (ireg->cmsb & HDLC_ERROR) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "isar frame error %x len %d", + ireg->cmsb, ireg->clsb); + bcs->hw.isar.rcvidx = 0; + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } else { + if (ireg->cmsb & HDLC_FSD) + bcs->hw.isar.rcvidx = 0; + ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; + bcs->hw.isar.rcvidx += ireg->clsb; + rcv_mbox(cs, ireg, ptr); + if (ireg->cmsb & HDLC_FED) { + if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ + printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", + bcs->hw.isar.rcvidx); + } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) + printk(KERN_WARNING "ISAR: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2), + bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2); + skb_queue_tail(&bcs->rqueue, skb); + isar_sched_event(bcs, B_RCVBUFREADY); + } + } + } + break; + default: + printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + break; + } +} + +void +isar_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int count; + u_char msb; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "isar_fill_fifo"); + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + if (!(bcs->hw.isar.reg->bstat & + (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) + return; + if (bcs->tx_skb->len > bcs->hw.isar.mml) { + msb = 0; + count = bcs->hw.isar.mml; + } else { + count = bcs->tx_skb->len; + msb = HDLC_FED; + } + if (!bcs->hw.isar.txcnt) + msb |= HDLC_FST; + save_flags(flags); + cli(); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.isar.txcnt += count; + switch (bcs->mode) { + case L1_MODE_NULL: + printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); + break; + case L1_MODE_TRANS: + if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + 0, count, ptr)) { + if (cs->debug) + debugl1(cs, "isar bin data send dp%d failed", + bcs->hw.isar.dpath); + } + break; + case L1_MODE_HDLC: + if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, + msb, count, ptr)) { + if (cs->debug) + debugl1(cs, "isar hdlc data send dp%d failed", + bcs->hw.isar.dpath); + } + break; + default: + printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode); + break; + } + restore_flags(flags); +} + +inline +struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) +{ + if ((!dpath) || (dpath == 3)) + return(NULL); + if (cs->bcs[0].hw.isar.dpath == dpath) + return(&cs->bcs[0]); + if (cs->bcs[1].hw.isar.dpath == dpath) + return(&cs->bcs[1]); + return(NULL); +} + +inline void +send_frames(struct BCState *bcs) +{ + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + isar_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->hw.isar.txcnt = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.isar.txcnt = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + isar_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + isar_sched_event(bcs, B_XMTBUFREADY); + } +} + +inline void +check_send(struct IsdnCardState *cs, u_char rdm) +{ + struct BCState *bcs; + + if (rdm & BSTAT_RDM1) { + if ((bcs = sel_bcs_isar(cs, 1))) { + if (bcs->mode) { + send_frames(bcs); + } + } + } + if (rdm & BSTAT_RDM2) { + if ((bcs = sel_bcs_isar(cs, 2))) { + if (bcs->mode) { + send_frames(bcs); + } + } + } + +} + +static char debbuf[64]; + +void +isar_int_main(struct IsdnCardState *cs) +{ + long flags; + struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; + struct BCState *bcs; + + save_flags(flags); + cli(); + get_irq_infos(cs, ireg); + switch (ireg->iis & ISAR_IIS_MSCMSD) { + case ISAR_IIS_RDATA: + if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { + isar_rcv_frame(cs, bcs); + } else { + debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", + ireg->iis, ireg->cmsb, ireg->clsb); + printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n", + ireg->iis, ireg->cmsb, ireg->clsb); + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + } + break; + case ISAR_IIS_GSTEV: + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + ireg->bstat |= ireg->cmsb; + check_send(cs, ireg->cmsb); + break; + case ISAR_IIS_BSTEV: + cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "Buffer STEV dpath%d msb(%x)", + ireg->iis>>6, ireg->cmsb); + break; + case ISAR_IIS_DIAG: + case ISAR_IIS_PSTRSP: + case ISAR_IIS_PSTEV: + case ISAR_IIS_BSTRSP: + case ISAR_IIS_IOM2RSP: + rcv_mbox(cs, ireg, (u_char *)ireg->par); + if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO)) + == L1_DEB_HSCX) { + u_char *tp=debbuf; + + tp += sprintf(debbuf, "msg iis(%x) msb(%x)", + ireg->iis, ireg->cmsb); + QuickHex(tp, (u_char *)ireg->par, ireg->clsb); + debugl1(cs, debbuf); + } + break; + default: + rcv_mbox(cs, ireg, debbuf); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)", + ireg->iis, ireg->cmsb, ireg->clsb); + break; + } + restore_flags(flags); +} + +void +setup_pump(struct BCState *bcs) { + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + + switch (bcs->mode) { + case L1_MODE_NULL: + case L1_MODE_TRANS: + case L1_MODE_HDLC: + if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) { + if (cs->debug) + debugl1(cs, "isar pump bypass cfg dp%d failed", + bcs->hw.isar.dpath); + } + break; + } + if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) { + if (cs->debug) + debugl1(cs, "isar pump status req dp%d failed", + bcs->hw.isar.dpath); + } +} + +void +setup_sart(struct BCState *bcs) { + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + + switch (bcs->mode) { + case L1_MODE_NULL: + if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) { + if (cs->debug) + debugl1(cs, "isar sart disable dp%d failed", + bcs->hw.isar.dpath); + } + break; + case L1_MODE_TRANS: + if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) { + if (cs->debug) + debugl1(cs, "isar sart binary dp%d failed", + bcs->hw.isar.dpath); + } + break; + case L1_MODE_HDLC: + if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, "\0")) { + if (cs->debug) + debugl1(cs, "isar sart binary dp%d failed", + bcs->hw.isar.dpath); + } + break; + } + if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) { + if (cs->debug) + debugl1(cs, "isar buf stat req dp%d failed", + bcs->hw.isar.dpath); + } +} + +void +setup_iom2(struct BCState *bcs) { + struct IsdnCardState *cs = bcs->cs; + u_char dps = SET_DPS(bcs->hw.isar.dpath); + u_char cmsb = 0, msg[5] = {0x10,0,0,0,0}; + + switch (bcs->mode) { + case L1_MODE_NULL: + /* dummy slot */ + msg[1] = msg[3] = bcs->hw.isar.dpath + 2; + break; + case L1_MODE_TRANS: + case L1_MODE_HDLC: + cmsb = 0x80; + if (bcs->channel) + msg[1] = msg[3] = 1; + break; + } + if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) { + if (cs->debug) + debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath); + } + if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) { + if (cs->debug) + debugl1(cs, "isar IOM2 cfg req dp%d failed", + bcs->hw.isar.dpath); + } +} + +int +modeisar(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + + /* Here we are selecting the best datapath for requested mode */ + if(bcs->mode == L1_MODE_NULL) { /* New Setup */ + bcs->channel = bc; + switch (mode) { + case L1_MODE_NULL: /* init */ + break; + case L1_MODE_TRANS: + case L1_MODE_HDLC: + /* best is datapath 2 */ + if (!test_and_set_bit(ISAR_DP2_USE, + &bcs->hw.isar.reg->Flags)) + bcs->hw.isar.dpath = 2; + else if (!test_and_set_bit(ISAR_DP1_USE, + &bcs->hw.isar.reg->Flags)) + bcs->hw.isar.dpath = 1; + else { + printk(KERN_ERR"isar modeisar both pathes in use\n"); + return(1); + } + break; + } + } + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar dp%d mode %d->%d ichan %d", + bcs->hw.isar.dpath, bcs->mode, mode, bc); + bcs->mode = mode; + setup_pump(bcs); + setup_sart(bcs); + setup_iom2(bcs); + if (bcs->mode == L1_MODE_NULL) { + /* Clear resources */ + if (bcs->hw.isar.dpath == 1) + test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags); + else if (bcs->hw.isar.dpath == 2) + test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags); + bcs->hw.isar.dpath = 0; + } + return(0); +} + +void +isar_setup(struct IsdnCardState *cs) +{ + u_char msg; + int i; + + /* Dpath 1, 2 */ + msg = 61; + for (i=0; i<2; i++) { + /* Buffer Config */ + if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | + ISAR_HIS_P12CFG, 4, 1, &msg)) { + if (cs->debug) + debugl1(cs, "isar P%dCFG failed", i+1); + } + cs->bcs[i].hw.isar.mml = msg; + cs->bcs[i].mode = 0; + cs->bcs[i].hw.isar.dpath = i + 1; + modeisar(&cs->bcs[i], 0, 0); + } +} + +void +isar_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + if (st->l1.bcs->cs->debug & L1_DEB_HSCX) + debugl1(st->l1.bcs->cs, "DRQ set BC_FLG_BUSY"); + st->l1.bcs->hw.isar.txcnt = 0; + restore_flags(flags); + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n"); + break; + } + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + if (st->l1.bcs->cs->debug & L1_DEB_HSCX) + debugl1(st->l1.bcs->cs, "PUI set BC_FLG_BUSY"); + st->l1.bcs->tx_skb = skb; + st->l1.bcs->hw.isar.txcnt = 0; + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + modeisar(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + if (st->l1.bcs->cs->debug & L1_DEB_HSCX) + debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY"); + modeisar(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +void +close_isarstate(struct BCState *bcs) +{ + modeisar(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.isar.rcvbuf) { + kfree(bcs->hw.isar.rcvbuf); + bcs->hw.isar.rcvbuf = NULL; + } + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); + } + } +} + +int +open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for isar.rcvbuf\n"); + return (1); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "openisar clear BC_FLG_BUSY"); + bcs->event = 0; + bcs->hw.isar.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); +} + +int +setstack_isar(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (open_isarstate(st->l1.hardware, bcs)) + return (-1); + st->l1.bcs = bcs; + st->l2.l2l1 = isar_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +HISAX_INITFUNC(void +initisar(struct IsdnCardState *cs)) +{ + cs->bcs[0].BC_SetStack = setstack_isar; + cs->bcs[1].BC_SetStack = setstack_isar; + cs->bcs[0].BC_Close = close_isarstate; + cs->bcs[1].BC_Close = close_isarstate; +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h --- v2.2.10/linux/drivers/isdn/hisax/isar.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isar.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,95 @@ +/* $Id: isar.h,v 1.3 1999/07/01 08:11:46 keil Exp $ + * isar.h ISAR (Siemens PSB 7110) specific defines + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * + * $Log: isar.h,v $ + * Revision 1.3 1999/07/01 08:11:46 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.2 1998/11/15 23:54:54 keil + * changes from 2.0 + * + * Revision 1.1 1998/08/13 23:33:48 keil + * First version, only init + * + * + */ + +#define ISAR_IRQMSK 0x04 +#define ISAR_IRQSTA 0x04 +#define ISAR_IRQBIT 0x75 +#define ISAR_CTRL_H 0x61 +#define ISAR_CTRL_L 0x60 +#define ISAR_IIS 0x58 +#define ISAR_IIA 0x58 +#define ISAR_HIS 0x50 +#define ISAR_HIA 0x50 +#define ISAR_MBOX 0x4c +#define ISAR_WADR 0x4a +#define ISAR_RADR 0x48 + +#define ISAR_HIS_VNR 0x14 +#define ISAR_HIS_DKEY 0x02 +#define ISAR_HIS_FIRM 0x1e +#define ISAR_HIS_STDSP 0x08 +#define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_P0CFG 0x3c +#define ISAR_HIS_P12CFG 0x24 +#define ISAR_HIS_SARTCFG 0x25 +#define ISAR_HIS_PUMPCFG 0x26 +#define ISAR_HIS_IOM2CFG 0x27 +#define ISAR_HIS_IOM2REQ 0x07 +#define ISAR_HIS_IOM2CTRL 0x2b +#define ISAR_HIS_BSTREQ 0x0c +#define ISAR_HIS_PSTREQ 0x0e +#define ISAR_HIS_SDATA 0x20 +#define ISAR_HIS_DPS1 0x40 +#define ISAR_HIS_DPS2 0x80 +#define SET_DPS(x) ((x<<6) & 0xc0) + +#define ISAR_IIS_MSCMSD 0x3f +#define ISAR_IIS_VNR 0x15 +#define ISAR_IIS_DKEY 0x03 +#define ISAR_IIS_FIRM 0x1f +#define ISAR_IIS_STDSP 0x09 +#define ISAR_IIS_DIAG 0x25 +#define ISAR_IIS_GSTEV 0x0 +#define ISAR_IIS_BSTEV 0x28 +#define ISAR_IIS_BSTRSP 0x2c +#define ISAR_IIS_PSTRSP 0x2e +#define ISAR_IIS_PSTEV 0x2a +#define ISAR_IIS_IOM2RSP 0x27 + +#define ISAR_IIS_RDATA 0x20 +#define ISAR_CTRL_SWVER 0x10 +#define ISAR_CTRL_STST 0x40 + +#define ISAR_MSG_HWVER {0x20, 0, 1} + +#define ISAR_DP1_USE 1 +#define ISAR_DP2_USE 2 + +#define PMOD_BYPASS 7 + +#define SMODE_DISABLE 0 +#define SMODE_HDLC 3 +#define SMODE_BINARY 4 + +#define HDLC_FED 0x40 +#define HDLC_FSD 0x20 +#define HDLC_FST 0x20 +#define HDLC_ERROR 0x1c + +#define BSTAT_RDM0 0x1 +#define BSTAT_RDM1 0x2 +#define BSTAT_RDM2 0x4 +#define BSTAT_RDM3 0x8 + + +extern int ISARVersion(struct IsdnCardState *cs, char *s); +extern int isar_load_firmware(struct IsdnCardState *cs, u_char *buf); +extern void isar_int_main(struct IsdnCardState *cs); +extern void initisar(struct IsdnCardState *cs); +extern void isar_fill_fifo(struct BCState *bcs); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.2.10/linux/drivers/isdn/hisax/isdnl1.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/isdn/hisax/isdnl1.c Mon Aug 9 12:04:39 1999 @@ -1,9 +1,13 @@ -/* $Id: isdnl1.c,v 2.18 1998/02/12 23:07:42 keil Exp $ +/* $Id: isdnl1.c,v 2.34 1999/07/09 13:50:15 keil Exp $ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * Thanks to Jan den Ouden * Fritz Elfert @@ -11,6 +15,52 @@ * * * $Log: isdnl1.c,v $ + * Revision 2.34 1999/07/09 13:50:15 keil + * remove unused variable + * + * Revision 2.33 1999/07/09 13:34:33 keil + * remove debug code + * + * Revision 2.32 1999/07/01 08:11:47 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.31 1998/11/15 23:54:56 keil + * changes from 2.0 + * + * Revision 2.30 1998/09/30 22:27:00 keil + * Add init of l1.Flags + * + * Revision 2.29 1998/09/27 23:54:43 keil + * cosmetics + * + * Revision 2.28 1998/09/27 12:52:23 keil + * Fix against segfault, if the driver cannot allocate an IRQ channel + * + * Revision 2.27 1998/08/13 23:36:39 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.26 1998/07/15 15:01:31 calle + * Support for AVM passive PCMCIA cards: + * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0 + * + * Revision 2.25 1998/05/25 14:10:09 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.24 1998/05/25 12:58:04 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.22 1998/04/15 16:40:13 keil + * Add S0Box and Teles PCI support + * Fix cardnr overwrite bug + * + * Revision 2.21 1998/04/10 10:35:28 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.20 1998/03/09 23:19:27 keil + * Changes for PCMCIA + * * Revision 2.18 1998/02/12 23:07:42 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -79,102 +129,21 @@ * */ -const char *l1_revision = "$Revision: 2.18 $"; +const char *l1_revision = "$Revision: 2.34 $"; #define __NO_VERSION__ #include #include "hisax.h" #include "isdnl1.h" -#include -#if (LINUX_VERSION_CODE < 0x020150) /* 2.1.80 */ -#define kstat_irqs( PAR ) kstat.interrupts( (PAR) ) -#endif - +#define TIMER3_VALUE 7000 -#if CARD_TELES0 -extern int setup_teles0(struct IsdnCard *card); -#endif - -#if CARD_TELES3 -extern int setup_teles3(struct IsdnCard *card); -#endif - -#if CARD_AVM_A1 -extern int setup_avm_a1(struct IsdnCard *card); -#endif - -#if CARD_ELSA -extern int setup_elsa(struct IsdnCard *card); -#endif - -#if CARD_IX1MICROR2 -extern int setup_ix1micro(struct IsdnCard *card); -#endif - -#if CARD_DIEHLDIVA -extern int setup_diva(struct IsdnCard *card); -#endif - -#if CARD_ASUSCOM -extern int setup_asuscom(struct IsdnCard *card); -#endif - -#if CARD_TELEINT -extern int setup_TeleInt(struct IsdnCard *card); -#endif - -#if CARD_SEDLBAUER -extern int setup_sedlbauer(struct IsdnCard *card); -#endif - -#if CARD_SPORTSTER -extern int setup_sportster(struct IsdnCard *card); -#endif - -#if CARD_MIC -extern int setup_mic(struct IsdnCard *card); -#endif - -#if CARD_NETJET -extern int setup_netjet(struct IsdnCard *card); -#endif - -#if CARD_TELES3C -extern int setup_t163c(struct IsdnCard *card); -#endif - -#if CARD_AMD7930 || CARD_DBRI -extern int setup_foreign(struct IsdnCard *card); -#endif - -#if CARD_NICCY -extern int setup_niccy(struct IsdnCard *card); -#endif - -#define HISAX_STATUS_BUFSIZE 4096 -#define ISDN_CTRL_DEBUG 1 -#define INCLUDE_INLINE_FUNCS -#include -#include -const char *CardType[] = -{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP", - "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", - "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", - "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", - "AMD 7930", "NICCY", "DBRI" -}; - -extern struct IsdnCard cards[]; -extern int nrcards; -extern char *HiSax_id; -extern struct IsdnBuffers *tracebuf; - -#define TIMER3_VALUE 7 +static +struct Fsm l1fsm_b = +{NULL, 0, 0, NULL, NULL}; static -struct Fsm l1fsm = +struct Fsm l1fsm_d = {NULL, 0, 0, NULL, NULL}; enum { @@ -187,9 +156,9 @@ ST_L1_F8, }; -#define L1_STATE_COUNT (ST_L1_F8+1) +#define L1D_STATE_COUNT (ST_L1_F8+1) -static char *strL1State[] = +static char *strL1DState[] = { "ST_L1_F2", "ST_L1_F3", @@ -201,7 +170,25 @@ }; enum { + ST_L1_NULL, + ST_L1_WAIT_ACT, + ST_L1_WAIT_DEACT, + ST_L1_ACTIV, +}; + +#define L1B_STATE_COUNT (ST_L1_ACTIV+1) + +static char *strL1BState[] = +{ + "ST_L1_NULL", + "ST_L1_WAIT_ACT", + "ST_L1_WAIT_DEACT", + "ST_L1_ACTIV", +}; + +enum { EV_PH_ACTIVATE, + EV_PH_DEACTIVATE, EV_RESET_IND, EV_DEACT_CNF, EV_DEACT_IND, @@ -219,6 +206,7 @@ static char *strL1Event[] = { "EV_PH_ACTIVATE", + "EV_PH_DEACTIVATE", "EV_RESET_IND", "EV_DEACT_CNF", "EV_DEACT_IND", @@ -231,154 +219,30 @@ "EV_TIMER3", }; -/* - * Find card with given driverId - */ -static inline struct IsdnCardState -*hisax_findcard(int driverid) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].cs) - if (cards[i].cs->myid == driverid) - return (cards[i].cs); - return (NULL); -} - -int -HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) -{ - int count; - u_char *p; - struct IsdnCardState *csta = hisax_findcard(id); - - if (csta) { - for (p = buf, count = 0; count < len; p++, count++) { - if (user) - put_user(*csta->status_read++, p); - else - *p++ = *csta->status_read++; - if (csta->status_read > csta->status_end) - csta->status_read = csta->status_buf; - } - return count; - } else { - printk(KERN_ERR - "HiSax: if_readstatus called with invalid driverId!\n"); - return -ENODEV; - } -} - -#if ISDN_CTRL_DEBUG void -HiSax_putstatus(struct IsdnCardState *csta, char *buf) +debugl1(struct IsdnCardState *cs, char *fmt, ...) { - long flags; - int len, count, i; - u_char *p; - isdn_ctrl ic; - - save_flags(flags); - cli(); - count = 0; - len = strlen(buf); - - if (!csta) { - printk(KERN_WARNING "HiSax: No CardStatus for message %s", buf); - restore_flags(flags); - return; - } - for (p = buf, i = len; i > 0; i--, p++) { - *csta->status_write++ = *p; - if (csta->status_write > csta->status_end) - csta->status_write = csta->status_buf; - count++; - } - restore_flags(flags); - if (count) { - ic.command = ISDN_STAT_STAVAIL; - ic.driver = csta->myid; - ic.arg = count; - csta->iif.statcallb(&ic); - } -} -#else -#define KDEBUG_DEF -#include "../kdebug.h" - -static int DbgLineNr=0,DbgSequenzNr=1; - -void -HiSax_putstatus(struct IsdnCardState *csta, char *buf) -{ - char tmp[512]; + va_list args; + char tmp[8]; - if (DbgLineNr==23) - DbgLineNr=0; - sprintf(tmp, "%5d %s",DbgSequenzNr++,buf); - gput_str(tmp,0,DbgLineNr++); -} -#endif - -int -ll_run(struct IsdnCardState *csta) -{ - long flags; - isdn_ctrl ic; - - save_flags(flags); - cli(); - ic.driver = csta->myid; - ic.command = ISDN_STAT_RUN; - csta->iif.statcallb(&ic); - restore_flags(flags); - return 0; -} - -void -ll_stop(struct IsdnCardState *csta) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_STOP; - ic.driver = csta->myid; - csta->iif.statcallb(&ic); - CallcFreeChan(csta); -} - -static void -ll_unload(struct IsdnCardState *csta) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_UNLOAD; - ic.driver = csta->myid; - csta->iif.statcallb(&ic); - if (csta->status_buf) - kfree(csta->status_buf); - csta->status_read = NULL; - csta->status_write = NULL; - csta->status_end = NULL; - kfree(csta->dlogspace); -} - -void -debugl1(struct IsdnCardState *cs, char *msg) -{ - char tmp[1024], tm[32]; - - jiftime(tm, jiffies); - sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg); - HiSax_putstatus(cs, tmp); + va_start(args, fmt); + sprintf(tmp, "Card%d ", cs->cardnr + 1); + VHiSax_putstatus(cs, tmp, fmt, args); + va_end(args); } static void -l1m_debug(struct FsmInst *fi, char *s) +l1m_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; + struct IsdnCardState *cs = st->l1.hardware; + char tmp[8]; - debugl1(st->l1.hardware, s); + va_start(args, fmt); + sprintf(tmp, "Card%d ", cs->cardnr + 1); + VHiSax_putstatus(cs, tmp, fmt, args); + va_end(args); } void @@ -389,9 +253,9 @@ st = cs->stlist; while (st) { if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else - st->l1.l1man(st, PH_ACTIVATE_IND, NULL); + st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); st = st->next; } } @@ -404,8 +268,8 @@ st = cs->stlist; while (st) { if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PAUSE_CNF, NULL); - st->l1.l1man(st, PH_DEACTIVATE_IND, NULL); + st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); + st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); st = st->next; } test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); @@ -422,7 +286,7 @@ stptr = cs->stlist; while (stptr != NULL) if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { - stptr->l1.l1l2(stptr, PH_PULL_CNF, NULL); + stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); break; } else stptr = stptr->next; @@ -434,7 +298,6 @@ struct sk_buff *skb, *nskb; struct PStack *stptr = cs->stlist; int found, tei, sapi; - char tmp[64]; if (stptr) if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) @@ -445,19 +308,27 @@ Logl2Frame(cs, skb, "PH_DATA", 1); #endif stptr = cs->stlist; + if (skb->len<3) { + debugl1(cs, "D-channel frame too short(%d)",skb->len); + idev_kfree_skb(skb, FREE_READ); + return; + } + if ((skb->data[0] & 1) || !(skb->data[1] &1)) { + debugl1(cs, "D-channel frame wrong EA0/EA1"); + idev_kfree_skb(skb, FREE_READ); + return; + } sapi = skb->data[0] >> 2; tei = skb->data[1] >> 1; - + if (cs->debug & DEB_DLOG_HEX) + LogFrame(cs, skb->data, skb->len); + if (cs->debug & DEB_DLOG_VERBOSE) + dlogframe(cs, skb, 1); if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - if (cs->dlogflag) { - LogFrame(cs, skb->data, skb->len); - dlogframe(cs, skb->data + 3, skb->len - 3, - "Q.931 frame network->user broadcast"); - } + if (sapi == CTRL_SAPI) { /* sapi 0 */ while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1l2(stptr, PH_DATA_IND, nskb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); stptr = stptr->next; @@ -465,37 +336,24 @@ } else if (sapi == TEI_SAPI) { while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1tei(stptr, PH_DATA_IND, nskb); + stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); stptr = stptr->next; } } - dev_kfree_skb(skb); - } else if (sapi == CTRL_SAPI) { + idev_kfree_skb(skb, FREE_READ); + } else if (sapi == CTRL_SAPI) { /* sapi 0 */ found = 0; while (stptr != NULL) if (tei == stptr->l2.tei) { - stptr->l1.l1l2(stptr, PH_DATA_IND, skb); + stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); found = !0; break; } else stptr = stptr->next; - if (!found) { - /* BD 10.10.95 - * Print out D-Channel msg not processed - * by isdn4linux - */ - - if ((!(skb->data[0] >> 2)) && (!(skb->data[2] & 0x01))) { - sprintf(tmp, - "Q.931 frame network->user with tei %d (not for us)", - skb->data[1] >> 1); - LogFrame(cs, skb->data, skb->len); - dlogframe(cs, skb->data + 4, skb->len - 4, tmp); - } - dev_kfree_skb(skb); - } + if (!found) + idev_kfree_skb(skb, FREE_READ); } } } @@ -505,14 +363,18 @@ { struct PStack *st = bcs->st; - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) + if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { + debugl1(bcs->cs, "BC_BUSY Error"); return; + } if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) - st->l1.l1l2(st, PH_PULL_CNF, NULL); - if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) - st->ma.manl1(st, PH_DEACTIVATE_CNF, 0); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); + } + } } static void @@ -520,8 +382,12 @@ { struct sk_buff *skb; + if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) { + FsmDelTimer(&bcs->st->l1.timer, 4); + FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); + } while ((skb = skb_dequeue(&bcs->rqueue))) { - bcs->st->l1.l1l2(bcs->st, PH_DATA_IND, skb); + bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); } } @@ -581,443 +447,6 @@ bcs->Flag = 0; } -static void -closecard(int cardnr) -{ - struct IsdnCardState *csta = cards[cardnr].cs; - struct sk_buff *skb; - - if (csta->bcs->BC_Close != NULL) { - csta->bcs->BC_Close(csta->bcs + 1); - csta->bcs->BC_Close(csta->bcs); - } - - if (csta->rcvbuf) { - kfree(csta->rcvbuf); - csta->rcvbuf = NULL; - } - while ((skb = skb_dequeue(&csta->rq))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&csta->sq))) { - dev_kfree_skb(skb); - } - if (csta->tx_skb) { - dev_kfree_skb(csta->tx_skb); - csta->tx_skb = NULL; - } - if (csta->mon_rx) { - kfree(csta->mon_rx); - csta->mon_rx = NULL; - } - if (csta->mon_tx) { - kfree(csta->mon_tx); - csta->mon_tx = NULL; - } - csta->cardmsg(csta, CARD_RELEASE, NULL); - del_timer(&csta->dbusytimer); - ll_unload(csta); -} - -HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs)) -{ - int irq_cnt, cnt = 3; - long flags; - - save_flags(flags); - cli(); - irq_cnt = kstat_irqs(cs->irq); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, - irq_cnt); - if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) { - printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", - cs->irq); - return(1); - } - while (cnt) { - cs->cardmsg(cs, CARD_INIT, NULL); - sti(); - current->state = TASK_INTERRUPTIBLE; - /* Timeout 10ms */ - schedule_timeout((10 * HZ) / 1000); - restore_flags(flags); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], - cs->irq, kstat_irqs(cs->irq)); - if (kstat_irqs(cs->irq) == irq_cnt) { - printk(KERN_WARNING - "%s: IRQ(%d) getting no interrupts during init %d\n", - CardType[cs->typ], cs->irq, 4 - cnt); - if (cnt == 1) { - free_irq(cs->irq, cs); - return (2); - } else { - cs->cardmsg(cs, CARD_RESET, NULL); - cnt--; - } - } else { - cs->cardmsg(cs, CARD_TEST, NULL); - return(0); - } - } - restore_flags(flags); - return(3); -} - -HISAX_INITFUNC(static int -checkcard(int cardnr, char *id, int *busy_flag)) -{ - long flags; - int ret = 0; - struct IsdnCard *card = cards + cardnr; - struct IsdnCardState *cs; - - save_flags(flags); - cli(); - if (!(cs = (struct IsdnCardState *) - kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for IsdnCardState(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - card->cs = cs; - cs->cardnr = cardnr; - cs->debug = L1_DEB_WARN; - cs->HW_Flags = 0; - cs->busy_flag = busy_flag; -#if TEI_PER_CARD -#else - test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); -#endif - cs->protocol = card->protocol; - - if ((card->typ > 0) && (card->typ < 31)) { - if (!((1 << card->typ) & SUPORTED_CARDS)) { - printk(KERN_WARNING - "HiSax: Support for %s Card not selected\n", - CardType[card->typ]); - restore_flags(flags); - return (0); - } - } else { - printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", - card->typ); - restore_flags(flags); - return (0); - } - if (!(cs->dlogspace = kmalloc(4096, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for dlogspace(card %d)\n", - cardnr + 1); - restore_flags(flags); - return (0); - } - if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for status_buf(card %d)\n", - cardnr + 1); - kfree(cs->dlogspace); - restore_flags(flags); - return (0); - } - cs->stlist = NULL; - cs->dlogflag = 0; - cs->mon_tx = NULL; - cs->mon_rx = NULL; - cs->status_read = cs->status_buf; - cs->status_write = cs->status_buf; - cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; - cs->typ = card->typ; - strcpy(cs->iif.id, id); - cs->iif.channels = 2; - cs->iif.maxbufsize = MAX_DATA_SIZE; - cs->iif.hl_hdrlen = MAX_HEADER_LEN; - cs->iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | -#ifdef CONFIG_HISAX_1TR6 - ISDN_FEATURE_P_1TR6 | -#endif -#ifdef CONFIG_HISAX_EURO - ISDN_FEATURE_P_EURO | -#endif -#ifdef CONFIG_HISAX_NI1 - ISDN_FEATURE_P_NI1 | -#endif - 0; - - cs->iif.command = HiSax_command; - cs->iif.writecmd = NULL; - cs->iif.writebuf_skb = HiSax_writebuf_skb; - cs->iif.readstat = HiSax_readstatus; - register_isdn(&cs->iif); - cs->myid = cs->iif.channels; - printk(KERN_INFO - "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, - (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : - (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : - (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : - (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : - "NONE", cs->iif.id, cs->myid); - switch (card->typ) { -#if CARD_TELES0 - case ISDN_CTYPE_16_0: - case ISDN_CTYPE_8_0: - ret = setup_teles0(card); - break; -#endif -#if CARD_TELES3 - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_COMPAQ_ISA: - ret = setup_teles3(card); - break; -#endif -#if CARD_AVM_A1 - case ISDN_CTYPE_A1: - ret = setup_avm_a1(card); - break; -#endif -#if CARD_ELSA - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_ELSA_PCI: - ret = setup_elsa(card); - break; -#endif -#if CARD_IX1MICROR2 - case ISDN_CTYPE_IX1MICROR2: - ret = setup_ix1micro(card); - break; -#endif -#if CARD_DIEHLDIVA - case ISDN_CTYPE_DIEHLDIVA: - ret = setup_diva(card); - break; -#endif -#if CARD_ASUSCOM - case ISDN_CTYPE_ASUSCOM: - ret = setup_asuscom(card); - break; -#endif -#if CARD_TELEINT - case ISDN_CTYPE_TELEINT: - ret = setup_TeleInt(card); - break; -#endif -#if CARD_SEDLBAUER - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - ret = setup_sedlbauer(card); - break; -#endif -#if CARD_SPORTSTER - case ISDN_CTYPE_SPORTSTER: - ret = setup_sportster(card); - break; -#endif -#if CARD_MIC - case ISDN_CTYPE_MIC: - ret = setup_mic(card); - break; -#endif -#if CARD_NETJET - case ISDN_CTYPE_NETJET: - ret = setup_netjet(card); - break; -#endif -#if CARD_TELES3C - case ISDN_CTYPE_TELES3C: - ret = setup_t163c(card); - break; -#endif -#if CARD_NICCY - case ISDN_CTYPE_NICCY: - ret = setup_niccy(card); - break; -#endif -#if CARD_AMD7930 || CARD_DBRI - case ISDN_CTYPE_AMD7930: - case ISDN_CTYPE_DBRI: - ret = setup_foreign(card); - break; -#endif - default: - printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n", - card->typ); - ll_unload(cs); - restore_flags(flags); - return (0); - } - if (!ret) { - ll_unload(cs); - restore_flags(flags); - return (0); - } - if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for isac rcvbuf\n"); - return (1); - } - cs->rcvidx = 0; - cs->tx_skb = NULL; - cs->tx_cnt = 0; - cs->event = 0; - cs->tqueue.next = 0; - cs->tqueue.sync = 0; - cs->tqueue.data = cs; - - skb_queue_head_init(&cs->rq); - skb_queue_head_init(&cs->sq); - - init_bcstate(cs, 0); - init_bcstate(cs, 1); - ret = init_card(cs); - if (ret) { - closecard(cardnr); - restore_flags(flags); - return (0); - } - init_tei(cs, cs->protocol); - CallcNewChan(cs); - ll_run(cs); - cs->l1cmd(cs, PH_RESET_REQ, NULL); - restore_flags(flags); - return (1); -} - -HISAX_INITFUNC(void -HiSax_shiftcards(int idx)) -{ - int i; - - for (i = idx; i < 15; i++) - memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); -} - -HISAX_INITFUNC(int -HiSax_inithardware(int *busy_flag)) -{ - int foundcards = 0; - int i = 0; - int t = ','; - int flg = 0; - char *id; - char *next_id = HiSax_id; - char ids[20]; - - if (strchr(HiSax_id, ',')) - t = ','; - else if (strchr(HiSax_id, '%')) - t = '%'; - - while (i < nrcards) { - if (cards[i].typ < 1) - break; - id = next_id; - if ((next_id = strchr(id, t))) { - *next_id++ = 0; - strcpy(ids, id); - flg = i + 1; - } else { - next_id = id; - if (flg >= i) - strcpy(ids, id); - else - sprintf(ids, "%s%d", id, i); - } - if (checkcard(i, ids, busy_flag)) { - foundcards++; - i++; - } else { - printk(KERN_WARNING "HiSax: Card %s not installed !\n", - CardType[cards[i].typ]); - if (cards[i].cs) - kfree((void *) cards[i].cs); - cards[i].cs = NULL; - HiSax_shiftcards(i); - } - } - return foundcards; -} - -void -HiSax_closehardware(void) -{ - int i; - long flags; - - save_flags(flags); - cli(); - for (i = 0; i < nrcards; i++) - if (cards[i].cs) { - ll_stop(cards[i].cs); - release_tei(cards[i].cs); - closecard(i); - free_irq(cards[i].cs->irq, cards[i].cs); - kfree((void *) cards[i].cs); - cards[i].cs = NULL; - } - Isdnl1Free(); - TeiFree(); - Isdnl2Free(); - CallcFree(); - restore_flags(flags); -} - -void -HiSax_reportcard(int cardnr) -{ - struct IsdnCardState *cs = cards[cardnr].cs; - struct PStack *stptr; - struct l3_process *pc; - int j, i = 1; - - printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); - printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); - printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); - printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", - (ulong) & HiSax_reportcard); - printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); - printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist)); - stptr = cs->stlist; - while (stptr != NULL) { - printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr); - printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp); - printk(KERN_DEBUG "HiSax: tei %d sapi %d\n", - stptr->l2.tei, stptr->l2.sap); - printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); - pc = stptr->l3.proc; - while (pc) { - printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref, - (ulong) pc); - printk(KERN_DEBUG "HiSax: state %d st 0x%lX chan 0x%lX\n", - pc->state, (ulong) pc->st, (ulong) pc->chan); - pc = pc->next; - } - stptr = stptr->next; - i++; - } - for (j = 0; j < 2; j++) { - printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j, - (ulong) & cs->channel[j]); - stptr = cs->channel[j].b_st; - i = 1; - while (stptr != NULL) { - printk(KERN_DEBUG "HiSax: b_st%d 0x%lX\n", i, (ulong) stptr); - printk(KERN_DEBUG "HiSax: man 0x%lX\n", (ulong) stptr->ma.layer); - stptr = stptr->next; - i++; - } - } -} - #ifdef L2FRAME_DEBUG /* psa */ char * @@ -1052,7 +481,7 @@ } } -static char tmp[20]; +static char tmpdeb[32]; char * l2frames(u_char * ptr) @@ -1061,7 +490,7 @@ case 1: case 5: case 9: - sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); + sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); break; case 0x6f: case 0x0f: @@ -1070,36 +499,33 @@ case 0x63: case 0x87: case 0xaf: - sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); + sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); break; default: if (!(ptr[2] & 1)) { - sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); + sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); break; } else return "invalid command"; } - return tmp; + return tmpdeb; } void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) { - char tmp[132]; u_char *ptr; ptr = skb->data; if (ptr[0] & 1 || !(ptr[1] & 1)) - debugl1(cs, "Addres not LAPD"); - else { - sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)", + debugl1(cs, "Address not LAPD"); + else + debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)", (dir ? "<-" : "->"), buf, l2frames(ptr), ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1); - debugl1(cs, tmp); - } } #endif @@ -1113,11 +539,10 @@ l1_deact_cnf(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F3); if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - cs->l1cmd(cs, PH_ENABLE_REQ, NULL); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); } static void @@ -1126,24 +551,23 @@ struct PStack *st = fi->userdata; FsmChangeState(fi, ST_L1_F3); - if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) { +// if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) { FsmDelTimer(&st->l1.timer, 1); FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - } +// } } static void l1_power_up(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { FsmChangeState(fi, ST_L1_F4); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); FsmDelTimer(&st->l1.timer, 1); - FsmAddTimer(&st->l1.timer, TIMER3_VALUE * HZ, EV_TIMER3, NULL, 2); + FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); } else FsmChangeState(fi, ST_L1_F3); @@ -1165,20 +589,18 @@ l1_info2_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F6); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); } static void l1_info4_ind(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; FsmChangeState(fi, ST_L1_F7); - cs->l1cmd(cs, PH_INFO3_REQ, NULL); + st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) FsmDelTimer(&st->l1.timer, 4); if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { @@ -1193,50 +615,61 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - + test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - L1deactivated(cs); - if (st->l1.l1m.state != ST_L1_F6) - FsmChangeState(fi, ST_L1_F3); + if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) + L1deactivated(st->l1.hardware); + if (st->l1.l1m.state != ST_L1_F6) { + FsmChangeState(fi, ST_L1_F3); + st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); + } } static void l1_timer_act(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags); test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1activated(cs); + L1activated(st->l1.hardware); } static void l1_timer_deact(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1deactivated(cs); - cs->l1cmd(cs, PH_DEACT_ACK, NULL); + L1deactivated(st->l1.hardware); + st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL); } static void l1_activate(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - cs->l1cmd(cs, PH_RESET_REQ, NULL); + st->l1.l1hw(st, HW_RESET | REQUEST, NULL); } -static struct FsmNode L1FnList[] HISAX_INITDATA = +static void +l1_activate_no(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) { + test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags); + L1deactivated(st->l1.hardware); + } +} + +static struct FsmNode L1DFnList[] HISAX_INITDATA = { {ST_L1_F3, EV_PH_ACTIVATE, l1_activate}, + {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, + {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, {ST_L1_F3, EV_RESET_IND, l1_reset}, {ST_L1_F4, EV_RESET_IND, l1_reset}, {ST_L1_F5, EV_RESET_IND, l1_reset}, @@ -1280,86 +713,159 @@ {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, }; -#define L1_FN_COUNT (sizeof(L1FnList)/sizeof(struct FsmNode)) +#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode)) + +static void +l1b_activate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_WAIT_ACT); + FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); +} + +static void +l1b_deactivate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_WAIT_DEACT); + FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); +} + +static void +l1b_timer_act(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_ACTIV); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); +} + +static void +l1b_timer_deact(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L1_NULL); + st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); +} + +static struct FsmNode L1BFnList[] HISAX_INITDATA = +{ + {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, + {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, + {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate}, + {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, +}; + +#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode)) HISAX_INITFUNC(void Isdnl1New(void)) { - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strEvent = strL1Event; - l1fsm.strState = strL1State; - FsmNew(&l1fsm, L1FnList, L1_FN_COUNT); + l1fsm_d.state_count = L1D_STATE_COUNT; + l1fsm_d.event_count = L1_EVENT_COUNT; + l1fsm_d.strEvent = strL1Event; + l1fsm_d.strState = strL1DState; + FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT); + l1fsm_b.state_count = L1B_STATE_COUNT; + l1fsm_b.event_count = L1_EVENT_COUNT; + l1fsm_b.strEvent = strL1Event; + l1fsm_b.strState = strL1BState; + FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT); } void Isdnl1Free(void) { - FsmFree(&l1fsm); + FsmFree(&l1fsm_d); + FsmFree(&l1fsm_b); } static void -dch_manl1(struct PStack *st, int pr, - void *arg) +dch_l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - char tmp[32]; switch (pr) { - case PH_ACTIVATE_REQ: - if (cs->debug) { - sprintf(tmp, "PH_ACTIVATE_REQ %s", - strL1State[st->l1.l1m.state]); - debugl1(cs, tmp); - } + case (PH_DATA | REQUEST): + case (PH_PULL | REQUEST): + case (PH_PULL |INDICATION): + st->l1.l1hw(st, pr, arg); + break; + case (PH_ACTIVATE | REQUEST): + if (cs->debug) + debugl1(cs, "PH_ACTIVATE_REQ %s", + strL1DState[st->l1.l1m.state]); if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); + st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); else { test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); } break; - case PH_DEACTIVATE_REQ: - if (cs->debug) { - sprintf(tmp, "PH_DEACTIVATE_REQ %s", - strL1State[st->l1.l1m.state]); - debugl1(cs, tmp); - } - break; - case PH_TESTLOOP_REQ: - if (1 & (int) arg) + case (PH_TESTLOOP | REQUEST): + if (1 & (long) arg) debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (int) arg) + if (2 & (long) arg) debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (int) arg)) + if (!(3 & (long) arg)) debugl1(cs, "PH_TEST_LOOP DISABLED"); - cs->l1cmd(cs, PH_TESTLOOP_REQ, arg); - break; - case PH_RESET_IND: - FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); - break; - case PH_DEACT_CNF: - FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); - break; - case PH_DEACT_IND: - FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); - break; - case PH_POWERUP_CNF: - FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); - break; - case PH_RSYNC_IND: - FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); + st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); break; - case PH_INFO2_IND: - FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); + default: + if (cs->debug) + debugl1(cs, "dch_l2l1 msg %04X unhandled", pr); break; - case PH_I4_P8_IND: - case PH_I4_P10_IND: - FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); + } +} + +void +l1_msg(struct IsdnCardState *cs, int pr, void *arg) { + struct PStack *st; + + st = cs->stlist; + + while (st) { + switch(pr) { + case (HW_RESET | INDICATION): + FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); + break; + case (HW_DEACTIVATE | CONFIRM): + FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); + break; + case (HW_DEACTIVATE | INDICATION): + FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); + break; + case (HW_POWERUP | CONFIRM): + FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); + break; + case (HW_RSYNC | INDICATION): + FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); + break; + case (HW_INFO2 | INDICATION): + FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); + break; + case (HW_INFO4_P8 | INDICATION): + case (HW_INFO4_P10 | INDICATION): + FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); + break; + default: + if (cs->debug) + debugl1(cs, "l1msg %04X unhandled", pr); + break; + } + st = st->next; + } +} + +void +l1_msg_b(struct PStack *st, int pr, void *arg) { + switch(pr) { + case (PH_ACTIVATE | REQUEST): + FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL); break; - default: - if (cs->debug) { - sprintf(tmp, "dch_manl1 msg %04X unhandled", pr); - debugl1(cs, tmp); - } + case (PH_DEACTIVATE | REQUEST): + FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL); break; } } @@ -1369,7 +875,7 @@ { st->l1.hardware = cs; st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm; + st->l1.l1m.fsm = &l1fsm_d; st->l1.l1m.state = ST_L1_F3; st->l1.l1m.debug = cs->debug; st->l1.l1m.userdata = st; @@ -1379,7 +885,22 @@ setstack_tei(st); setstack_manager(st); st->l1.stlistp = &(cs->stlist); - st->ma.manl1 = dch_manl1; + st->l2.l2l1 = dch_l2l1; st->l1.Flags = 0; cs->setstack_d(st, cs); +} + +void +setstack_l1_B(struct PStack *st) +{ + struct IsdnCardState *cs = st->l1.hardware; + + st->l1.l1m.fsm = &l1fsm_b; + st->l1.l1m.state = ST_L1_NULL; + st->l1.l1m.debug = cs->debug; + st->l1.l1m.userdata = st; + st->l1.l1m.userint = 0; + st->l1.l1m.printdebug = l1m_debug; + st->l1.Flags = 0; + FsmInitTimer(&st->l1.l1m, &st->l1.timer); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.2.10/linux/drivers/isdn/hisax/isdnl1.h Wed Apr 1 16:20:58 1998 +++ linux/drivers/isdn/hisax/isdnl1.h Mon Aug 9 12:04:39 1999 @@ -1,6 +1,16 @@ -/* $Id: isdnl1.h,v 2.5 1998/02/02 13:36:58 keil Exp $ +/* $Id: isdnl1.h,v 2.8 1998/11/15 23:54:59 keil Exp $ * $Log: isdnl1.h,v $ + * Revision 2.8 1998/11/15 23:54:59 keil + * changes from 2.0 + * + * Revision 2.7 1998/09/30 22:21:55 keil + * cosmetics + * + * Revision 2.6 1998/05/25 12:58:06 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.5 1998/02/02 13:36:58 keil * more debug * @@ -22,21 +32,6 @@ * */ - -#define L2FRAME_DEBUG - -/* DEBUG Level */ - -#define L1_DEB_WARN 0x01 -#define L1_DEB_INTSTAT 0x02 -#define L1_DEB_ISAC 0x04 -#define L1_DEB_ISAC_FIFO 0x08 -#define L1_DEB_HSCX 0x10 -#define L1_DEB_HSCX_FIFO 0x20 -#define L1_DEB_LAPD 0x40 -#define L1_DEB_IPAC 0x80 -#define L1_DEB_RECEIVE_FRAME 0x100 - #define D_RCVBUFREADY 0 #define D_XMTBUFREADY 1 #define D_L1STATECHANGE 2 @@ -49,11 +44,12 @@ #define B_RCVBUFREADY 0 #define B_XMTBUFREADY 1 -extern void debugl1(struct IsdnCardState *sp, char *msg); +extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); extern void DChannel_proc_xmt(struct IsdnCardState *cs); extern void DChannel_proc_rcv(struct IsdnCardState *cs); - +extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg); +extern void l1_msg_b(struct PStack *st, int pr, void *arg); #ifdef L2FRAME_DEBUG -extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir); +extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); #endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.2.10/linux/drivers/isdn/hisax/isdnl2.c Thu May 14 18:43:55 1998 +++ linux/drivers/isdn/hisax/isdnl2.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,45 @@ -/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $ +/* $Id: isdnl2.c,v 2.17 1999/07/01 08:11:50 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 2.17 1999/07/01 08:11:50 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.16 1998/11/15 23:55:01 keil + * changes from 2.0 + * + * Revision 2.15 1998/08/13 23:36:42 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.14 1998/06/19 15:19:18 keil + * fix LAPB tx_cnt for none I-frames + * + * Revision 2.13 1998/06/18 23:17:20 keil + * LAPB bugfix + * + * Revision 2.12 1998/05/25 14:10:12 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.11 1998/05/25 12:58:08 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.9 1998/04/10 10:35:30 paul + * fixed (silly?) warnings from egcs on Alpha. + * + * Revision 2.8 1998/03/07 22:57:04 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.7 1998/02/12 23:07:47 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -25,7 +58,7 @@ * Old stuff is still in the separate branch. * * Revision 2.2 1997/07/31 11:49:05 keil - * Eroor handling for no TEI assign + * Error handling for no TEI assign * * Revision 2.1 1997/07/27 21:34:38 keil * cosmetics @@ -41,9 +74,9 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.7 $"; +const char *l2_revision = "$Revision: 2.17 $"; -static void l2m_debug(struct FsmInst *fi, char *s); +static void l2m_debug(struct FsmInst *fi, char *fmt, ...); static struct Fsm l2fsm = @@ -76,7 +109,7 @@ enum { EV_L2_UI, - EV_L2_SABMX, + EV_L2_SABME, EV_L2_DISC, EV_L2_DM, EV_L2_UA, @@ -86,23 +119,25 @@ EV_L2_DL_DATA, EV_L2_ACK_PULL, EV_L2_DL_UNIT_DATA, - EV_L2_DL_ESTABLISH, - EV_L2_DL_RELEASE, + EV_L2_DL_ESTABLISH_REQ, + EV_L2_DL_RELEASE_REQ, EV_L2_MDL_ASSIGN, EV_L2_MDL_REMOVE, EV_L2_MDL_ERROR, - EV_L2_MDL_NOTEIPROC, EV_L1_DEACTIVATE, EV_L2_T200, EV_L2_T203, + EV_L2_SET_OWN_BUSY, + EV_L2_CLEAR_OWN_BUSY, + EV_L2_FRAME_ERROR, }; -#define L2_EVENT_COUNT (EV_L2_T203+1) +#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR+1) static char *strL2Event[] = { "EV_L2_UI", - "EV_L2_SABMX", + "EV_L2_SABME", "EV_L2_DISC", "EV_L2_DM", "EV_L2_UA", @@ -112,15 +147,17 @@ "EV_L2_DL_DATA", "EV_L2_ACK_PULL", "EV_L2_DL_UNIT_DATA", - "EV_L2_DL_ESTABLISH", - "EV_L2_DL_RELEASE", + "EV_L2_DL_ESTABLISH_REQ", + "EV_L2_DL_RELEASE_REQ", "EV_L2_MDL_ASSIGN", "EV_L2_MDL_REMOVE", "EV_L2_MDL_ERROR", - "EV_L2_MDL_NOTEIPROC", "EV_L1_DEACTIVATE", "EV_L2_T200", "EV_L2_T203", + "EV_L2_SET_OWN_BUSY", + "EV_L2_CLEAR_OWN_BUSY", + "EV_L2_FRAME_ERROR", }; static int l2addrsize(struct Layer2 *l2); @@ -134,51 +171,46 @@ l2->windowar[i] = NULL; } -static void -ReleaseWin(struct Layer2 *l2) +static int +freewin1(struct Layer2 *l2) { int i, cnt = 0; for (i = 0; i < MAX_WINDOW; i++) { if (l2->windowar[i]) { cnt++; - dev_kfree_skb(l2->windowar[i]); + idev_kfree_skb(l2->windowar[i], FREE_WRITE); l2->windowar[i] = NULL; } } - if (cnt) - printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); + return cnt; } -inline int -cansend(struct PStack *st) +inline void +freewin(struct PStack *st) { - int p1; - - p1 = st->l2.vs - st->l2.va; - if (p1 < 0) - p1 += (test_bit(FLG_MOD128, &st->l2.flag) ? 128 : 8); - return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); + freewin1(&st->l2); } static void -discard_i_queue(struct PStack *st) +ReleaseWin(struct Layer2 *l2) { - struct sk_buff *skb; + int cnt; - while ((skb = skb_dequeue(&st->l2.i_queue))) { - dev_kfree_skb(skb); - } + if((cnt = freewin1(l2))) + printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); } -static void -discard_ui_queue(struct PStack *st) +inline unsigned int +cansend(struct PStack *st) { - struct sk_buff *skb; + unsigned int p1; - while ((skb = skb_dequeue(&st->l2.ui_queue))) { - dev_kfree_skb(skb); - } + if(test_bit(FLG_MOD128, &st->l2.flag)) + p1 = (st->l2.vs - st->l2.va) % 128; + else + p1 = (st->l2.vs - st->l2.va) % 8; + return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); } inline void @@ -224,103 +256,209 @@ } } -static void -enqueue_ui(struct PStack *st, - struct sk_buff *skb) -{ - st->l2.l2l1(st, PH_DATA_REQ, skb); -} - -static void +inline static void enqueue_super(struct PStack *st, struct sk_buff *skb) { - st->l2.l2l1(st, PH_DATA_REQ, skb); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l1.bcs->tx_cnt += skb->len; + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } +#define enqueue_ui(a, b) enqueue_super(a, b) + inline int -IsUI(u_char * data, int ext) +IsUI(u_char * data) { return ((data[0] & 0xef) == UI); } inline int -IsUA(u_char * data, int ext) +IsUA(u_char * data) { return ((data[0] & 0xef) == UA); } inline int -IsDM(u_char * data, int ext) +IsDM(u_char * data) { return ((data[0] & 0xef) == DM); } inline int -IsDISC(u_char * data, int ext) +IsDISC(u_char * data) { return ((data[0] & 0xef) == DISC); } inline int -IsRR(u_char * data, int ext) +IsRR(u_char * data, struct PStack *st) { - if (ext) + if (test_bit(FLG_MOD128, &st->l2.flag)) return (data[0] == RR); else return ((data[0] & 0xf) == 1); } inline int -IsSABMX(u_char * data, int ext) +IsSFrame(u_char * data, struct PStack *st) +{ + register u_char d = *data; + + if (!test_bit(FLG_MOD128, &st->l2.flag)) + d &= 0xf; + return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c)); +} + +inline int +IsSABME(u_char * data, struct PStack *st) { u_char d = data[0] & ~0x10; - return (ext ? d == SABME : d == SABM); + return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM); } inline int -IsREJ(u_char * data, int ext) +IsREJ(u_char * data, struct PStack *st) { - return (ext ? data[0] == REJ : (data[0] & 0xf) == REJ); + return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ); } inline int -IsFRMR(u_char * data, int ext) +IsFRMR(u_char * data) { return ((data[0] & 0xef) == FRMR); } inline int -IsRNR(u_char * data, int ext) +IsRNR(u_char * data, struct PStack *st) { - return (ext ? data[0] == RNR : (data[0] & 0xf) == RNR); + return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR); } -static int -legalnr(struct PStack *st, int nr) +int +iframe_error(struct PStack *st, struct sk_buff *skb) { - struct Layer2 *l2 = &st->l2; - int lnr, lvs; + int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0); + int rsp = *skb->data & 0x2; + + if (test_bit(FLG_ORIG, &st->l2.flag)) + rsp = !rsp; + + if (rsp) + return 'L'; + + + if (skb->len <= i) + return 'N'; + + if ((skb->len - i) > st->l2.maxlen) + return 'O'; + + + return 0; +} + +int +super_error(struct PStack *st, struct sk_buff *skb) +{ + if (skb->len != l2addrsize(&st->l2) + + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1)) + return 'N'; + + return 0; +} + +int +unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp) +{ + int rsp = (*skb->data & 0x2) >> 1; + if (test_bit(FLG_ORIG, &st->l2.flag)) + rsp = !rsp; + + if (rsp != wantrsp) + return 'L'; + + if (skb->len != l2addrsize(&st->l2) + 1) + return 'N'; + + return 0; +} + +int +UI_error(struct PStack *st, struct sk_buff *skb) +{ + int rsp = *skb->data & 0x2; + if (test_bit(FLG_ORIG, &st->l2.flag)) + rsp = !rsp; + + if (rsp) + return 'L'; + + if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1) + return 'O'; - lvs = (l2->vs >= l2->va) ? l2->vs : - (l2->vs + (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8)); - lnr = (nr >= l2->va) ? nr : (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); - return (lnr <= lvs); + return 0; +} + +int +FRMR_error(struct PStack *st, struct sk_buff *skb) +{ + int headers = l2addrsize(&st->l2) + 1; + u_char *datap = skb->data + headers; + int rsp = *skb->data & 0x2; + + if (test_bit(FLG_ORIG, &st->l2.flag)) + rsp = !rsp; + + if (!rsp) + return 'L'; + + if (test_bit(FLG_MOD128, &st->l2.flag)) { + if (skb->len < headers + 5) + return 'N'; + else + l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x", + datap[0], datap[1], datap[2], + datap[3], datap[4]); + } else { + if (skb->len < headers + 3) + return 'N'; + else + l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x", + datap[0], datap[1], datap[2]); + } + + return 0; +} + +static unsigned int +legalnr(struct PStack *st, unsigned int nr) +{ + struct Layer2 *l2 = &st->l2; + + if(test_bit(FLG_MOD128, &l2->flag)) + return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); + else + return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); } static void -setva(struct PStack *st, int nr) +setva(struct PStack *st, unsigned int nr) { struct Layer2 *l2 = &st->l2; int len; while (l2->va != nr) { - l2->va = (l2->va + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); + (l2->va)++; + if(test_bit(FLG_MOD128, &l2->flag)) + l2->va %= 128; + else + l2->va %= 8; len = l2->windowar[l2->sow]->len; if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type) len = -1; - dev_kfree_skb(l2->windowar[l2->sow]); + idev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE); l2->windowar[l2->sow] = NULL; l2->sow = (l2->sow + 1) % l2->window; if (st->lli.l2writewakeup && (len >=0)) @@ -341,6 +479,7 @@ printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n"); return; } + SET_SKB_FREE(skb); memcpy(skb_put(skb, i), tmp, i); enqueue_super(st, skb); } @@ -354,7 +493,7 @@ inline void FreeSkb(struct sk_buff *skb) { - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } @@ -368,6 +507,48 @@ return (PF); } +inline void +start_t200(struct PStack *st, int i) +{ + FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); + test_and_set_bit(FLG_T200_RUN, &st->l2.flag); +} + +inline void +restart_t200(struct PStack *st, int i) +{ + FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); + test_and_set_bit(FLG_T200_RUN, &st->l2.flag); +} + +inline void +stop_t200(struct PStack *st, int i) +{ + if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) + FsmDelTimer(&st->l2.t200, i); +} + +inline void +st5_dl_release_l2l3(struct PStack *st) +{ + int pr; + + if(test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) + pr = DL_RELEASE | CONFIRM; + else + pr = DL_RELEASE | INDICATION; + + st->l2.l2l3(st, pr, NULL); +} + +inline void +lapb_dl_release_l2l3(struct PStack *st, int f) +{ + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st->l2.l2l3(st, DL_RELEASE | f, NULL); +} + static void establishlink(struct FsmInst *fi) { @@ -379,49 +560,91 @@ cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10; send_uframe(st, cmd, CMD); FsmDelTimer(&st->l2.t203, 1); - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 1); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); + restart_t200(st, 1); + test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); + freewin(st); FsmChangeState(fi, ST_L2_5); } static void -l2_mdl_error(struct FsmInst *fi, int event, void *arg) +l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) { struct sk_buff *skb = arg; struct PStack *st = fi->userdata; - switch (event) { - case EV_L2_UA: - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'C'); - else - st->ma.layer(st, MDL_ERROR_IND, (void *) 'D'); - break; - case EV_L2_DM: - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'B'); - else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'E'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } - break; + if (get_PollFlagFree(st, skb)) + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C'); + else + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D'); +} + +static void +l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) +{ + struct sk_buff *skb = arg; + struct PStack *st = fi->userdata; + + if (get_PollFlagFree(st, skb)) + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); + else { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); + establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } } static void -l2_dl_establish(struct FsmInst *fi, int event, void *arg) +l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) { + struct sk_buff *skb = arg; struct PStack *st = fi->userdata; - int state = fi->state; + if (get_PollFlagFree(st, skb)) + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); + else { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); + } + establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); +} + +static void +l2_go_st3(struct FsmInst *fi, int event, void *arg) +{ FsmChangeState(fi, ST_L2_3); - if (state == ST_L2_1) - st->l2.l2tei(st, MDL_ASSIGN_IND, NULL); } static void -l2_send_ui(struct PStack *st) +l2_mdl_assign(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L2_3); + st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); +} + +static void +l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + skb_queue_tail(&st->l2.ui_queue, skb); + FsmChangeState(fi, ST_L2_2); + st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); +} + +static void +l2_queue_ui(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + skb_queue_tail(&st->l2.ui_queue, skb); +} + +static void +tx_ui(struct PStack *st) { struct sk_buff *skb; u_char header[MAX_HEADER_LEN]; @@ -436,18 +659,13 @@ } static void -l2_put_ui(struct FsmInst *fi, int event, void *arg) +l2_send_ui(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; skb_queue_tail(&st->l2.ui_queue, skb); - if (fi->state == ST_L2_1) { - FsmChangeState(fi, ST_L2_2); - st->l2.l2tei(st, MDL_ASSIGN_IND, NULL); - } - if (fi->state > ST_L2_3) - l2_send_ui(st); + tx_ui(st); } static void @@ -457,11 +675,12 @@ struct sk_buff *skb = arg; skb_pull(skb, l2headersize(&st->l2, 1)); - if (skb->len > st->l2.maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); - FreeSkb(skb); - } else - st->l2.l2l3(st, DL_UNIT_DATA, skb); + st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb); +/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * in states 1-3 for broadcast + */ + + } static void @@ -469,245 +688,243 @@ { struct PStack *st = fi->userdata; - if (fi->state != ST_L2_4) - discard_i_queue(st); - if (fi->state != ST_L2_5) - establishlink(fi); + establishlink(fi); test_and_set_bit(FLG_L3_INIT, &st->l2.flag); } static void -l2_dl_release(struct FsmInst *fi, int event, void *arg) +l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - if (fi->state == ST_L2_4) { - st->l2.l2man(st, DL_RELEASE, NULL); - return; - } else if (fi->state == ST_L2_5) { - test_and_set_bit(FLG_PEND_REL, &st->l2.flag); - return; - } - discard_i_queue(st); + discard_queue(&st->l2.i_queue); + test_and_set_bit(FLG_L3_INIT, &st->l2.flag); + test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); +} + +static void +l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.i_queue); + establishlink(fi); + test_and_set_bit(FLG_L3_INIT, &st->l2.flag); +} + +static void +l2_release(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); +} + +static void +l2_pend_rel(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + test_and_set_bit(FLG_PEND_REL, &st->l2.flag); +} + +static void +l2_disconnect(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.i_queue); + freewin(st); FsmChangeState(fi, ST_L2_6); st->l2.rc = 0; send_uframe(st, DISC | 0x10, CMD); FsmDelTimer(&st->l2.t203, 1); - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 2); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); + restart_t200(st, 2); } static void -l2_got_SABMX(struct FsmInst *fi, int event, void *arg) +l2_start_multi(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - int est = 1, state, rsp; - u_char PollFlag; + + send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); + + clear_exception(&st->l2); + st->l2.vs = 0; + st->l2.va = 0; + st->l2.vr = 0; + st->l2.sow = 0; + FsmChangeState(fi, ST_L2_7); + FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); + + st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); +} + +static void +l2_send_UA(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); +} + +static void +l2_send_DM(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + send_uframe(st, DM | get_PollFlagFree(st, skb), RSP); +} + +static void +l2_restart_multi(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + int est = 0, state; state = fi->state; - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); - return; - } - if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); - return; - } - PollFlag = get_PollFlagFree(st, skb); - if (ST_L2_6 == state) { - send_uframe(st, DM | PollFlag, RSP); - return; - } else - send_uframe(st, UA | PollFlag, RSP); - if (ST_L2_5 == state) - return; - if (ST_L2_4 != state) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'F'); - if (st->l2.vs != st->l2.va) { - discard_i_queue(st); - est = 1; - } else - est = 0; + + send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); + + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F'); + + if (st->l2.vs != st->l2.va) { + discard_queue(&st->l2.i_queue); + est = 1; } + clear_exception(&st->l2); st->l2.vs = 0; st->l2.va = 0; st->l2.vr = 0; st->l2.sow = 0; FsmChangeState(fi, ST_L2_7); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 2); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); + stop_t200(st, 3); + FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); if (est) - st->l2.l2man(st, DL_ESTABLISH, NULL); + st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); - if (ST_L2_8 == state) + if ((ST_L2_7==state) || (ST_L2_8 == state)) if (skb_queue_len(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void -l2_got_disconn(struct FsmInst *fi, int event, void *arg) +l2_stop_multi(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - u_char PollFlag, cmd = UA; - int state, rel = 1, cst = 1, rsp; - state = fi->state; - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; + FsmChangeState(fi, ST_L2_4); + FsmDelTimer(&st->l2.t203, 3); + stop_t200(st, 4); - if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); + send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); + + discard_queue(&st->l2.i_queue); + freewin(st); + lapb_dl_release_l2l3(st, INDICATION); +} + +static void +l2_connected(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + int pr=-1; + + if (!get_PollFlag(st, skb)) { + l2_mdl_error_ua(fi, event, arg); return; - } - if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); + } + FreeSkb(skb); + + if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) + l2_disconnect(fi, event, arg); + + if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { + pr = DL_ESTABLISH | CONFIRM; + } else if (st->l2.vs != st->l2.va) { + discard_queue(&st->l2.i_queue); + pr = DL_ESTABLISH | INDICATION; + } + + stop_t200(st, 5); + + st->l2.vr = 0; + st->l2.vs = 0; + st->l2.va = 0; + st->l2.sow = 0; + FsmChangeState(fi, ST_L2_7); + FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); + + if (pr != -1) + st->l2.l2l3(st, pr, NULL); + + if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); +} + +static void +l2_released(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + if (!get_PollFlag(st, skb)) { + l2_mdl_error_ua(fi, event, arg); return; } - PollFlag = get_PollFlagFree(st, skb); - if ((state == ST_L2_4) || (state == ST_L2_5)) { - rel = 0; - cst = 0; - cmd = DM; - } else if (state == ST_L2_6) { - rel = 0; - cst = 0; - } - if (cst) { - FsmChangeState(fi, ST_L2_4); - FsmDelTimer(&st->l2.t203, 3); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 2); - } - send_uframe(st, cmd | PollFlag, RSP); - if (rel) - st->l2.l2man(st, DL_RELEASE, NULL); -} + FreeSkb(skb); + stop_t200(st, 6); + lapb_dl_release_l2l3(st, CONFIRM); + FsmChangeState(fi, ST_L2_4); +} static void -l2_got_ua(struct FsmInst *fi, int event, void *arg) +l2_reestablish(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - u_char PollFlag, est = 1; - int state,rsp; - state = fi->state; - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (!rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); - return; - } - if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) - establishlink(fi); - return; - } - PollFlag = get_PollFlag(st, skb); - if (!PollFlag) { - l2_mdl_error(fi, event, arg); - return; + if (!get_PollFlagFree(st, skb)) { + establishlink(fi); + test_and_set_bit(FLG_L3_INIT, &st->l2.flag); } - FreeSkb(skb); +} - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 2); - if (fi->state == ST_L2_5) { - if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) { - discard_i_queue(st); - st->l2.rc = 0; - send_uframe(st, DISC | 0x10, CMD); - FsmChangeState(fi, ST_L2_6); - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 4); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); - } else { - if (!test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { - if (st->l2.vs != st->l2.va) - discard_i_queue(st); - else - est = 0; - } - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); - if (est) - st->l2.l2man(st, DL_ESTABLISH, NULL); - } - } else { /* ST_L2_6 */ - st->l2.l2man(st, DL_RELEASE, NULL); +static void +l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + if (get_PollFlagFree(st, skb)) { + stop_t200(st, 7); + if (!test_bit(FLG_L3_INIT, &st->l2.flag)) + discard_queue(&st->l2.i_queue); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st5_dl_release_l2l3(st); FsmChangeState(fi, ST_L2_4); } } static void -l2_got_dm(struct FsmInst *fi, int event, void *arg) +l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - u_char PollFlag; - int state,rsp; - state = fi->state; - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (!rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); - if ((state == ST_L2_7) || (state == ST_L2_8)) - establishlink(fi); - return; - } - if (skb->len != (l2addrsize(&st->l2) + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8)) - establishlink(fi); - return; - } - PollFlag = get_PollFlagFree(st, skb); - if (!PollFlag) { - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } else { - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 2); - if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag)) - discard_i_queue(st); - st->l2.l2man(st, DL_RELEASE, NULL); + if (get_PollFlagFree(st, skb)) { + stop_t200(st, 8); + lapb_dl_release_l2l3(st, CONFIRM); FsmChangeState(fi, ST_L2_4); } } @@ -731,6 +948,7 @@ printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n"); return; } + SET_SKB_FREE(skb); memcpy(skb_put(skb, i), tmp, i); enqueue_super(st, skb); } @@ -753,8 +971,7 @@ else enquiry_cr(st, RR, CMD, 1); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 12); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); + start_t200(st, 9); } @@ -763,42 +980,44 @@ { struct PStack *st = fi->userdata; - st->ma.layer(st, MDL_ERROR_IND, (void *) 'J'); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J'); establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } static void -invoke_retransmission(struct PStack *st, int nr) +invoke_retransmission(struct PStack *st, unsigned int nr) { struct Layer2 *l2 = &st->l2; - int p1; - long flags; + unsigned int p1; if (l2->vs != nr) { - save_flags(flags); - cli(); while (l2->vs != nr) { - l2->vs = l2->vs - 1; - if (l2->vs < 0) - l2->vs += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); - p1 = l2->vs - l2->va; - if (p1 < 0) - p1 += (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); + (l2->vs)--; + if(test_bit(FLG_MOD128, &l2->flag)) { + l2->vs %= 128; + p1 = (l2->vs - l2->va) % 128; + } else { + l2->vs %= 8; + p1 = (l2->vs - l2->va) % 8; + } p1 = (p1 + l2->sow) % l2->window; + if (test_bit(FLG_LAPB, &l2->flag)) + st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0); skb_queue_head(&l2->i_queue, l2->windowar[p1]); l2->windowar[p1] = NULL; } - restore_flags(flags); - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } } static void -l2_got_st7_super(struct FsmInst *fi, int event, void *arg) +l2_st7_got_super(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - int PollFlag, nr, rsp, typ = RR; + int PollFlag, rsp, typ = RR; + unsigned int nr; struct Layer2 *l2 = &st->l2; rsp = *skb->data & 0x2; @@ -806,70 +1025,77 @@ rsp = !rsp; skb_pull(skb, l2addrsize(l2)); - if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) { + if (IsRNR(skb->data, st)) { test_and_set_bit(FLG_PEER_BUSY, &l2->flag); typ = RNR; } else test_and_clear_bit(FLG_PEER_BUSY, &l2->flag); - if (IsREJ(skb->data, test_bit(FLG_MOD128, &l2->flag))) + if (IsREJ(skb->data, st)) typ = REJ; + if (test_bit(FLG_MOD128, &l2->flag)) { - if (skb->len == 2) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } + PollFlag = (skb->data[1] & 0x1) == 0x1; + nr = skb->data[1] >> 1; } else { - if (skb->len == 1) { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } + PollFlag = (skb->data[0] & 0x10); + nr = (skb->data[0] >> 5) & 0x7; } FreeSkb(skb); - if ((!rsp) && PollFlag) - enquiry_response(st); - if (rsp && PollFlag) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'A'); + if (PollFlag) { + if (rsp) + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A'); + else + enquiry_response(st); + } if (legalnr(st, nr)) { if (typ == REJ) { setva(st, nr); invoke_retransmission(st, nr); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 9); + stop_t200(st, 10); if (FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 6)) l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ"); } else if ((nr == l2->vs) && (typ == RR)) { setva(st, nr); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 9); + stop_t200(st, 11); FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 7); } else if ((l2->va != nr) || (typ == RNR)) { setva(st, nr); - FsmDelTimer(&st->l2.t203, 9); - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 6); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); + if(typ != RR) FsmDelTimer(&st->l2.t203, 9); + restart_t200(st, 12); } if (skb_queue_len(&st->l2.i_queue) && (typ == RR)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); +} - if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) { - fi->userint &= ~LC_FLUSH_WAIT; - st->l2.l2man(st, DL_FLUSH, NULL); - } +static void +l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); + if (!test_bit(FLG_L3_INIT, &st->l2.flag)) + skb_queue_tail(&st->l2.i_queue, skb); + else + FreeSkb(skb); +} + +static void +l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); + skb_queue_tail(&st->l2.i_queue, skb); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void @@ -880,10 +1106,7 @@ if (test_bit(FLG_LAPB, &st->l2.flag)) st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag))) - skb_queue_tail(&st->l2.i_queue, skb); - if (fi->state == ST_L2_7) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + skb_queue_tail(&st->l2.i_queue, skb); } static void @@ -891,73 +1114,37 @@ { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - struct IsdnCardState *sp = st->l1.hardware; struct Layer2 *l2 = &(st->l2); - int PollFlag, ns, nr, i, hs, rsp; - char str[64]; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; + int PollFlag, ns, i; + unsigned int nr; - if (rsp) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); - FreeSkb(skb); - establishlink(fi); - return; - } i = l2addrsize(l2); if (test_bit(FLG_MOD128, &l2->flag)) { - if (skb->len <= (i + 1)) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } else if ((skb->len - i - 1) > l2->maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); - FreeSkb(skb); - establishlink(fi); - return; - } PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); ns = skb->data[i] >> 1; nr = (skb->data[i + 1] >> 1) & 0x7f; } else { - if (skb->len <= i) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } else if ((skb->len - i) > l2->maxlen) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'O'); - FreeSkb(skb); - establishlink(fi); - return; - } PollFlag = (skb->data[i] & 0x10); ns = (skb->data[i] >> 1) & 0x7; nr = (skb->data[i] >> 5) & 0x7; } if (test_bit(FLG_OWN_BUSY, &l2->flag)) { FreeSkb(skb); - enquiry_response(st); + if(PollFlag) enquiry_response(st); } else if (l2->vr == ns) { - l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8); + (l2->vr)++; + if(test_bit(FLG_MOD128, &l2->flag)) + l2->vr %= 128; + else + l2->vr %= 8; test_and_clear_bit(FLG_REJEXC, &l2->flag); - if (test_bit(FLG_LAPD, &l2->flag)) - if (sp->dlogflag) { - hs = l2headersize(l2, 0); - LogFrame(st->l1.hardware, skb->data, skb->len); - sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei); - dlogframe(st->l1.hardware, skb->data + hs, - skb->len - hs, str); - } + if (PollFlag) enquiry_response(st); else test_and_set_bit(FLG_ACK_PEND, &l2->flag); skb_pull(skb, l2headersize(l2, 0)); - st->l2.l2l3(st, DL_DATA, skb); + st->l2.l2l3(st, DL_DATA | INDICATION, skb); } else { /* n(s)!=v(r) */ FreeSkb(skb); @@ -971,26 +1158,22 @@ } if (legalnr(st, nr)) { - setva(st, nr); if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) { if (nr == st->l2.vs) { - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 10); + stop_t200(st, 13); FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 7); - } else if (nr != st->l2.va) { - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, - NULL, 8); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); - } + } else if (nr != st->l2.va) + restart_t200(st, 14); } + setva(st, nr); } else { nrerrorrecovery(fi); return; } if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) enquiry_cr(st, RR, RSP, 0); } @@ -1000,7 +1183,7 @@ { struct PStack *st = fi->userdata; - st->l2.tei = (int) arg; + st->l2.tei = (long) arg; if (fi->state == ST_L2_3) { establishlink(fi); @@ -1008,13 +1191,7 @@ } else FsmChangeState(fi, ST_L2_4); if (skb_queue_len(&st->l2.ui_queue)) - l2_send_ui(st); -} - -static void -l2_no_tei(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L2_4); + tx_ui(st); } static void @@ -1028,9 +1205,11 @@ } else if (st->l2.rc == st->l2.N200) { FsmChangeState(fi, ST_L2_4); test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - discard_i_queue(st); - st->ma.layer(st, MDL_ERROR_IND, (void *) 'G'); - st->l2.l2man(st, DL_RELEASE, NULL); + discard_queue(&st->l2.i_queue); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + st5_dl_release_l2l3(st); } else { st->l2.rc++; FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); @@ -1049,8 +1228,9 @@ FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); } else if (st->l2.rc == st->l2.N200) { FsmChangeState(fi, ST_L2_4); - st->ma.layer(st, MDL_ERROR_IND, (void *) 'H'); - st->l2.l2man(st, DL_RELEASE, NULL); + test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H'); + lapb_dl_release_l2l3(st, CONFIRM); } else { st->l2.rc++; FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, @@ -1060,7 +1240,7 @@ } static void -l2_st78_tout_200(struct FsmInst *fi, int event, void *arg) +l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; @@ -1070,12 +1250,28 @@ return; } test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - if (fi->state == ST_L2_7) { - st->l2.rc = 0; - FsmChangeState(fi, ST_L2_8); + st->l2.rc = 0; + FsmChangeState(fi, ST_L2_8); + + transmit_enquiry(st); + st->l2.rc++; +} + +static void +l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if (test_bit(FLG_LAPD, &st->l2.flag) && + test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { + FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); + return; } + test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); if (st->l2.rc == st->l2.N200) { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I'); establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } else { transmit_enquiry(st); st->l2.rc++; @@ -1104,7 +1300,9 @@ struct sk_buff *skb, *oskb; struct Layer2 *l2 = &st->l2; u_char header[MAX_HEADER_LEN]; - int p1, i; + int i; + int unsigned p1; + long flags; if (!cansend(st)) return; @@ -1113,14 +1311,17 @@ if (!skb) return; - p1 = l2->vs - l2->va; - if (p1 < 0) - p1 += test_bit(FLG_MOD128, &l2->flag) ? 128 : 8; + save_flags(flags); + cli(); + if(test_bit(FLG_MOD128, &l2->flag)) + p1 = (l2->vs - l2->va) % 128; + else + p1 = (l2->vs - l2->va) % 8; p1 = (p1 + l2->sow) % l2->window; if (l2->windowar[p1]) { printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", p1); - dev_kfree_skb(l2->windowar[p1]); + idev_kfree_skb(l2->windowar[p1], FREE_WRITE); } l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC); @@ -1134,6 +1335,8 @@ header[i++] = (l2->vr << 5) | (l2->vs << 1); l2->vs = (l2->vs + 1) % 8; } + restore_flags(flags); + p1 = skb->data - skb->head; if (p1 >= i) memcpy(skb_push(skb, i), header, i); @@ -1142,89 +1345,74 @@ "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); oskb = skb; skb = alloc_skb(oskb->len + i, GFP_ATOMIC); + SET_SKB_FREE(skb); memcpy(skb_put(skb, i), header, i); memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len); FreeSkb(oskb); } - st->l2.l2l1(st, PH_PULL_IND, skb); + st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { FsmDelTimer(&st->l2.t203, 13); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); } if (skb_queue_len(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } static void -l2_got_st8_super(struct FsmInst *fi, int event, void *arg) +l2_st8_got_super(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - int PollFlag, nr, rsp, rnr = 0; + int PollFlag, rsp, rnr = 0; + unsigned int nr; struct Layer2 *l2 = &st->l2; rsp = *skb->data & 0x2; if (test_bit(FLG_ORIG, &l2->flag)) rsp = !rsp; + skb_pull(skb, l2addrsize(l2)); - if (IsRNR(skb->data, test_bit(FLG_MOD128, &l2->flag))) { + if (IsRNR(skb->data, st)) { test_and_set_bit(FLG_PEER_BUSY, &l2->flag); rnr = 1; } else test_and_clear_bit(FLG_PEER_BUSY, &l2->flag); + if (test_bit(FLG_MOD128, &l2->flag)) { - if (skb->len == 2) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } + PollFlag = (skb->data[1] & 0x1) == 0x1; + nr = skb->data[1] >> 1; } else { - if (skb->len == 1) { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - FreeSkb(skb); - establishlink(fi); - return; - } + PollFlag = (skb->data[0] & 0x10); + nr = (skb->data[0] >> 5) & 0x7; } FreeSkb(skb); if (rsp && PollFlag) { if (legalnr(st, nr)) { - setva(st, nr); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 7); - FsmDelTimer(&l2->t203, 8); if (rnr) { - FsmRestartTimer(&l2->t200, l2->T200, - EV_L2_T200, NULL, 14); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); - } else + restart_t200(st, 15); + } else { + stop_t200(st, 16); FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 5); + setva(st, nr); + } invoke_retransmission(st, nr); FsmChangeState(fi, ST_L2_7); if (skb_queue_len(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL_REQ, NULL); - else if (fi->userint & LC_FLUSH_WAIT) { - fi->userint &= ~LC_FLUSH_WAIT; - st->l2.l2man(st, DL_FLUSH, NULL); - } - } + st->l2.l2l1(st, PH_PULL | REQUEST, NULL); + } else + nrerrorrecovery(fi); } else { if (!rsp && PollFlag) enquiry_response(st); if (legalnr(st, nr)) { setva(st, nr); - } + } else + nrerrorrecovery(fi); } } @@ -1233,30 +1421,12 @@ { struct PStack *st = fi->userdata; struct sk_buff *skb = arg; - char tmp[64]; skb_pull(skb, l2addrsize(&st->l2) + 1); - if (test_bit(FLG_MOD128, &st->l2.flag)) { - if (skb->len < 5) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - else { - sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x", - skb->data[0], skb->data[1], skb->data[2], - skb->data[3], skb->data[4]); - l2m_debug(&st->l2.l2m, tmp); - } - } else { - if (skb->len < 3) - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); - else { - sprintf(tmp, "FRMR information %2x %2x %2x", - skb->data[0], skb->data[1], skb->data[2]); - l2m_debug(&st->l2.l2m, tmp); - } - } + if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ - (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'K'); + (IsUA(skb->data) && (fi->state == ST_L2_7))) { + st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K'); establishlink(fi); test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } @@ -1264,103 +1434,206 @@ } static void +l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.ui_queue); + st->l2.tei = -1; + FsmChangeState(fi, ST_L2_1); +} + +static void +l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.ui_queue); + st->l2.tei = -1; + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); + FsmChangeState(fi, ST_L2_1); +} + +static void +l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); + freewin(st); + st->l2.tei = -1; + stop_t200(st, 17); + st5_dl_release_l2l3(st); + FsmChangeState(fi, ST_L2_1); +} + +static void +l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.ui_queue); + st->l2.tei = -1; + stop_t200(st, 18); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); + FsmChangeState(fi, ST_L2_1); +} + +static void l2_tei_remove(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_i_queue(st); - discard_ui_queue(st); + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); + freewin(st); st->l2.tei = -1; - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 18); + stop_t200(st, 17); FsmDelTimer(&st->l2.t203, 19); - if (fi->state != ST_L2_4) - st->l2.l2man(st, DL_RELEASE, NULL); + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); FsmChangeState(fi, ST_L2_1); } static void -l2_persistant_da(struct FsmInst *fi, int event, void *arg) +l2_discard_i(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - discard_i_queue(st); - discard_ui_queue(st); - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, 18); + discard_queue(&st->l2.i_queue); +} + +static void +l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); + freewin(st); + stop_t200(st, 19); + st5_dl_release_l2l3(st); + FsmChangeState(fi, ST_L2_4); +} + +static void +l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.ui_queue); + stop_t200(st, 20); + st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); + FsmChangeState(fi, ST_L2_4); +} + +static void +l2_persistant_da(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); + freewin(st); + stop_t200(st, 19); FsmDelTimer(&st->l2.t203, 19); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); - clear_exception(&st->l2); - switch (fi->state) { - case ST_L2_3: - st->l2.l2man(st, DL_RELEASE, NULL); - case ST_L2_2: - FsmChangeState(fi, ST_L2_1); - break; - case ST_L2_5: - case ST_L2_6: - case ST_L2_7: - case ST_L2_8: - st->l2.l2man(st, DL_RELEASE, NULL); - FsmChangeState(fi, ST_L2_4); - break; + st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); + FsmChangeState(fi, ST_L2_4); +} + +static void +l2_set_own_busy(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if(!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) { + enquiry_cr(st, RNR, RSP, 0); + test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); + } +} + +static void +l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + if(!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) { + enquiry_cr(st, RR, RSP, 0); + test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); } } +static void +l2_frame_error(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->ma.layer(st, MDL_ERROR | INDICATION, arg); +} + +static void +l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + st->ma.layer(st, MDL_ERROR | INDICATION, arg); + establishlink(fi); + test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); +} + static struct FsmNode L2FnList[] HISAX_INITDATA = { - {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei}, - {ST_L2_1, EV_L2_DL_ESTABLISH, l2_dl_establish}, - {ST_L2_2, EV_L2_DL_ESTABLISH, l2_dl_establish}, - {ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish}, - {ST_L2_5, EV_L2_DL_ESTABLISH, l2_establish}, - {ST_L2_7, EV_L2_DL_ESTABLISH, l2_establish}, - {ST_L2_8, EV_L2_DL_ESTABLISH, l2_establish}, - {ST_L2_4, EV_L2_DL_RELEASE, l2_dl_release}, - {ST_L2_5, EV_L2_DL_RELEASE, l2_dl_release}, - {ST_L2_7, EV_L2_DL_RELEASE, l2_dl_release}, - {ST_L2_8, EV_L2_DL_RELEASE, l2_dl_release}, - {ST_L2_5, EV_L2_DL_DATA, l2_feed_iqueue}, - {ST_L2_7, EV_L2_DL_DATA, l2_feed_iqueue}, + {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, + {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, + {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, + {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, + {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, + {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, + {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, + {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, + {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, + {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, + {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, + {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, - {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_put_ui}, - {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_put_ui}, + {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_queue_ui_assign}, + {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui}, + {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui}, + {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui}, + {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_ui}, {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ERROR, l2_tei_remove}, - {ST_L2_3, EV_L2_MDL_ERROR, l2_tei_remove}, - {ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove}, + {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, + {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, + {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, + {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, + {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_4, EV_L2_SABMX, l2_got_SABMX}, - {ST_L2_5, EV_L2_SABMX, l2_got_SABMX}, - {ST_L2_6, EV_L2_SABMX, l2_got_SABMX}, - {ST_L2_7, EV_L2_SABMX, l2_got_SABMX}, - {ST_L2_8, EV_L2_SABMX, l2_got_SABMX}, - {ST_L2_4, EV_L2_DISC, l2_got_disconn}, - {ST_L2_5, EV_L2_DISC, l2_got_disconn}, - {ST_L2_6, EV_L2_DISC, l2_got_disconn}, - {ST_L2_7, EV_L2_DISC, l2_got_disconn}, - {ST_L2_8, EV_L2_DISC, l2_got_disconn}, - {ST_L2_4, EV_L2_UA, l2_mdl_error}, - {ST_L2_5, EV_L2_UA, l2_got_ua}, - {ST_L2_6, EV_L2_UA, l2_got_ua}, - {ST_L2_7, EV_L2_UA, l2_mdl_error}, - {ST_L2_8, EV_L2_UA, l2_mdl_error}, - {ST_L2_4, EV_L2_DM, l2_got_dm}, - {ST_L2_5, EV_L2_DM, l2_got_dm}, - {ST_L2_6, EV_L2_DM, l2_got_dm}, - {ST_L2_7, EV_L2_DM, l2_mdl_error}, - {ST_L2_8, EV_L2_DM, l2_mdl_error}, + {ST_L2_4, EV_L2_SABME, l2_start_multi}, + {ST_L2_5, EV_L2_SABME, l2_send_UA}, + {ST_L2_6, EV_L2_SABME, l2_send_DM}, + {ST_L2_7, EV_L2_SABME, l2_restart_multi}, + {ST_L2_8, EV_L2_SABME, l2_restart_multi}, + {ST_L2_4, EV_L2_DISC, l2_send_DM}, + {ST_L2_5, EV_L2_DISC, l2_send_DM}, + {ST_L2_6, EV_L2_DISC, l2_send_UA}, + {ST_L2_7, EV_L2_DISC, l2_stop_multi}, + {ST_L2_8, EV_L2_DISC, l2_stop_multi}, + {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, + {ST_L2_5, EV_L2_UA, l2_connected}, + {ST_L2_6, EV_L2_UA, l2_released}, + {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, + {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, + {ST_L2_4, EV_L2_DM, l2_reestablish}, + {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, + {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, + {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, + {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, {ST_L2_1, EV_L2_UI, l2_got_ui}, {ST_L2_2, EV_L2_UI, l2_got_ui}, {ST_L2_3, EV_L2_UI, l2_got_ui}, @@ -1371,21 +1644,30 @@ {ST_L2_8, EV_L2_UI, l2_got_ui}, {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_7, EV_L2_SUPER, l2_got_st7_super}, - {ST_L2_8, EV_L2_SUPER, l2_got_st8_super}, + {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, + {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, {ST_L2_7, EV_L2_I, l2_got_iframe}, {ST_L2_8, EV_L2_I, l2_got_iframe}, {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st78_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st78_tout_200}, + {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, + {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, - {ST_L2_2, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_3, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_persistant_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_persistant_da}, + {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, + {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, + {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, + {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, + {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, + {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, + {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, + {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, + {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, + {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, + {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, + {ST_L2_4, EV_L1_DEACTIVATE, l2_discard_i}, + {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da}, + {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da}, {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da}, {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da}, }; @@ -1398,52 +1680,79 @@ struct sk_buff *skb = arg; u_char *datap; int ret = 1, len; + int c = 0; switch (pr) { - case (PH_DATA_IND): + case (PH_DATA | INDICATION): datap = skb->data; len = l2addrsize(&st->l2); if (skb->len > len) datap += len; else { - st->ma.layer(st, MDL_ERROR_IND, (void *) 'N'); + FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N'); FreeSkb(skb); return; } - if (!(*datap & 1)) /* I-Frame */ - ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); - else if ((*datap & 3) == 1) /* S-Frame */ - ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb); - else if (IsUI(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); - else if (IsSABMX(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb); - else if (IsUA(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb); - else if (IsDISC(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb); - else if (IsDM(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb); - else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag))) - ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); - else { - ret = 0; - st->ma.layer(st, MDL_ERROR_IND, (void *) 'L'); + if (!(*datap & 1)) { /* I-Frame */ + if(!(c = iframe_error(st, skb))) + ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); + } else if (IsSFrame(datap, st)) { /* S-Frame */ + if(!(c = super_error(st, skb))) + ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb); + } else if (IsUI(datap)) { + if(!(c = UI_error(st, skb))) + ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); + } else if (IsSABME(datap, st)) { + if(!(c = unnum_error(st, skb, CMD))) + ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb); + } else if (IsUA(datap)) { + if(!(c = unnum_error(st, skb, RSP))) + ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb); + } else if (IsDISC(datap)) { + if(!(c = unnum_error(st, skb, CMD))) + ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb); + } else if (IsDM(datap)) { + if(!(c = unnum_error(st, skb, RSP))) + ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb); + } else if (IsFRMR(datap)) { + if(!(c = FRMR_error(st,skb))) + ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); + } else { + FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L'); FreeSkb(skb); + ret = 0; } - if (ret) { + if(c) { FreeSkb(skb); + FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) c); + ret = 0; } + if (ret) + FreeSkb(skb); break; - case (PH_PULL_CNF): + case (PH_PULL | CONFIRM): FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); break; - case (PH_PAUSE_IND): + case (PH_PAUSE | INDICATION): test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag); break; - case (PH_PAUSE_CNF): + case (PH_PAUSE | CONFIRM): test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag); break; + case (PH_ACTIVATE | CONFIRM): + case (PH_ACTIVATE | INDICATION): + test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag); + if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) + FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); + break; + case (PH_DEACTIVATE | INDICATION): + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag); + FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); + break; + default: + l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr); + break; } } @@ -1451,45 +1760,43 @@ isdnl2_l3l2(struct PStack *st, int pr, void *arg) { switch (pr) { - case (DL_DATA): + case (DL_DATA | REQUEST): if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); + idev_kfree_skb((struct sk_buff *) arg, FREE_READ); } break; - case (DL_UNIT_DATA): + case (DL_UNIT_DATA | REQUEST): if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); + idev_kfree_skb((struct sk_buff *) arg, FREE_READ); } break; - } -} - -static void -isdnl2_manl2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg); - break; - case (DL_RELEASE): - FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg); - break; - case (MDL_NOTEIPROC): - FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL); - break; - case (DL_FLUSH): - (&st->l2.l2m)->userint |= LC_FLUSH_WAIT; + case (DL_ESTABLISH | REQUEST): + if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) { + if (test_bit(FLG_LAPD, &st->l2.flag) || + test_bit(FLG_ORIG, &st->l2.flag)) { + FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); + } + } else { + if (test_bit(FLG_LAPD, &st->l2.flag) || + test_bit(FLG_ORIG, &st->l2.flag)) { + test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag); + } + st->l2.l2l1(st, PH_ACTIVATE, NULL); + } break; - case (PH_DEACTIVATE_IND): - FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); + case (DL_RELEASE | REQUEST): + if (test_bit(FLG_LAPB, &st->l2.flag)) { + st->l2.l2l1(st, PH_DEACTIVATE, NULL); + } + FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg); break; - case (MDL_ASSIGN_REQ): + case (MDL_ASSIGN | REQUEST): FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); break; - case (MDL_REMOVE_REQ): + case (MDL_REMOVE | REQUEST): FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg); break; - case (MDL_ERROR_REQ): + case (MDL_ERROR | RESPONSE): FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg); break; } @@ -1498,22 +1805,22 @@ void releasestack_isdnl2(struct PStack *st) { - FsmDelTimer(&st->l2.t200, 15); + FsmDelTimer(&st->l2.t200, 21); FsmDelTimer(&st->l2.t203, 16); - discard_i_queue(st); - discard_ui_queue(st); + discard_queue(&st->l2.i_queue); + discard_queue(&st->l2.ui_queue); ReleaseWin(&st->l2); } static void -l2m_debug(struct FsmInst *fi, char *s) +l2m_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; - char tm[32], str[256]; - jiftime(tm, jiffies); - sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s); - HiSax_putstatus(st->l1.hardware, str); + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args); + va_end(args); } void @@ -1521,7 +1828,6 @@ { st->l1.l1l2 = isdnl2_l1l2; st->l3.l3l2 = isdnl2_l3l2; - st->ma.manl2 = isdnl2_manl2; skb_queue_head_init(&st->l2.i_queue); skb_queue_head_init(&st->l2.ui_queue); @@ -1529,6 +1835,9 @@ st->l2.debug = 0; st->l2.l2m.fsm = &l2fsm; + if (test_bit(FLG_LAPB, &st->l2.flag)) + st->l2.l2m.state = ST_L2_4; + else st->l2.l2m.state = ST_L2_1; st->l2.l2m.debug = 0; st->l2.l2m.userdata = st; @@ -1540,9 +1849,27 @@ FsmInitTimer(&st->l2.l2m, &st->l2.t203); } +static void +transl2_l3l2(struct PStack *st, int pr, void *arg) +{ + switch (pr) { + case (DL_DATA | REQUEST): + case (DL_UNIT_DATA | REQUEST): + st->l2.l2l1(st, PH_DATA | REQUEST, arg); + break; + case (DL_ESTABLISH | REQUEST): + st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); + break; + case (DL_RELEASE | REQUEST): + st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); + break; + } +} + void setstack_transl2(struct PStack *st) { + st->l3.l3l2 = transl2_l3l2; } void diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.2.10/linux/drivers/isdn/hisax/isdnl3.c Wed Apr 1 16:20:59 1998 +++ linux/drivers/isdn/hisax/isdnl3.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,30 @@ -/* $Id: isdnl3.c,v 2.5 1998/02/12 23:07:52 keil Exp $ +/* $Id: isdnl3.c,v 2.9 1999/07/01 08:11:53 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: isdnl3.c,v $ + * Revision 2.9 1999/07/01 08:11:53 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.8 1998/11/15 23:55:04 keil + * changes from 2.0 + * + * Revision 2.7 1998/05/25 14:10:15 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.6 1998/05/25 12:58:11 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.5 1998/02/12 23:07:52 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -47,7 +65,64 @@ #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 2.5 $"; +const char *l3_revision = "$Revision: 2.9 $"; + +static +struct Fsm l3fsm = +{NULL, 0, 0, NULL, NULL}; + +enum { + ST_L3_LC_REL, + ST_L3_LC_ESTAB_WAIT, + ST_L3_LC_REL_DELAY, + ST_L3_LC_REL_WAIT, + ST_L3_LC_ESTAB, +}; + +#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1) + +static char *strL3State[] = +{ + "ST_L3_LC_REL", + "ST_L3_LC_ESTAB_WAIT", + "ST_L3_LC_REL_DELAY", + "ST_L3_LC_REL_WAIT", + "ST_L3_LC_ESTAB", +}; + +enum { + EV_ESTABLISH_REQ, + EV_ESTABLISH_IND, + EV_ESTABLISH_CNF, + EV_RELEASE_REQ, + EV_RELEASE_CNF, + EV_RELEASE_IND, + EV_TIMEOUT, +}; + +#define L3_EVENT_COUNT (EV_TIMEOUT+1) + +static char *strL3Event[] = +{ + "EV_ESTABLISH_REQ", + "EV_ESTABLISH_IND", + "EV_ESTABLISH_CNF", + "EV_RELEASE_REQ", + "EV_RELEASE_CNF", + "EV_RELEASE_IND", + "EV_TIMEOUT", +}; + +static void +l3m_debug(struct FsmInst *fi, char *fmt, ...) +{ + va_list args; + struct PStack *st = fi->userdata; + + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args); + va_end(args); +} u_char * findie(u_char * p, int size, u_char ie, int wanted_set) @@ -74,7 +149,14 @@ else { if (codeset == wanted_set) { if (*p == ie) - return (p); + { /* improved length check (Werner Cornelius) */ + if ((pend - p) < 2) + return(NULL); + if (*(p+1) > (pend - (p+2))) + return(NULL); + return (p); + } + if (*p > ie) return (NULL); } @@ -90,15 +172,15 @@ int getcallref(u_char * p) { - int l, m = 1, cr = 0; + int l, cr = 0; + p++; /* prot discr */ + if (*p & 0xfe) /* wrong callref BRI only 1 octet*/ + return(-2); l = 0xf & *p++; /* callref length */ if (!l) /* dummy CallRef */ return(-1); - while (l--) { - cr += m * (*p++); - m *= 8; - } + cr = *p++; return (cr); } @@ -115,25 +197,12 @@ } void -l3_debug(struct PStack *st, char *s) -{ - char str[256], tm[32]; - - jiftime(tm, jiffies); - sprintf(str, "%s l3 %s\n", tm, s); - HiSax_putstatus(st->l1.hardware, str); -} - -void newl3state(struct l3_process *pc, int state) { - char tmp[80]; - - if (pc->debug & L3_DEB_STATE) { - sprintf(tmp, "newstate cr %d %d --> %d", pc->callref, - pc->state, state); - l3_debug(pc->st, tmp); - } + if (pc->debug & L3_DEB_STATE) + l3_debug(pc->st, "newstate cr %d %d --> %d", + pc->callref & 0x7F, + pc->state, state); pc->state = state; } @@ -188,6 +257,7 @@ printk(KERN_WARNING "HiSax: No skb for D-channel\n"); return (NULL); } + SET_SKB_FREE(skb); skb_reserve(skb, MAX_HEADER_LEN); return (skb); } @@ -197,12 +267,19 @@ { struct sk_buff *skb = arg; - HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n"); + HiSax_putstatus(st->l1.hardware, "L3", "no D protocol"); if (skb) { - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } } +static int +no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) +{ + printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n",ic->arg & 0xFF); + return(-1); +} + #ifdef CONFIG_HISAX_EURO extern void setstack_dss1(struct PStack *st); #endif @@ -246,7 +323,7 @@ np->next = p; } p->next = NULL; - p->debug = L3_DEB_WARN; + p->debug = st->l3.debug; p->callref = cr; p->state = 0; p->chan = NULL; @@ -269,24 +346,47 @@ StopAllL3Timer(p); if (pp) pp->next = np->next; - else - p->st->l3.proc = np->next; + else if (!(p->st->l3.proc = np->next) && + !test_bit(FLG_PTP, &p->st->l2.flag)) + FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); kfree(p); return; } pp = np; np = np->next; } - printk(KERN_ERR "HiSax internal L3 error CR not in list\n"); + printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref); + l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref); }; +static void +l3ml3p(struct PStack *st, int pr) +{ + struct l3_process *p = st->l3.proc; + + while (p) { + st->l3.l3ml3(st, pr, p); + p = p->next; + } +} + void -setstack_isdnl3(struct PStack *st, struct Channel *chanp) +setstack_l3dc(struct PStack *st, struct Channel *chanp) { char tmp[64]; st->l3.proc = NULL; st->l3.global = NULL; + skb_queue_head_init(&st->l3.squeue); + st->l3.l3m.fsm = &l3fsm; + st->l3.l3m.state = ST_L3_LC_REL; + st->l3.l3m.debug = 1; + st->l3.l3m.userdata = st; + st->l3.l3m.userint = 0; + st->l3.l3m.printdebug = l3m_debug; + FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer); + strcpy(st->l3.debug_id, "L3DC "); + st->lli.l4l3_proto = no_l3_proto_spec; #ifdef CONFIG_HISAX_EURO if (st->protocol == ISDN_PTYPE_EURO) { @@ -306,10 +406,12 @@ if (st->protocol == ISDN_PTYPE_LEASED) { st->lli.l4l3 = no_l3_proto; st->l2.l2l3 = no_l3_proto; + st->l3.l3ml3 = no_l3_proto; printk(KERN_INFO "HiSax: Leased line mode\n"); } else { st->lli.l4l3 = no_l3_proto; st->l2.l2l3 = no_l3_proto; + st->l3.l3ml3 = no_l3_proto; sprintf(tmp, "protocol %s not supported", (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : (st->protocol == ISDN_PTYPE_EURO) ? "euro" : @@ -321,6 +423,11 @@ } void +isdnl3_trans(struct PStack *st, int pr, void *arg) { + st->l3.l3l2(st, pr, arg); +} + +void releasestack_isdnl3(struct PStack *st) { while (st->l3.proc) @@ -330,4 +437,174 @@ kfree(st->l3.global); st->l3.global = NULL; } + FsmDelTimer(&st->l3.l3m_timer, 54); + discard_queue(&st->l3.squeue); +} + +void +setstack_l3bc(struct PStack *st, struct Channel *chanp) +{ + + st->l3.proc = NULL; + st->l3.global = NULL; + skb_queue_head_init(&st->l3.squeue); + st->l3.l3m.fsm = &l3fsm; + st->l3.l3m.state = ST_L3_LC_REL; + st->l3.l3m.debug = 1; + st->l3.l3m.userdata = st; + st->l3.l3m.userint = 0; + st->l3.l3m.printdebug = l3m_debug; + strcpy(st->l3.debug_id, "L3BC "); + st->lli.l4l3 = isdnl3_trans; +} + +#define DREL_TIMER_VALUE 40000 + +static void +lc_activate(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); + st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +lc_connect(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + FsmChangeState(fi, ST_L3_LC_ESTAB); + while ((skb = skb_dequeue(&st->l3.squeue))) { + st->l3.l3l2(st, DL_DATA | REQUEST, skb); + } + l3ml3p(st, DL_ESTABLISH | INDICATION); +} + +static void +lc_connected(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + struct sk_buff *skb = arg; + + FsmDelTimer(&st->l3.l3m_timer, 51); + FsmChangeState(fi, ST_L3_LC_ESTAB); + while ((skb = skb_dequeue(&st->l3.squeue))) { + st->l3.l3l2(st, DL_DATA | REQUEST, skb); + } + l3ml3p(st, DL_ESTABLISH | CONFIRM); +} + +static void +lc_start_delay(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_REL_DELAY); + FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); +} + +static void +lc_release_req(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_REL_WAIT); + st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); +} + +static void +lc_release_ind(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmDelTimer(&st->l3.l3m_timer, 52); + FsmChangeState(fi, ST_L3_LC_REL); + discard_queue(&st->l3.squeue); + l3ml3p(st, DL_RELEASE | INDICATION); +} + +static void +lc_release_cnf(struct FsmInst *fi, int event, void *arg) +{ + struct PStack *st = fi->userdata; + + FsmChangeState(fi, ST_L3_LC_REL); + discard_queue(&st->l3.squeue); + l3ml3p(st, DL_RELEASE | CONFIRM); +} + + +/* *INDENT-OFF* */ +static struct FsmNode L3FnList[] HISAX_INITDATA = +{ + {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, + {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, + {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect}, + {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected}, + {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay}, + {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, + {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, + {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay}, + {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind}, + {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected}, + {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req}, + {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf}, + {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate}, +}; +/* *INDENT-ON* */ + +#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode)) + +void +l3_msg(struct PStack *st, int pr, void *arg) +{ + + switch (pr) { + case (DL_DATA | REQUEST): + if (st->l3.l3m.state == ST_L3_LC_ESTAB) { + st->l3.l3l2(st, pr, arg); + } else { + struct sk_buff *skb = arg; + + skb_queue_head(&st->l3.squeue, skb); + FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); + } + break; + case (DL_ESTABLISH | REQUEST): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); + break; + case (DL_ESTABLISH | CONFIRM): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL); + break; + case (DL_ESTABLISH | INDICATION): + FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL); + break; + case (DL_RELEASE | INDICATION): + FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL); + break; + case (DL_RELEASE | CONFIRM): + FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL); + break; + case (DL_RELEASE | REQUEST): + FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); + break; + } +} + +HISAX_INITFUNC(void +Isdnl3New(void)) +{ + l3fsm.state_count = L3_STATE_COUNT; + l3fsm.event_count = L3_EVENT_COUNT; + l3fsm.strEvent = strL3Event; + l3fsm.strState = strL3State; + FsmNew(&l3fsm, L3FnList, L3_FN_COUNT); +} + +void +Isdnl3Free(void) +{ + FsmFree(&l3fsm); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h --- v2.2.10/linux/drivers/isdn/hisax/isdnl3.h Wed Apr 1 16:20:59 1998 +++ linux/drivers/isdn/hisax/isdnl3.h Mon Aug 9 12:04:39 1999 @@ -1,6 +1,20 @@ -/* $Id: isdnl3.h,v 2.0 1997/07/27 21:15:42 keil Exp $ +/* $Id: isdnl3.h,v 2.4 1999/07/01 08:11:54 keil Exp $ * $Log: isdnl3.h,v $ + * Revision 2.4 1999/07/01 08:11:54 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.3 1998/11/15 23:55:06 keil + * changes from 2.0 + * + * Revision 2.2 1998/05/25 14:10:17 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.1 1998/05/25 12:58:13 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.0 1997/07/27 21:15:42 keil * New Callref based layer3 * @@ -22,20 +36,23 @@ #define SBIT(state) (1<l1.hardware, "l3 ", fmt, ## args) + extern void newl3state(struct l3_process *pc, int state); extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t); extern void L3DelTimer(struct L3Timer *t); @@ -45,3 +62,4 @@ extern struct l3_process *new_l3_process(struct PStack *st, int cr); extern void release_l3_process(struct l3_process *p); extern struct l3_process *getl3proc(struct PStack *st, int cr); +extern void l3_msg(struct PStack *st, int pr, void *arg); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c --- v2.2.10/linux/drivers/isdn/hisax/isurf.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/isurf.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,252 @@ +/* $Id: isurf.c,v 1.3 1999/07/12 21:05:18 keil Exp $ + + * isurf.c low level stuff for Siemens I-Surf/I-Talk cards + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * $Log: isurf.c,v $ + * Revision 1.3 1999/07/12 21:05:18 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.2 1999/07/01 08:07:56 keil + * Initial version + * + * + * + */ + +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "isac.h" +#include "isar.h" +#include "isdnl1.h" + +extern const char *CardType[]; + +static const char *ISurf_revision = "$Revision: 1.3 $"; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +#define ISURF_ISAR_RESET 1 +#define ISURF_ISAC_RESET 2 +#define ISURF_ISAR_EA 4 +#define ISURF_ARCOFI_RESET 8 +#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET) + +#define ISURF_ISAR_OFFSET 0 +#define ISURF_ISAC_OFFSET 0x100 + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readb(cs->hw.isurf.isac + offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writeb(value, cs->hw.isurf.isac + offset); mb(); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + register int i; + for (i = 0; i < size; i++) + data[i] = readb(cs->hw.isurf.isac); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + register int i; + for (i = 0; i < size; i++){ + writeb(data[i], cs->hw.isurf.isac);mb(); + } +} + +/* ISAR access routines + * mode = 0 access with IRQ on + * mode = 1 access with IRQ off + * mode = 2 access with IRQ off and using last offset + */ + +static u_char +ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) +{ + return(readb(cs->hw.isurf.isar + offset)); +} + +static void +WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) +{ + writeb(value, cs->hw.isurf.isar + offset);mb(); +} + +static void +isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + int cnt = 5; + + if (!cs) { + printk(KERN_WARNING "ISurf: Spurious interrupt!\n"); + return; + } + + val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); + Start_ISAR: + if (val & ISAR_IRQSTA) + isar_int_main(cs); + val = readb(cs->hw.isurf.isac + ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); + if ((val & ISAR_IRQSTA) && --cnt) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "ISAR IntStat after IntRoutine"); + goto Start_ISAR; + } + val = readb(cs->hw.isurf.isac + ISAC_ISTA); + if (val && --cnt) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (!cnt) + printk(KERN_WARNING "ISurf IRQ LOOP\n"); + + writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); + writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb(); + writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb(); + writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); +} + +void +release_io_isurf(struct IsdnCardState *cs) +{ + release_region(cs->hw.isurf.reset, 1); +} + +static void +reset_isurf(struct IsdnCardState *cs, u_char chips) +{ + long flags; + + printk(KERN_INFO "ISurf: resetting card\n"); + + byteout(cs->hw.isurf.reset, chips); /* Reset On */ + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + restore_flags(flags); +} + +static int +ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + reset_isurf(cs, ISURF_RESET); + return(0); + case CARD_RELEASE: + release_io_isurf(cs); + return(0); + case CARD_INIT: + clear_pending_isac_ints(cs); + writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb(); + initisac(cs); + initisar(cs); + /* Reenable ISAC IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + return(0); + case CARD_TEST: + return(0); + case CARD_LOAD_FIRM: + if (isar_load_firmware(cs, arg)) + return(1); + ll_run(cs); + reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | + ISURF_ARCOFI_RESET); + initisac(cs); + cs->writeisac(cs, ISAC_MASK, 0); + cs->writeisac(cs, ISAC_CMDR, 0x41); + return(0); + } + return(0); +} + +__initfunc(int +setup_isurf(struct IsdnCard *card)) +{ + int ver; + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, ISurf_revision); + printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); + + if (cs->typ != ISDN_CTYPE_ISURF) + return(0); + if (card->para[1] && card->para[2]) { + cs->hw.isurf.reset = card->para[1]; + cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET; + cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET; + cs->irq = card->para[0]; + } else { + printk(KERN_WARNING "HiSax: %s port/mem not set\n", + CardType[card->typ]); + return (0); + } + if (check_region(cs->hw.isurf.reset, 1)) { + printk(KERN_WARNING + "HiSax: %s config port %x already in use\n", + CardType[card->typ], + cs->hw.isurf.reset); + return (0); + } else { + request_region(cs->hw.isurf.reset, 1, "isurf isdn"); + } + + printk(KERN_INFO + "ISurf: defined at 0x%x 0x%x IRQ %d\n", + cs->hw.isurf.reset, + cs->hw.isurf.isar, + cs->irq); + + cs->cardmsg = &ISurf_card_msg; + cs->irq_func = &isurf_interrupt; + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; + cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; + reset_isurf(cs, ISURF_RESET); + test_and_set_bit(HW_ISAR, &cs->HW_Flags); + ISACVersion(cs, "ISurf:"); + cs->BC_Read_Reg = &ReadISAR; + cs->BC_Write_Reg = &WriteISAR; + cs->BC_Send_Data = &isar_fill_fifo; + ver = ISARVersion(cs, "ISurf:"); + if (ver < 0) { + printk(KERN_WARNING + "ISurf: wrong ISAR version (ret = %d)\n", ver); + release_io_isurf(cs); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.2.10/linux/drivers/isdn/hisax/ix1_micro.c Wed Apr 1 16:21:01 1998 +++ linux/drivers/isdn/hisax/ix1_micro.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: ix1_micro.c,v 2.6 1998/02/11 17:28:09 keil Exp $ +/* $Id: ix1_micro.c,v 2.8 1999/07/12 21:05:19 keil Exp $ * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil @@ -11,6 +11,13 @@ * Beat Doebeli * * $Log: ix1_micro.c,v $ + * Revision 2.8 1999/07/12 21:05:19 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.7 1998/04/15 16:44:31 keil + * new init code + * * Revision 2.6 1998/02/11 17:28:09 keil * Niccy PnP/PCI support * @@ -81,7 +88,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.6 $"; +const char *ix1_revision = "$Revision: 2.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -196,7 +203,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "IX1: Spurious interrupt!\n"); @@ -204,16 +211,12 @@ } val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) @@ -226,16 +229,12 @@ debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); - } - if (stat & 2) { - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); - } + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); + writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); } void @@ -273,14 +272,8 @@ case CARD_RELEASE: release_io_ix1micro(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &ix1micro_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -331,6 +324,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &ix1_card_msg; + cs->irq_func = &ix1micro_interrupt; ISACVersion(cs, "ix1-Micro:"); if (HscxVersion(cs, "ix1-Micro:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c --- v2.2.10/linux/drivers/isdn/hisax/jade.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/jade.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,326 @@ +/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $ + * + * jade.c JADE stuff (derived from original hscx.c) + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * $Log: jade.c,v $ + * Revision 1.2 1999/07/01 08:07:57 keil + * Initial version + * + * + */ + + +#define __NO_VERSION__ +#include "hisax.h" +#include "hscx.h" +#include "jade.h" +#include "isdnl1.h" +#include + + +HISAX_INITFUNC(int +JadeVersion(struct IsdnCardState *cs, char *s)) +{ + int ver,i; + int to = 50; + cs->BC_Write_Reg(cs, -1, 0x50, 0x19); + i=0; + while (to) { + udelay(1); + ver = cs->BC_Read_Reg(cs, -1, 0x60); + to--; + if (ver) + break; + if (!to) { + printk(KERN_INFO "%s JADE version not obtainable\n", s); + return (0); + } + } + /* Wait for the JADE */ + udelay(10); + /* Read version */ + ver = cs->BC_Read_Reg(cs, -1, 0x60); + printk(KERN_INFO "%s JADE version: %d\n", s, ver); + return (1); +} + +/* Write to indirect accessible jade register set */ +static void +jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value) +{ + int to = 50; + long flags; + u_char ret; + save_flags(flags); + cli(); + /* Write the data */ + cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value); + /* Say JADE we wanna write indirect reg 'reg' */ + cs->BC_Write_Reg(cs, -1, COMM_JADE, reg); + to = 50; + /* Wait for RDY goes high */ + while (to) { + udelay(1); + ret = cs->BC_Read_Reg(cs, -1, COMM_JADE); + to--; + if (ret & 1) + /* Got acknowledge */ + break; + if (!to) { + restore_flags(flags); + printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value); + return; + } + } + restore_flags(flags); +} + + + +void +modejade(struct BCState *bcs, int mode, int bc) +{ + struct IsdnCardState *cs = bcs->cs; + int jade = bcs->hw.hscx.hscx; + + if (cs->debug & L1_DEB_HSCX) { + char tmp[40]; + sprintf(tmp, "jade %c mode %d ichan %d", + 'A' + jade, mode, bc); + debugl1(cs, tmp); + } + bcs->mode = mode; + bcs->channel = bc; + + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00); + + jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08); + jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08); + jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00); + jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00); + + cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07); + cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07); + + if (bc == 0) { + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00); + } else { + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04); + cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04); + } + switch (mode) { + case (L1_MODE_NULL): + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO); + break; + case (L1_MODE_TRANS): + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC)); + break; + case (L1_MODE_HDLC): + cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC)); + break; + } + if (mode) { + cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC)); + cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES); + /* Unmask ints */ + cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8); + } + else + /* Mask ints */ + cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00); +} + +void +jade_sched_event(struct BCState *bcs, int event) +{ + bcs->event |= 1 << event; + queue_task(&bcs->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void +jade_l2l1(struct PStack *st, int pr, void *arg) +{ + struct sk_buff *skb = arg; + long flags; + + switch (pr) { + case (PH_DATA | REQUEST): + save_flags(flags); + cli(); + if (st->l1.bcs->tx_skb) { + skb_queue_tail(&st->l1.bcs->squeue, skb); + restore_flags(flags); + } else { + st->l1.bcs->tx_skb = skb; + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->hw.hscx.count = 0; + restore_flags(flags); + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + } + break; + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { + printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n"); + break; + } + test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + st->l1.bcs->tx_skb = skb; + st->l1.bcs->hw.hscx.count = 0; + st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); + break; + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { + test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); + } else + test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); + break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + modejade(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + modejade(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; + } +} + +void +close_jadestate(struct BCState *bcs) +{ + modejade(bcs, 0, bcs->channel); + if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { + if (bcs->hw.hscx.rcvbuf) { + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + } + if (bcs->blog) { + kfree(bcs->blog); + bcs->blog = NULL; + } + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + } + } +} + +static int +open_jadestate(struct IsdnCardState *cs, struct BCState *bcs) +{ + if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { + if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for hscx.rcvbuf\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + return (1); + } + if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for bcs->blog\n"); + test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + return (2); + } + skb_queue_head_init(&bcs->rqueue); + skb_queue_head_init(&bcs->squeue); + } + bcs->tx_skb = NULL; + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + bcs->event = 0; + bcs->hw.hscx.rcvidx = 0; + bcs->tx_cnt = 0; + return (0); +} + + +int +setstack_jade(struct PStack *st, struct BCState *bcs) +{ + bcs->channel = st->l1.bc; + if (open_jadestate(st->l1.hardware, bcs)) + return (-1); + st->l1.bcs = bcs; + st->l2.l2l1 = jade_l2l1; + setstack_manager(st); + bcs->st = st; + setstack_l1_B(st); + return (0); +} + +HISAX_INITFUNC(void +clear_pending_jade_ints(struct IsdnCardState *cs)) +{ + int val; + char tmp[64]; + + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); + + val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR); + sprintf(tmp, "jade B ISTA %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR); + sprintf(tmp, "jade A ISTA %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR); + sprintf(tmp, "jade B STAR %x", val); + debugl1(cs, tmp); + val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR); + sprintf(tmp, "jade A STAR %x", val); + debugl1(cs, tmp); + /* Unmask ints */ + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); +} + +HISAX_INITFUNC(void +initjade(struct IsdnCardState *cs)) +{ + cs->bcs[0].BC_SetStack = setstack_jade; + cs->bcs[1].BC_SetStack = setstack_jade; + cs->bcs[0].BC_Close = close_jadestate; + cs->bcs[1].BC_Close = close_jadestate; + cs->bcs[0].hw.hscx.hscx = 0; + cs->bcs[1].hw.hscx.hscx = 1; + + /* Stop DSP audio tx/rx */ + jade_write_indirect(cs, 0x11, 0x0f); + jade_write_indirect(cs, 0x17, 0x2f); + + /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */ + cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO); + cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO); + /* Power down, 1-Idle, RxTx least significant bit first */ + cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00); + /* Mask all interrupts */ + cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); + cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); + /* Setup host access to hdlc controller */ + jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2)); + /* Unmask HDLC int (don´t forget DSP int later on)*/ + cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2)); + + /* once again TRANSPARENT */ + modejade(cs->bcs, 0, 0); + modejade(cs->bcs + 1, 0, 0); +} + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/jade.h linux/drivers/isdn/hisax/jade.h --- v2.2.10/linux/drivers/isdn/hisax/jade.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/jade.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,137 @@ +/* $Id: jade.h,v 1.2 1999/07/01 08:07:58 keil Exp $ + * jade.h JADE specific defines + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * + * $Log: jade.h,v $ + * Revision 1.2 1999/07/01 08:07:58 keil + * Initial version + * + * + */ + +/* All Registers original Siemens Spec */ +#ifndef __JADE_H__ +#define __JADE_H__ + +/* Special registers for access to indirect accessible JADE regs */ +#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */ +#define COMM_JADE 0x0040 /* Jade communication area */ + +/********************************************************************/ +/* JADE-HDLC registers */ +/********************************************************************/ +#define jade_HDLC_RFIFO 0x00 /* R */ +#define jade_HDLC_XFIFO 0x00 /* W */ + +#define jade_HDLC_STAR 0x20 /* R */ + #define jadeSTAR_XDOV 0x80 + #define jadeSTAR_XFW 0x40 /* Does not work*/ + #define jadeSTAR_XCEC 0x20 + #define jadeSTAR_RCEC 0x10 + #define jadeSTAR_BSY 0x08 + #define jadeSTAR_RNA 0x04 + #define jadeSTAR_STR 0x02 + #define jadeSTAR_STX 0x01 + +#define jade_HDLC_XCMD 0x20 /* W */ + #define jadeXCMD_XF 0x80 + #define jadeXCMD_XME 0x40 + #define jadeXCMD_XRES 0x20 + #define jadeXCMD_STX 0x01 + +#define jade_HDLC_RSTA 0x21 /* R */ + #define jadeRSTA_VFR 0x80 + #define jadeRSTA_RDO 0x40 + #define jadeRSTA_CRC 0x20 + #define jadeRSTA_RAB 0x10 + #define jadeRSTA_MASK 0xF0 + +#define jade_HDLC_MODE 0x22 /* RW*/ + #define jadeMODE_TMO 0x80 + #define jadeMODE_RAC 0x40 + #define jadeMODE_XAC 0x20 + #define jadeMODE_TLP 0x10 + #define jadeMODE_ERFS 0x02 + #define jadeMODE_ETFS 0x01 + +#define jade_HDLC_RBCH 0x24 /* R */ + +#define jade_HDLC_RBCL 0x25 /* R */ +#define jade_HDLC_RCMD 0x25 /* W */ + #define jadeRCMD_RMC 0x80 + #define jadeRCMD_RRES 0x40 + #define jadeRCMD_RMD 0x20 + #define jadeRCMD_STR 0x02 + +#define jade_HDLC_CCR0 0x26 /* RW*/ + #define jadeCCR0_PU 0x80 + #define jadeCCR0_ITF 0x40 + #define jadeCCR0_C32 0x20 + #define jadeCCR0_CRL 0x10 + #define jadeCCR0_RCRC 0x08 + #define jadeCCR0_XCRC 0x04 + #define jadeCCR0_RMSB 0x02 + #define jadeCCR0_XMSB 0x01 + +#define jade_HDLC_CCR1 0x27 /* RW*/ + #define jadeCCR1_RCS0 0x80 + #define jadeCCR1_RCONT 0x40 + #define jadeCCR1_RFDIS 0x20 + #define jadeCCR1_XCS0 0x10 + #define jadeCCR1_XCONT 0x08 + #define jadeCCR1_XFDIS 0x04 + +#define jade_HDLC_TSAR 0x28 /* RW*/ +#define jade_HDLC_TSAX 0x29 /* RW*/ +#define jade_HDLC_RCCR 0x2A /* RW*/ +#define jade_HDLC_XCCR 0x2B /* RW*/ + +#define jade_HDLC_ISR 0x2C /* R */ +#define jade_HDLC_IMR 0x2C /* W */ + #define jadeISR_RME 0x80 + #define jadeISR_RPF 0x40 + #define jadeISR_RFO 0x20 + #define jadeISR_XPR 0x10 + #define jadeISR_XDU 0x08 + #define jadeISR_ALLS 0x04 + +#define jade_INT 0x75 + #define jadeINT_HDLC1 0x02 + #define jadeINT_HDLC2 0x01 + #define jadeINT_DSP 0x04 +#define jade_INTR 0x70 + +/********************************************************************/ +/* Indirect accessible JADE registers of common interest */ +/********************************************************************/ +#define jade_CHIPVERSIONNR 0x00 /* Does not work*/ + +#define jade_HDLCCNTRACCESS 0x10 + #define jadeINDIRECT_HAH1 0x02 + #define jadeINDIRECT_HAH2 0x01 + +#define jade_HDLC1SERRXPATH 0x1D +#define jade_HDLC1SERTXPATH 0x1E +#define jade_HDLC2SERRXPATH 0x1F +#define jade_HDLC2SERTXPATH 0x20 + #define jadeINDIRECT_SLIN1 0x10 + #define jadeINDIRECT_SLIN0 0x08 + #define jadeINDIRECT_LMOD1 0x04 + #define jadeINDIRECT_LMOD0 0x02 + #define jadeINDIRECT_HHR 0x01 + #define jadeINDIRECT_HHX 0x01 + +#define jade_RXAUDIOCH1CFG 0x11 +#define jade_RXAUDIOCH2CFG 0x14 +#define jade_TXAUDIOCH1CFG 0x17 +#define jade_TXAUDIOCH2CFG 0x1A + +extern int JadeVersion(struct IsdnCardState *cs, char *s); +extern void jade_sched_event(struct BCState *bcs, int event); +extern void modejade(struct BCState *bcs, int mode, int bc); +extern void clear_pending_jade_ints(struct IsdnCardState *cs); +extern void initjade(struct IsdnCardState *cs); + +#endif /* __JADE_H__ */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c --- v2.2.10/linux/drivers/isdn/hisax/jade_irq.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/jade_irq.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,247 @@ +/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $ + * + * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) + * + * Author Roland Klabunde (R.Klabunde@Berkom.de) + * + * $Log: jade_irq.c,v $ + * Revision 1.2 1999/07/01 08:07:59 keil + * Initial version + * + * + */ + +static inline void +waitforCEC(struct IsdnCardState *cs, int jade, int reg) +{ + int to = 50; + int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC); + while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) { + udelay(1); + to--; + } + if (!to) + printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n"); +} + + +static inline void +waitforXFW(struct IsdnCardState *cs, int jade) +{ + /* Does not work on older jade versions, don't care */ +} + +static inline void +WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data) +{ + long flags; + + save_flags(flags); + cli(); + waitforCEC(cs, jade, reg); + WRITEJADE(cs, jade, reg, data); + restore_flags(flags); +} + + + +static void +jade_empty_fifo(struct BCState *bcs, int count) +{ + u_char *ptr; + struct IsdnCardState *cs = bcs->cs; + long flags; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "jade_empty_fifo"); + + if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "jade_empty_fifo: incoming packet too large"); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); + bcs->hw.hscx.rcvidx = 0; + return; + } + ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; + bcs->hw.hscx.rcvidx += count; + save_flags(flags); + cli(); + READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); + restore_flags(flags); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "jade_empty_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + +static void +jade_fill_fifo(struct BCState *bcs) +{ + struct IsdnCardState *cs = bcs->cs; + int more, count; + int fifo_size = 32; + u_char *ptr; + long flags; + + if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) + debugl1(cs, "jade_fill_fifo"); + + if (!bcs->tx_skb) + return; + if (bcs->tx_skb->len <= 0) + return; + + more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; + if (bcs->tx_skb->len > fifo_size) { + more = !0; + count = fifo_size; + } else + count = bcs->tx_skb->len; + + waitforXFW(cs, bcs->hw.hscx.hscx); + save_flags(flags); + cli(); + ptr = bcs->tx_skb->data; + skb_pull(bcs->tx_skb, count); + bcs->tx_cnt -= count; + bcs->hw.hscx.count += count; + WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME)); + restore_flags(flags); + if (cs->debug & L1_DEB_HSCX_FIFO) { + char *t = bcs->blog; + + t += sprintf(t, "jade_fill_fifo %c cnt %d", + bcs->hw.hscx.hscx ? 'B' : 'A', count); + QuickHex(t, ptr, count); + debugl1(cs, bcs->blog); + } +} + + +static inline void +jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) +{ + u_char r; + struct BCState *bcs = cs->bcs + jade; + struct sk_buff *skb; + int fifo_size = 32; + int count; + int i_jade = (int) jade; /* To satisfy the compiler */ + + if (!test_bit(BC_FLG_INIT, &bcs->Flag)) + return; + + if (val & 0x80) { /* RME */ + r = READJADE(cs, i_jade, jade_HDLC_RSTA); + if ((r & 0xf0) != 0xa0) { + if (!(r & 0x80)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A")); + if ((r & 0x40) && bcs->mode) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode); + if (!(r & 0x20)) + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "JADE %c CRC error", 'A'+jade); + WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); + } else { + count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; + if (count == 0) + count = fifo_size; + jade_empty_fifo(bcs, count); + if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { + if (cs->debug & L1_DEB_HSCX_FIFO) + debugl1(cs, "HX Frame %d", count); + if (!(skb = dev_alloc_skb(count))) + printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A")); + else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); + skb_queue_tail(&bcs->rqueue, skb); + } + } + } + bcs->hw.hscx.rcvidx = 0; + jade_sched_event(bcs, B_RCVBUFREADY); + } + if (val & 0x40) { /* RPF */ + jade_empty_fifo(bcs, fifo_size); + if (bcs->mode == L1_MODE_TRANS) { + /* receive audio data */ + if (!(skb = dev_alloc_skb(fifo_size))) + printk(KERN_WARNING "HiSax: receive out of memory\n"); + else { + SET_SKB_FREE(skb); + memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); + skb_queue_tail(&bcs->rqueue, skb); + } + bcs->hw.hscx.rcvidx = 0; + jade_sched_event(bcs, B_RCVBUFREADY); + } + } + if (val & 0x10) { /* XPR */ + if (bcs->tx_skb) { + if (bcs->tx_skb->len) { + jade_fill_fifo(bcs); + return; + } else { + if (bcs->st->lli.l1writewakeup && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); + jade_fill_fifo(bcs); + } else { + test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); + jade_sched_event(bcs, B_XMTBUFREADY); + } + } +} + +static inline void +jade_int_main(struct IsdnCardState *cs, u_char val, int jade) +{ + struct BCState *bcs; + bcs = cs->bcs + jade; + + if (val & jadeISR_RFO) { + /* handled with RDO */ + val &= ~jadeISR_RFO; + } + if (val & jadeISR_XDU) { + /* relevant in HDLC mode only */ + /* don't reset XPR here */ + if (bcs->mode == 1) + jade_fill_fifo(bcs); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + if (bcs->tx_skb) { + skb_push(bcs->tx_skb, bcs->hw.hscx.count); + bcs->tx_cnt += bcs->hw.hscx.count; + bcs->hw.hscx.count = 0; + } + WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val); + } + } + if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val); + jade_interrupt(cs, val, jade); + } +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.2.10/linux/drivers/isdn/hisax/l3_1tr6.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/l3_1tr6.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,32 @@ -/* $Id: l3_1tr6.c,v 2.4 1998/02/12 23:07:57 keil Exp $ +/* $Id: l3_1tr6.c,v 2.9 1999/07/01 08:11:55 keil Exp $ * German 1TR6 D-channel protocol * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) + * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert * * * $Log: l3_1tr6.c,v $ + * Revision 2.9 1999/07/01 08:11:55 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.8 1998/11/15 23:55:08 keil + * changes from 2.0 + * + * Revision 2.7 1998/08/13 23:36:45 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.6 1998/05/25 14:10:18 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.5 1998/05/25 12:58:14 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * * Revision 2.4 1998/02/12 23:07:57 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -38,7 +59,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.4 $"; +const char *l3_1tr6_revision = "$Revision: 2.9 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ @@ -56,66 +77,34 @@ return; p = skb_put(skb, 4); MsgHead(p, pc->callref, mt, pd); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } -static int -l31tr6_check_messagetype_validity(int mt, int pd) { -/* verify if a message type exists */ - - if (pd == PROTO_DIS_N0) - switch(mt) { - case MT_N0_REG_IND: - case MT_N0_CANC_IND: - case MT_N0_FAC_STA: - case MT_N0_STA_ACK: - case MT_N0_STA_REJ: - case MT_N0_FAC_INF: - case MT_N0_INF_ACK: - case MT_N0_INF_REJ: - case MT_N0_CLOSE: - case MT_N0_CLO_ACK: - return(1); - default: - return(0); - } - else if (pd == PROTO_DIS_N1) - switch(mt) { - case MT_N1_ESC: - case MT_N1_ALERT: - case MT_N1_CALL_SENT: - case MT_N1_CONN: - case MT_N1_CONN_ACK: - case MT_N1_SETUP: - case MT_N1_SETUP_ACK: - case MT_N1_RES: - case MT_N1_RES_ACK: - case MT_N1_RES_REJ: - case MT_N1_SUSP: - case MT_N1_SUSP_ACK: - case MT_N1_SUSP_REJ: - case MT_N1_USER_INFO: - case MT_N1_DET: - case MT_N1_DISC: - case MT_N1_REL: - case MT_N1_REL_ACK: - case MT_N1_CANC_ACK: - case MT_N1_CANC_REJ: - case MT_N1_CON_CON: - case MT_N1_FAC: - case MT_N1_FAC_ACK: - case MT_N1_FAC_CAN: - case MT_N1_FAC_REG: - case MT_N1_FAC_REJ: - case MT_N1_INFO: - case MT_N1_REG_ACK: - case MT_N1_REG_REJ: - case MT_N1_STAT: - return (1); - default: - return(0); - } - return(0); +static void +l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) +{ + StopAllL3Timer(pc); + newl3state(pc, 19); + l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + + idev_kfree_skb(skb, FREE_READ); + l3_1tr6_release_req(pc, 0, NULL); +} + +static void +l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) +{ + idev_kfree_skb(skb, FREE_READ); + if (pc->st->l3.debug & L3_DEB_WARN) + l3_debug(pc->st, msg); + l3_1tr6_release_req(pc, 0, NULL); } static void @@ -204,7 +193,7 @@ L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void @@ -220,17 +209,29 @@ /* Channel Identification */ p = skb->data; if ((p = findie(p, skb->len, WE0_chanID, 0))) { - pc->para.bchannel = p[2] & 0x3; - bcfound++; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel"); + if (p[1] != 1) { + l3_1tr6_error(pc, "setup wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "setup wrong WE0_chanID", skb); + return; + } + if ((pc->para.bchannel = p[2] & 0x3)) + bcfound++; + } else { + l3_1tr6_error(pc, "missing setup chanID", skb); + return; + } p = skb->data; if ((p = findie(p, skb->len, WE6_serviceInd, 6))) { pc->para.setup.si1 = p[2]; pc->para.setup.si2 = p[3]; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without service indicator"); + } else { + l3_1tr6_error(pc, "missing setup SI", skb); + return; + } p = skb->data; if ((p = findie(p, skb->len, WE0_destAddr, 0))) @@ -250,7 +251,7 @@ if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) pc->para.spv = 1; } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); /* Signal all services, linklevel takes care of Service-Indicator */ if (bcfound) { @@ -261,7 +262,7 @@ l3_debug(pc->st, tmp); } newl3state(pc, 6); - pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } else release_l3_process(pc); } @@ -276,12 +277,22 @@ p = skb->data; newl3state(pc, 2); if ((p = findie(p, skb->len, WE0_chanID, 0))) { + if (p[1] != 1) { + l3_1tr6_error(pc, "setup_ack wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb); + return; + } pc->para.bchannel = p[2] & 0x3; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); - dev_kfree_skb(skb); + } else { + l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb); + return; + } + idev_kfree_skb(skb, FREE_READ); L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void @@ -293,13 +304,27 @@ L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, WE0_chanID, 0))) { + if (p[1] != 1) { + l3_1tr6_error(pc, "call sent wrong chanID len", skb); + return; + } + if ((p[2] & 0xf4) != 0x80) { + l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb); + return; + } + if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) { + l3_1tr6_error(pc, "call sent wrong chanID value", skb); + return; + } pc->para.bchannel = p[2] & 0x3; - } else if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); - dev_kfree_skb(skb); + } else { + l3_1tr6_error(pc, "missing call sent WE0_chanID", skb); + return; + } + idev_kfree_skb(skb, FREE_READ); L3AddTimer(&pc->timer, T310, CC_T310); newl3state(pc, 3); - pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void @@ -307,10 +332,10 @@ { struct sk_buff *skb = arg; - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); L3DelTimer(&pc->timer); /* T304 */ newl3state(pc, 4); - pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void @@ -330,7 +355,7 @@ } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -338,7 +363,7 @@ } } else if (pc->st->l3.debug & L3_DEB_CHARGE) l3_debug(pc->st, "charging info not found"); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } @@ -347,7 +372,7 @@ { struct sk_buff *skb = arg; - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } static void @@ -356,10 +381,14 @@ struct sk_buff *skb = arg; L3DelTimer(&pc->timer); /* T310 */ + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connect date", skb); + return; + } newl3state(pc, 10); - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void @@ -380,13 +409,16 @@ pc->para.cause = 0; pc->para.loc = 0; } - } else - pc->para.cause = -1; - dev_kfree_skb(skb); + } else { + pc->para.cause = NO_CAUSE; + l3_1tr6_error(pc, "missing REL cause", skb); + return; + } + idev_kfree_skb(skb, FREE_READ); StopAllL3Timer(pc); newl3state(pc, 0); l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); release_l3_process(pc); } @@ -395,11 +427,11 @@ { struct sk_buff *skb = arg; - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); StopAllL3Timer(pc); newl3state(pc, 0); - pc->para.cause = -1; - pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); release_l3_process(pc); } @@ -421,7 +453,7 @@ } if (tmpcharge > pc->para.chargeinfo) { pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); + pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); } if (pc->st->l3.debug & L3_DEB_CHARGE) { sprintf(tmp, "charging info %d", pc->para.chargeinfo); @@ -446,11 +478,15 @@ } else { if (pc->st->l3.debug & L3_DEB_WARN) l3_debug(pc->st, "cause not found"); - pc->para.cause = -1; + pc->para.cause = NO_CAUSE; } - dev_kfree_skb(skb); + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connack date", skb); + return; + } + idev_kfree_skb(skb, FREE_READ); newl3state(pc, 12); - pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); } @@ -459,11 +495,15 @@ { struct sk_buff *skb = arg; - dev_kfree_skb(skb); + if (!findie(skb->data, skb->len, WE6_date, 6)) { + l3_1tr6_error(pc, "missing connack date", skb); + return; + } + idev_kfree_skb(skb, FREE_READ); newl3state(pc, 10); pc->para.chargeinfo = 0; L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); } static void @@ -502,7 +542,7 @@ if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T313, CC_T313); } @@ -530,6 +570,9 @@ case 0x10: clen = 0; break; + case 0x11: + cause = CAUSE_UserBusy; + break; case 0x15: cause = CAUSE_CallRejected; break; @@ -545,20 +588,11 @@ if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); } static void -l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -567,8 +601,8 @@ l3_1tr6_setup_req(pc, pr, arg); } else { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL); - release_l3_process(pc); + pc->para.cause = 0; + l3_1tr6_disconnect_req(pc, 0, NULL); } } @@ -578,7 +612,7 @@ L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void @@ -592,7 +626,7 @@ u_char clen = 1; L3DelTimer(&pc->timer); - if (pc->para.cause > 0) + if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; /* Map DSS1 causes */ switch (cause & 0x7f) { @@ -613,7 +647,7 @@ if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); } @@ -623,7 +657,7 @@ L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void @@ -632,7 +666,7 @@ L3DelTimer(&pc->timer); pc->para.cause = 0xE6; l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void @@ -648,29 +682,45 @@ l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); release_l3_process(pc); } + +static void +l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = CAUSE_LocalProcErr; + l3_1tr6_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + /* *INDENT-OFF* */ static struct stateentry downstl[] = { {SBIT(0), - CC_SETUP_REQ, l3_1tr6_setup_req}, + CC_SETUP | REQUEST, l3_1tr6_setup_req}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), - CC_DISCONNECT_REQ, l3_1tr6_disconnect_req}, + CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req}, {SBIT(12), - CC_RELEASE_REQ, l3_1tr6_release_req}, - {ALL_STATES, - CC_DLRL, l3_1tr6_reset}, + CC_RELEASE | REQUEST, l3_1tr6_release_req}, {SBIT(6), - CC_IGNORE, l3_1tr6_reset}, + CC_IGNORE | REQUEST, l3_1tr6_reset}, {SBIT(6), - CC_REJECT_REQ, l3_1tr6_disconnect_req}, + CC_REJECT | REQUEST, l3_1tr6_disconnect_req}, {SBIT(6), - CC_ALERTING_REQ, l3_1tr6_alert_req}, + CC_ALERTING | REQUEST, l3_1tr6_alert_req}, {SBIT(6) | SBIT(7), - CC_SETUP_RSP, l3_1tr6_setup_rsp}, + CC_SETUP | RESPONSE, l3_1tr6_setup_rsp}, {SBIT(1), CC_T303, l3_1tr6_t303}, {SBIT(2), @@ -687,12 +737,14 @@ CC_T308_2, l3_1tr6_t308_2}, }; -static int downstl_len = sizeof(downstl) / -sizeof(struct stateentry); +#define DOWNSTL_LEN \ + (sizeof(downstl) / sizeof(struct stateentry)) static struct stateentry datastln1[] = { {SBIT(0), + MT_N1_INVALID, l3_1tr6_invalid}, + {SBIT(0), MT_N1_SETUP, l3_1tr6_setup}, {SBIT(1), MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, @@ -711,18 +763,31 @@ {SBIT(10), MT_N1_INFO, l3_1tr6_info}, {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | - SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19), + SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), MT_N1_REL, l3_1tr6_rel}, {SBIT(19), + MT_N1_REL, l3_1tr6_rel_ack}, + {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | + SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), + MT_N1_REL_ACK, l3_1tr6_invalid}, + {SBIT(19), MT_N1_REL_ACK, l3_1tr6_rel_ack} }; -/* *INDENT-ON* */ - +#define DATASTLN1_LEN \ + (sizeof(datastln1) / sizeof(struct stateentry)) - -static int datastln1_len = sizeof(datastln1) / -sizeof(struct stateentry); +static struct stateentry manstatelist[] = +{ + {SBIT(2), + DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3_1tr6_dl_release}, +}; + +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) +/* *INDENT-ON* */ static void up1tr6(struct PStack *st, int pr, void *arg) @@ -732,22 +797,34 @@ struct sk_buff *skb = arg; char tmp[80]; + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | CONFIRM): + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + } if (skb->len < 4) { if (st->l3.debug & L3_DEB_PROTERR) { sprintf(tmp, "up1tr6 len only %d", skb->len); l3_debug(st, tmp); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { if (st->l3.debug & L3_DEB_PROTERR) { sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d", - (pr == DL_DATA) ? " " : "(broadcast) ", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", skb->data[0], skb->len); l3_debug(st, tmp); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } if (skb->data[1] != 1) { @@ -755,43 +832,62 @@ sprintf(tmp, "up1tr6 CR len not 1"); l3_debug(st, tmp); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } cr = skb->data[2]; mt = skb->data[3]; if (skb->data[0] == PROTO_DIS_N0) { - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%s N0 mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", mt); + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt); l3_debug(st, tmp); } } else if (skb->data[0] == PROTO_DIS_N1) { if (!(proc = getl3proc(st, cr))) { - if ((mt == MT_N1_SETUP) && (cr < 128)) { + if (mt == MT_N1_SETUP) { + if (cr < 128) { + if (!(proc = new_l3_process(st, cr))) { + if (st->l3.debug & L3_DEB_PROTERR) { + sprintf(tmp, "up1tr6 no roc mem"); + l3_debug(st, tmp); + } + idev_kfree_skb(skb, FREE_READ); + return; + } + } else { + idev_kfree_skb(skb, FREE_READ); + return; + } + } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) || + (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) || + (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) || + (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) || + (mt == MT_N1_INFO)) { + idev_kfree_skb(skb, FREE_READ); + return; + } else { if (!(proc = new_l3_process(st, cr))) { if (st->l3.debug & L3_DEB_PROTERR) { sprintf(tmp, "up1tr6 no roc mem"); l3_debug(st, tmp); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } - } else { - dev_kfree_skb(skb); - return; + mt = MT_N1_INVALID; } } - for (i = 0; i < datastln1_len; i++) + for (i = 0; i < DATASTLN1_LEN; i++) if ((mt == datastln1[i].primitive) && ((1 << proc->state) & datastln1[i].state)) break; - if (i == datastln1_len) { - dev_kfree_skb(skb); + if (i == DATASTLN1_LEN) { + idev_kfree_skb(skb, FREE_READ); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); l3_debug(st, tmp); } @@ -799,7 +895,7 @@ } else { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x", - (pr == DL_DATA) ? " " : "(broadcast) ", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); l3_debug(st, tmp); } @@ -816,7 +912,10 @@ struct Channel *chan; char tmp[80]; - if (CC_SETUP_REQ == pr) { + if ((DL_ESTABLISH | REQUEST)== pr) { + l3_msg(st, pr, NULL); + return; + } else if ((CC_SETUP | REQUEST) == pr) { chan = arg; cr = newcallref(); cr |= 0x80; @@ -832,11 +931,11 @@ proc = arg; } - for (i = 0; i < downstl_len; i++) + for (i = 0; i < DOWNSTL_LEN; i++) if ((pr == downstl[i].primitive) && ((1 << proc->state) & downstl[i].state)) break; - if (i == downstl_len) { + if (i == DOWNSTL_LEN) { if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "down1tr6 state %d prim %d unhandled", proc->state, pr); @@ -852,6 +951,34 @@ } } +static void +man1tr6(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d man1tr6 state %d prim %d", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + void setstack_1tr6(struct PStack *st) { @@ -859,6 +986,7 @@ st->lli.l4l3 = down1tr6; st->l2.l2l3 = up1tr6; + st->l3.l3ml3 = man1tr6; st->l3.N303 = 0; strcpy(tmp, l3_1tr6_revision); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h --- v2.2.10/linux/drivers/isdn/hisax/l3_1tr6.h Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/l3_1tr6.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,11 @@ -/* $Id: l3_1tr6.h,v 2.0 1997/07/27 21:15:47 keil Exp $ +/* $Id: l3_1tr6.h,v 2.1 1998/08/13 23:36:48 keil Exp $ * * German 1TR6 D-channel protocol defines * * $Log: l3_1tr6.h,v $ + * Revision 2.1 1998/08/13 23:36:48 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * * Revision 2.0 1997/07/27 21:15:47 keil * New Callref based layer3 * @@ -64,6 +67,7 @@ #define MT_N1_REG_ACK 0x6C #define MT_N1_REG_REJ 0x6F #define MT_N1_STAT 0x63 +#define MT_N1_INVALID 0 /* * W Elemente diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.2.10/linux/drivers/isdn/hisax/l3dss1.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/l3dss1.c Mon Aug 9 12:04:39 1999 @@ -1,14 +1,42 @@ -/* $Id: l3dss1.c,v 2.7 1998/02/12 23:08:01 keil Exp $ +/* $Id: l3dss1.c,v 2.14 1999/07/09 08:30:08 keil Exp $ * EURO/DSS1 D-channel protocol * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.14 1999/07/09 08:30:08 keil + * cosmetics + * + * Revision 2.13 1999/07/01 08:11:58 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.12 1998/11/15 23:55:10 keil + * changes from 2.0 + * + * Revision 2.11 1998/08/13 23:36:51 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 2.10 1998/05/25 14:10:20 keil + * HiSax 3.0 + * X.75 and leased are working again. + * + * Revision 2.9 1998/05/25 12:58:17 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/03/19 13:18:47 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 2.7 1998/02/12 23:08:01 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -50,119 +78,349 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.7 $"; +const char *dss1_revision = "$Revision: 2.14 $"; #define EXT_BEARER_CAPS 1 #define MsgHead(ptr, cref, mty) \ *ptr++ = 0x8; \ - *ptr++ = 0x1; \ - *ptr++ = cref^0x80; \ + if (cref == -1) { \ + *ptr++ = 0x0; \ + } else { \ + *ptr++ = 0x1; \ + *ptr++ = cref^0x80; \ + } \ *ptr++ = mty -#ifdef HISAX_DE_AOC +/**********************************************/ +/* get a new invoke id for remote operations. */ +/* Only a return value != 0 is valid */ +/**********************************************/ +static unsigned char new_invoke_id(struct PStack *p) +{ + unsigned char retval; + int flags,i; + + i = 32; /* maximum search depth */ + + save_flags(flags); + cli(); + + retval = p->prot.dss1.last_invoke_id + 1; /* try new id */ + while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) { + p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8; + i--; + } + if (i) { + while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7))) + retval++; + } else + retval = 0; + p->prot.dss1.last_invoke_id = retval; + p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7)); + restore_flags(flags); + + return(retval); +} /* new_invoke_id */ + +/*************************/ +/* free a used invoke id */ +/*************************/ +static void free_invoke_id(struct PStack *p, unsigned char id) +{ int flags; + + if (!id) return; /* 0 = invalid value */ + + save_flags(flags); + cli(); + p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7)); + restore_flags(flags); +} /* free_invoke_id */ + + +/**********************************************************/ +/* create a new l3 process and fill in dss1 specific data */ +/**********************************************************/ +static struct l3_process +*dss1_new_l3_process(struct PStack *st, int cr) +{ struct l3_process *proc; + + if (!(proc = new_l3_process(st, cr))) + return(NULL); + + proc->prot.dss1.invoke_id = 0; + proc->prot.dss1.remote_operation = 0; + proc->prot.dss1.uus1_data[0] = '\0'; + + return(proc); +} /* dss1_new_l3_process */ + +/************************************************/ +/* free a l3 process and all dss1 specific data */ +/************************************************/ +static void +dss1_release_l3_process(struct l3_process *p) +{ + free_invoke_id(p->st,p->prot.dss1.invoke_id); + release_l3_process(p); +} /* dss1_release_l3_process */ + +/********************************************************/ +/* search a process with invoke id id and dummy callref */ +/********************************************************/ +static struct l3_process * +l3dss1_search_dummy_proc(struct PStack *st, int id) +{ struct l3_process *pc = st->l3.proc; /* start of processes */ + + if (!id) return(NULL); + + while (pc) + { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id)) + return(pc); + pc = pc->next; + } + return(NULL); +} /* l3dss1_search_dummy_proc */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return result is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3dss1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = DSS1_STAT_INVOKE_RES; + ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; + ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; + ic.parm.dss1_io.proc = pc->prot.dss1.proc; + ic.parm.dss1_io.timeout= 0; + ic.parm.dss1_io.datalen = nlen; + ic.parm.dss1_io.data = p; + free_invoke_id(pc->st, pc->prot.dss1.invoke_id); + pc->prot.dss1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + dss1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); +} /* l3dss1_dummy_return_result */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a return error is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3dss1_dummy_error_return(struct PStack *st, int id, ulong error) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + struct l3_process *pc = NULL; + + if ((pc = l3dss1_search_dummy_proc(st, id))) + { L3DelTimer(&pc->timer); /* remove timer */ + + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = DSS1_STAT_INVOKE_ERR; + ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; + ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; + ic.parm.dss1_io.proc = pc->prot.dss1.proc; + ic.parm.dss1_io.timeout= error; + ic.parm.dss1_io.datalen = 0; + ic.parm.dss1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.dss1.invoke_id); + pc->prot.dss1.invoke_id = 0; /* reset id */ + + cs->iif.statcallb(&ic); + dss1_release_l3_process(pc); + } + else + l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); +} /* l3dss1_error_return */ + +/*******************************************************************/ +/* called when a facility message with a dummy callref is received */ +/* and a invoke is delivered. id specifies the invoke id. */ +/*******************************************************************/ +static void +l3dss1_dummy_invoke(struct PStack *st, int cr, int id, + int ident, u_char *p, u_char nlen) +{ isdn_ctrl ic; + struct IsdnCardState *cs; + + l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", + (cr == -1) ? "local" : "broadcast",id,ident,nlen); + if (cr >= -1) return; /* ignore local data */ + + cs = st->l1.hardware; + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = DSS1_STAT_INVOKE_BRD; + ic.parm.dss1_io.hl_id = id; + ic.parm.dss1_io.ll_id = 0; + ic.parm.dss1_io.proc = ident; + ic.parm.dss1_io.timeout= 0; + ic.parm.dss1_io.datalen = nlen; + ic.parm.dss1_io.data = p; + + cs->iif.statcallb(&ic); +} /* l3dss1_dummy_invoke */ + static void -l3dss1_parse_facility(struct l3_process *pc, u_char *p) +l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, + int cr, u_char * p) { int qd_len = 0; - char tmp[32]; + unsigned char nlen = 0, ilen, cp_tag; + int ident, id; + ulong err_ret; + + if (pc) + st = pc->st; /* valid Stack */ + else + if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ p++; qd_len = *p++; if (qd_len == 0) { - l3_debug(pc->st, "qd_len == 0"); + l3_debug(st, "qd_len == 0"); return; } - if((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ - l3_debug(pc->st, "supplementary service != 0x11"); + if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ + l3_debug(st, "supplementary service != 0x11"); return; } - while(qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; qd_len--; - } - if(qd_len < 2) { - l3_debug(pc->st, "qd_len < 2"); - return; + while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ + p++; + qd_len--; } - p++; qd_len--; - if((*p & 0xE0) != 0xA0) { /* class and form */ - l3_debug(pc->st, "class and form != 0xA0"); + if (qd_len < 2) { + l3_debug(st, "qd_len < 2"); return; } - switch(*p & 0x1F) { /* component tag */ - case 1: /* invoke */ - { - unsigned char nlen, ilen; - int ident; - - p++; qd_len--; - if(qd_len < 1) { - l3_debug(pc->st, "qd_len < 1"); - break; - } - if(*p & 0x80) { /* length format */ - l3_debug(pc->st, "*p & 0x80 length format"); - break; - } - nlen = *p++; qd_len--; - if(qd_len < nlen) { - l3_debug(pc->st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if(nlen < 2) { - l3_debug(pc->st, "nlen < 2"); - return; - } - if(*p != 0x02) { /* invoke identifier tag */ - l3_debug(pc->st, "invoke identifier tag !=0x02"); - return; - } - p++; nlen--; - if(*p & 0x80) { /* length format */ - l3_debug(pc->st, "*p & 0x80 length format 2"); - break; - } - ilen = *p++; nlen--; - if(ilen > nlen || ilen == 0) { - l3_debug(pc->st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - ident = 0; - while(ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - if(nlen < 2) { - l3_debug(pc->st, "nlen < 2 22"); - return; - } - if(*p != 0x02) { /* operation value */ - l3_debug(pc->st, "operation value !=0x02"); - return; - } - p++; nlen--; - ilen = *p++; nlen--; - if(ilen > nlen || ilen == 0) { - l3_debug(pc->st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while(ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - #define FOO1(s,a,b) \ + p++; + qd_len--; + if ((*p & 0xE0) != 0xA0) { /* class and form */ + l3_debug(st, "class and form != 0xA0"); + return; + } + + cp_tag = *p & 0x1F; /* remember tag value */ + + p++; + qd_len--; + if (qd_len < 1) + { l3_debug(st, "qd_len < 1"); + return; + } + if (*p & 0x80) + { /* length format indefinite or limited */ + nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ + if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || + (nlen > 1)) + { l3_debug(st, "length format error or not implemented"); + return; + } + if (nlen == 1) + { nlen = *p++; /* complete length */ + qd_len--; + } + else + { qd_len -= 2; /* trailing null bytes */ + if ((*(p+qd_len)) || (*(p+qd_len+1))) + { l3_debug(st,"length format indefinite error"); + return; + } + nlen = qd_len; + } + } + else + { nlen = *p++; + qd_len--; + } + if (qd_len < nlen) + { l3_debug(st, "qd_len < nlen"); + return; + } + qd_len -= nlen; + + if (nlen < 2) + { l3_debug(st, "nlen < 2"); + return; + } + if (*p != 0x02) + { /* invoke identifier tag */ + l3_debug(st, "invoke identifier tag !=0x02"); + return; + } + p++; + nlen--; + if (*p & 0x80) + { /* length format */ + l3_debug(st, "invoke id length format 2"); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + id = 0; + while (ilen > 0) + { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ + ilen--; + } + + switch (cp_tag) { /* component tag */ + case 1: /* invoke */ + if (nlen < 2) { + l3_debug(st, "nlen < 2 22"); + return; + } + if (*p != 0x02) { /* operation value */ + l3_debug(st, "operation value !=0x02"); + return; + } + p++; + nlen--; + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) { + l3_debug(st, "ilen > nlen || ilen == 0 22"); + return; + } + nlen -= ilen; + ident = 0; + while (ilen > 0) { + ident = (ident << 8) | (*p++ & 0xFF); + ilen--; + } + + if (!pc) + { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen); + return; + } +#if HISAX_DE_AOC + { + +#define FOO1(s,a,b) \ while(nlen > 1) { \ int ilen = p[1]; \ if(nlen < ilen+2) { \ - l3_debug(pc->st, "FOO1 nlen < ilen+2"); \ + l3_debug(st, "FOO1 nlen < ilen+2"); \ return; \ } \ nlen -= ilen+2; \ @@ -174,305 +432,824 @@ p += ilen+2; \ } \ } - - switch(ident) { - default: - break; - case 0x22: /* during */ - FOO1("1A",0x30,FOO1("1C",0xA1,FOO1("1D",0x30,FOO1("1E",0x02,({ - ident = 0; - while(ilen > 0) { - ident = (ident<<8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - if (*(p+2) == 0) { - sprintf(tmp, "charging info during %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - else { - sprintf(tmp, "charging info final %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - } - }))))) - break; - case 0x24: /* final */ - FOO1("2A",0x30,FOO1("2B",0x30,FOO1("2C",0xA1,FOO1("2D",0x30,FOO1("2E",0x02,({ - ident = 0; - while(ilen > 0) { - ident = (ident<<8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - sprintf(tmp, "charging info final %d", pc->para.chargeinfo); - l3_debug(pc->st, tmp); - } - })))))) - break; - } - #undef FOO1 - + + switch (ident) { + case 0x22: /* during */ + FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( { + ident = 0; + nlen = (nlen)?nlen:0; /* Make gcc happy */ + while (ilen > 0) { + ident = (ident << 8) | *p++; + ilen--; + } + if (ident > pc->para.chargeinfo) { + pc->para.chargeinfo = ident; + st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); + } + if (st->l3.debug & L3_DEB_CHARGE) { + if (*(p + 2) == 0) { + l3_debug(st, "charging info during %d", pc->para.chargeinfo); + } + else { + l3_debug(st, "charging info final %d", pc->para.chargeinfo); + } + } + } + ))))) + break; + case 0x24: /* final */ + FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( { + ident = 0; + nlen = (nlen)?nlen:0; /* Make gcc happy */ + while (ilen > 0) { + ident = (ident << 8) | *p++; + ilen--; + } + if (ident > pc->para.chargeinfo) { + pc->para.chargeinfo = ident; + st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); + } + if (st->l3.debug & L3_DEB_CHARGE) { + l3_debug(st, "charging info final %d", pc->para.chargeinfo); + } + } + )))))) + break; + default: + l3_debug(st, "invoke break invalid ident %02x",ident); + break; + } +#undef FOO1 + + } +#else not HISAX_DE_AOC + l3_debug(st, "invoke break"); +#endif not HISAX_DE_AOC + break; + case 2: /* return result */ + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3dss1_dummy_return_result(st, id, p, nlen); + return; + } + if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) + { /* Diversion successfull */ + free_invoke_id(st,pc->prot.dss1.invoke_id); + pc->prot.dss1.remote_result = 0; /* success */ + pc->prot.dss1.invoke_id = 0; + pc->redir_result = pc->prot.dss1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + else + l3_debug(st,"return error unknown identifier"); + break; + case 3: /* return error */ + err_ret = 0; + if (nlen < 2) + { l3_debug(st, "return error nlen < 2"); + return; + } + if (*p != 0x02) + { /* result tag */ + l3_debug(st, "invoke error tag !=0x02"); + return; + } + p++; + nlen--; + if (*p > 4) + { /* length format */ + l3_debug(st, "invoke return errlen > 4 "); + return; + } + ilen = *p++; + nlen--; + if (ilen > nlen || ilen == 0) + { l3_debug(st, "error return ilen > nlen || ilen == 0"); + return; + } + nlen -= ilen; + while (ilen > 0) + { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ + ilen--; + } + /* if no process available handle separately */ + if (!pc) + { if (cr == -1) + l3dss1_dummy_error_return(st, id, err_ret); + return; + } + if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) + { /* Deflection error */ + free_invoke_id(st,pc->prot.dss1.invoke_id); + pc->prot.dss1.remote_result = err_ret; /* result */ + pc->prot.dss1.invoke_id = 0; + pc->redir_result = pc->prot.dss1.remote_result; + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); + } /* Deflection error */ + else + l3_debug(st,"return result unknown identifier"); + break; + default: + l3_debug(st, "facility default break tag=0x%02x",cp_tag); + break; + } +} + +static void +l3dss1_message(struct l3_process *pc, u_char mt) +{ + struct sk_buff *skb; + u_char *p; + + if (!(skb = l3_alloc_skb(4))) + return; + p = skb_put(skb, 4); + MsgHead(p, pc->callref, mt); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause) +{ + struct sk_buff *skb; + u_char tmp[16]; + u_char *p = tmp; + int l; + + MsgHead(p, pc->callref, mt); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = cause | 0x80; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg) +{ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + MsgHead(p, pc->callref, MT_STATUS); + + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + + *p++ = IE_CALL_STATE; + *p++ = 0x1; + *p++ = pc->state & 0x3f; + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) +{ + /* This routine is called if here was no SETUP made (checks in dss1up and in + * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code + * MT_STATUS_ENQUIRE in the NULL state is handled too + */ + u_char tmp[16]; + u_char *p = tmp; + int l; + struct sk_buff *skb; + + switch (pc->para.cause) { + case 81: /* invalid callreference */ + case 88: /* incomp destination */ + case 96: /* mandory IE missing */ + case 100: /* invalid IE contents */ + case 101: /* incompatible Callstate */ + MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = pc->para.cause | 0x80; + break; + default: + printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n", + pc->para.cause); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + dss1_release_l3_process(pc); +} + +static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, + IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_CONNECT_PN, + IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; +static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, -1}; +static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, IE_USER_USER, -1}; +/* not used + * static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, + * IE_CALLED_PN, -1}; + */ +static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | + IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; +static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_USER_USER, -1}; +/* a RELEASE_COMPLETE with errors don't require special actions +static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_USER_USER, -1}; +*/ +static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, + IE_DISPLAY, -1}; +static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, + IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, + IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_CALLING_PN, + IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_LLC, IE_USER_USER, -1}; +static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, + IE_PROGRESS, IE_DISPLAY, -1}; +static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | + IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; +static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; +static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used + * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, + * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; + * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; + * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | + * IE_MANDATORY, -1}; + */ +static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; +static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; +static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; + +struct ie_len { + int ie; + int len; +}; + +static +struct ie_len max_ie_len[] = { + {IE_SEGMENT, 4}, + {IE_BEARER, 12}, + {IE_CAUSE, 32}, + {IE_CALL_ID, 10}, + {IE_CALL_STATE, 3}, + {IE_CHANNEL_ID, 34}, + {IE_FACILITY, 255}, + {IE_PROGRESS, 4}, + {IE_NET_FAC, 255}, + {IE_NOTIFY, 3}, + {IE_DISPLAY, 82}, + {IE_DATE, 8}, + {IE_KEYPAD, 34}, + {IE_SIGNAL, 3}, + {IE_INFORATE, 6}, + {IE_E2E_TDELAY, 11}, + {IE_TDELAY_SEL, 5}, + {IE_PACK_BINPARA, 3}, + {IE_PACK_WINSIZE, 4}, + {IE_PACK_SIZE, 4}, + {IE_CUG, 7}, + {IE_REV_CHARGE, 3}, + {IE_CALLING_PN, 24}, + {IE_CALLING_SUB, 23}, + {IE_CALLED_PN, 24}, + {IE_CALLED_SUB, 23}, + {IE_REDIR_NR, 255}, + {IE_TRANS_SEL, 255}, + {IE_RESTART_IND, 3}, + {IE_LLC, 18}, + {IE_HLC, 5}, + {IE_USER_USER, 131}, + {-1,0}, +}; + +static int +getmax_ie_len(u_char ie) { + int i = 0; + while (max_ie_len[i].ie != -1) { + if (max_ie_len[i].ie == ie) + return(max_ie_len[i].len); + i++; + } + return(255); +} + +static int +ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { + int ret = 1; + + while (*checklist != -1) { +#if 0 + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "ie_in_set ie(%x) cl(%x)", + ie, *checklist); +#endif + if ((*checklist & 0xff) == ie) { + if (ie & 0x80) + return(-ret); + else + return(ret); + } + ret++; + checklist++; + } + return(0); +} + +static int +check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) +{ + int *cl = checklist; + u_char mt; + u_char *p, ie; + int l, newpos, oldpos; + int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; + + p = skb->data; + /* skip cr */ + p++; + l = (*p++) & 0xf; + p += l; + mt = *p++; + oldpos = 0; +/* shift codeset procedure not implemented in the moment */ + while ((p - skb->data) < skb->len) { + if ((newpos = ie_in_set(pc, *p, cl))) { + if (newpos > 0) { + if (newpos < oldpos) + err_seq++; + else + oldpos = newpos; + } + } else { + if (ie_in_set(pc, *p, comp_required)) + err_compr++; + else + err_ureg++; } - break; - case 2: /* return result */ - l3_debug(pc->st, "return result break"); - break; - case 3: /* return error */ - l3_debug(pc->st, "return error break"); - break; - default: - l3_debug(pc->st, "default break"); - break; - } -} -#endif - -static int -l3dss1_check_messagetype_validity(int mt) { -/* verify if a message type exists */ - switch(mt) { + ie = *p++; + if (newpos >= 0) { + l = *p++; + p += l; + l += 2; + } else + l = 1; + if (l > getmax_ie_len(ie)) + err_len++; + } + if (err_compr | err_ureg | err_len | err_seq) { + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d", + mt, err_compr, err_ureg, err_len, err_seq); + if (err_compr) + return(ERR_IE_COMPREHENSION); + if (err_ureg) + return(ERR_IE_UNRECOGNIZED); + if (err_len) + return(ERR_IE_LENGTH); + if (err_seq) + return(ERR_IE_SEQUENCE); + } + return(0); +} + +/* verify if a message type exists and contain no IE error */ +static int +l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) +{ + switch (mt) { case MT_ALERTING: case MT_CALL_PROCEEDING: case MT_CONNECT: case MT_CONNECT_ACKNOWLEDGE: + case MT_DISCONNECT: + case MT_INFORMATION: + case MT_FACILITY: + case MT_NOTIFY: case MT_PROGRESS: + case MT_RELEASE: + case MT_RELEASE_COMPLETE: case MT_SETUP: case MT_SETUP_ACKNOWLEDGE: - case MT_RESUME: case MT_RESUME_ACKNOWLEDGE: case MT_RESUME_REJECT: - case MT_SUSPEND: case MT_SUSPEND_ACKNOWLEDGE: case MT_SUSPEND_REJECT: case MT_USER_INFORMATION: - case MT_DISCONNECT: - case MT_RELEASE: - case MT_RELEASE_COMPLETE: case MT_RESTART: case MT_RESTART_ACKNOWLEDGE: - case MT_SEGMENT: case MT_CONGESTION_CONTROL: - case MT_INFORMATION: - case MT_FACILITY: - case MT_NOTIFY: case MT_STATUS: case MT_STATUS_ENQUIRY: + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt); + break; + case MT_RESUME: /* RESUME only in user->net */ + case MT_SUSPEND: /* SUSPEND only in user->net */ + default: + if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) + l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt); + pc->para.cause = 97; + l3dss1_status_send(pc, 0, NULL); return(1); + } + return(0); +} + +static void +l3dss1_std_ie_err(struct l3_process *pc, int ret) { + + if (pc->debug & L3_DEB_CHECK) + l3_debug(pc->st, "check_infoelements ret %d", ret); + switch(ret) { + case 0: + break; + case ERR_IE_COMPREHENSION: + pc->para.cause = 96; + l3dss1_status_send(pc, 0, NULL); + break; + case ERR_IE_UNRECOGNIZED: + pc->para.cause = 99; + l3dss1_status_send(pc, 0, NULL); + break; + case ERR_IE_LENGTH: + pc->para.cause = 100; + l3dss1_status_send(pc, 0, NULL); + break; + case ERR_IE_SEQUENCE: default: - return(0); + break; } +} + +static int +l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { + u_char *p; + + p = skb->data; + if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { + p++; + if (*p != 1) { /* len for BRI = 1 */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid len %d", *p); + return (-2); + } + p++; + if (*p & 0x60) { /* only base rate interface */ + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "wrong chid %x", *p); + return (-3); + } + return(*p & 0x3); + } else + return(-1); +} + +static int +l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) { + u_char l, i=0; + u_char *p; + + p = skb->data; + pc->para.cause = 31; + pc->para.loc = 0; + if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + p++; + l = *p++; + if (l>30) + return(1); + if (l) { + pc->para.loc = *p++; + l--; + } else { + return(2); + } + if (l && !(pc->para.loc & 0x80)) { + l--; + p++; /* skip recommendation */ + } + if (l) { + pc->para.cause = *p++; + l--; + if (!(pc->para.cause & 0x80)) + return(3); + } else + return(4); + while (l && (i<6)) { + pc->para.diag[i++] = *p++; + l--; + } + } else + return(-1); return(0); } static void -l3dss1_message(struct l3_process *pc, u_char mt) +l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd) { struct sk_buff *skb; - u_char *p; + u_char tmp[16+40]; + u_char *p = tmp; + int l; - if (!(skb = l3_alloc_skb(4))) + MsgHead(p, pc->callref, cmd); + + if (pc->prot.dss1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.dss1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.dss1.uus1_data); + p += strlen(pc->prot.dss1.uus1_data); + pc->prot.dss1.uus1_data[0] = '\0'; + } + + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); -} + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3dss1_msg_with_uus */ static void l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg) { StopAllL3Timer(pc); newl3state(pc, 19); - l3dss1_message(pc, MT_RELEASE); + if (!pc->prot.dss1.uus1_data[0]) + l3dss1_message(pc, MT_RELEASE); + else + l3dss1_msg_with_uus(pc, MT_RELEASE); L3AddTimer(&pc->timer, T308, CC_T308_1); } -static void -l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int cause = -1; +static void +l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3dss1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); + } else if (ret < 0) + pc->para.cause = NO_CAUSE; + StopAllL3Timer(pc); + newl3state(pc, 0); + pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); + dss1_release_l3_process(pc); +} + +#if EXT_BEARER_CAPS + +u_char * +EncodeASyncParams(u_char * p, u_char si2) +{ // 7c 06 88 90 21 42 00 bb + + p[0] = p[1] = 0; + p[2] = 0x80; + if (si2 & 32) // 7 data bits + + p[2] += 16; + else // 8 data bits + + p[2] += 24; + + if (si2 & 16) // 2 stop bits + + p[2] += 96; + else // 1 stop bit + + p[2] = 32; + + if (si2 & 8) // even parity + + p[2] += 2; + else // no parity + + p[2] += 3; + + switch (si2 & 0x07) { + case 0: + p[0] = 66; // 1200 bit/s + + break; + case 1: + p[0] = 88; // 1200/75 bit/s + + break; + case 2: + p[0] = 87; // 75/1200 bit/s + + break; + case 3: + p[0] = 67; // 2400 bit/s + + break; + case 4: + p[0] = 69; // 4800 bit/s + + break; + case 5: + p[0] = 72; // 9600 bit/s + + break; + case 6: + p[0] = 73; // 14400 bit/s + + break; + case 7: + p[0] = 75; // 19200 bit/s + + break; + } + return p + 3; +} + +u_char +EncodeSyncParams(u_char si2, u_char ai) +{ + + switch (si2) { + case 0: + return ai + 2; // 1200 bit/s + + case 1: + return ai + 24; // 1200/75 bit/s + + case 2: + return ai + 23; // 75/1200 bit/s + + case 3: + return ai + 3; // 2400 bit/s + + case 4: + return ai + 5; // 4800 bit/s + + case 5: + return ai + 8; // 9600 bit/s + + case 6: + return ai + 9; // 14400 bit/s + + case 7: + return ai + 11; // 19200 bit/s + + case 8: + return ai + 14; // 48000 bit/s + + case 9: + return ai + 15; // 56000 bit/s + + case 15: + return ai + 40; // negotiate bit/s + + default: + break; + } + return ai; +} + + +static u_char +DecodeASyncParams(u_char si2, u_char * p) +{ + u_char info; + + switch (p[5]) { + case 66: // 1200 bit/s + + break; // si2 don't change + + case 88: // 1200/75 bit/s + + si2 += 1; + break; + case 87: // 75/1200 bit/s + + si2 += 2; + break; + case 67: // 2400 bit/s + + si2 += 3; + break; + case 69: // 4800 bit/s + + si2 += 4; + break; + case 72: // 9600 bit/s + + si2 += 5; + break; + case 73: // 14400 bit/s + + si2 += 6; + break; + case 75: // 19200 bit/s + + si2 += 7; + break; + } + + info = p[7] & 0x7f; + if ((info & 16) && (!(info & 8))) // 7 data bits + + si2 += 32; // else 8 data bits + + if ((info & 96) == 96) // 2 stop bits + + si2 += 16; // else 1 stop bit + + if ((info & 2) && (!(info & 1))) // even parity + + si2 += 8; // else no parity + + return si2; +} + + +static u_char +DecodeSyncParams(u_char si2, u_char info) +{ + info &= 0x7f; + switch (info) { + case 40: // bit/s negotiation failed ai := 165 not 175! + + return si2 + 15; + case 15: // 56000 bit/s failed, ai := 0 not 169 ! + + return si2 + 9; + case 14: // 48000 bit/s + + return si2 + 8; + case 11: // 19200 bit/s + + return si2 + 7; + case 9: // 14400 bit/s + + return si2 + 6; + case 8: // 9600 bit/s + + return si2 + 5; + case 5: // 4800 bit/s + + return si2 + 4; + case 3: // 2400 bit/s + + return si2 + 3; + case 23: // 75/1200 bit/s + + return si2 + 2; + case 24: // 1200/75 bit/s + + return si2 + 1; + default: // 1200 bit/s - p = skb->data; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - if (*p++ == 2) - pc->para.loc = *p++; - cause = *p & 0x7f; + return si2; } - dev_kfree_skb(skb); - StopAllL3Timer(pc); - pc->para.cause = cause; - newl3state(pc, 0); - pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL); - release_l3_process(pc); } -#ifdef EXT_BEARER_CAPS +static u_char +DecodeSI2(struct sk_buff *skb) +{ + u_char *p; //, *pend=skb->data + skb->len; -u_char *EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb + if ((p = findie(skb->data, skb->len, 0x7c, 0))) { + switch (p[4] & 0x0f) { + case 0x01: + if (p[1] == 0x04) // sync. Bitratenadaption - p[0] = p[1] = 0; p[2] = 0x80; - if (si2 & 32) // 7 data bits - p[2] += 16; - else // 8 data bits - p[2] +=24; - - if (si2 & 16) // 2 stop bits - p[2] += 96; - else // 1 stop bit - p[2] = 32; - - if (si2 & 8) // even parity - p[2] += 2; - else // no parity - p[2] += 3; - - switch (si2 & 0x07) - { - case 0: p[0] = 66; // 1200 bit/s - break; - case 1: p[0] = 88; // 1200/75 bit/s - break; - case 2: p[0] = 87; // 75/1200 bit/s - break; - case 3: p[0] = 67; // 2400 bit/s - break; - case 4: p[0] = 69; // 4800 bit/s - break; - case 5: p[0] = 72; // 9600 bit/s - break; - case 6: p[0] = 73; // 14400 bit/s - break; - case 7: p[0] = 75; // 19200 bit/s - break; - } - return p+3; -} - -u_char EncodeSyncParams(u_char si2, u_char ai) -{ - - switch (si2) - { - case 0: return ai + 2; // 1200 bit/s - case 1: return ai + 24; // 1200/75 bit/s - case 2: return ai + 23; // 75/1200 bit/s - case 3: return ai + 3; // 2400 bit/s - case 4: return ai + 5; // 4800 bit/s - case 5: return ai + 8; // 9600 bit/s - case 6: return ai + 9; // 14400 bit/s - case 7: return ai + 11; // 19200 bit/s - case 8: return ai + 14; // 48000 bit/s - case 9: return ai + 15; // 56000 bit/s - case 15: return ai + 40; // negotiate bit/s - default: break; - } - return ai; -} - - -static u_char DecodeASyncParams(u_char si2, u_char *p) -{ u_char info; - - switch (p[5]) - { - case 66: // 1200 bit/s - break; // si2 bleibt gleich - case 88: // 1200/75 bit/s - si2 += 1; - break; - case 87: // 75/1200 bit/s - si2 += 2; - break; - case 67: // 2400 bit/s - si2 += 3; - break; - case 69: // 4800 bit/s - si2 += 4; - break; - case 72: // 9600 bit/s - si2 += 5; - break; - case 73: // 14400 bit/s - si2 += 6; - break; - case 75: // 19200 bit/s - si2 += 7; - break; - } - - info = p[7] & 0x7f; - if ((info & 16) && (!(info & 8))) // 7 data bits - si2 += 32; // else 8 data bits - if ((info & 96) == 96) // 2 stop bits - si2 += 16; // else 1 stop bit - if ((info & 2) && (!(info & 1))) // even parity - si2 += 8; // else no parity - - return si2; -} - - -static u_char DecodeSyncParams(u_char si2, u_char info) -{ - info &= 0x7f; - switch (info) - { - case 40: // bit/s aushandeln --- hat nicht geklappt, ai wird 165 statt 175! - return si2 + 15; - case 15: // 56000 bit/s --- hat nicht geklappt, ai wird 0 statt 169 ! - return si2 + 9; - case 14: // 48000 bit/s - return si2 + 8; - case 11: // 19200 bit/s - return si2 + 7; - case 9: // 14400 bit/s - return si2 + 6; - case 8: // 9600 bit/s - return si2 + 5; - case 5: // 4800 bit/s - return si2 + 4; - case 3: // 2400 bit/s - return si2 + 3; - case 23: // 75/1200 bit/s - return si2 + 2; - case 24: // 1200/75 bit/s - return si2 + 1; - default: // 1200 bit/s - return si2; - } -} - -static u_char DecodeSI2(struct sk_buff *skb) -{ u_char *p; //, *pend=skb->data + skb->len; - - if ((p = findie(skb->data, skb->len, 0x7c, 0))) - { - switch (p[4] & 0x0f) - { - case 0x01: if (p[1] == 0x04) // sync. Bitratenadaption - return DecodeSyncParams(160, p[5]); // V.110/X.30 - else if (p[1] == 0x06) // async. Bitratenadaption - return DecodeASyncParams(192, p); // V.110/X.30 - break; - case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; + return DecodeSyncParams(160, p[5]); // V.110/X.30 + + else if (p[1] == 0x06) // async. Bitratenadaption + + return DecodeASyncParams(192, p); // V.110/X.30 + + break; + case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption + + return DecodeSyncParams(176, p[5]); // V.120 + + break; + } + } + return 0; } #endif @@ -486,6 +1263,7 @@ u_char tmp[128]; u_char *p = tmp; u_char channel = 0; + u_char send_keypad; u_char screen = 0x80; u_char *teln; u_char *msn; @@ -495,13 +1273,17 @@ MsgHead(p, pc->callref, MT_SETUP); + teln = pc->para.setup.phone; + send_keypad = (strchr(teln,'*') || strchr(teln,'#')) ? 1 : 0; /* * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 */ -#ifdef HISAX_EURO_SENDCOMPLETE - *p++ = 0xa1; /* complete indicator */ +#if HISAX_EURO_SENDCOMPLETE + if (!send_keypad) + *p++ = 0xa1; /* complete indicator */ #endif - switch (pc->para.setup.si1) { + if (!send_keypad) + switch (pc->para.setup.si1) { case 1: /* Telephony */ *p++ = 0x4; /* BC-IE-code */ *p++ = 0x3; /* Length */ @@ -517,12 +1299,26 @@ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ *p++ = 0x90; /* Circuit-Mode 64kbps */ break; - } + } + else { *p++ = 0x4; /* assumptions for bearer services with keypad */ + *p++ = 0x3; + *p++ = 0x80; + *p++ = 0x90; + *p++ = 0xa3; + *p++ = 0x18; /* no specific channel */ + *p++ = 0x01; + *p++ = 0x83; + *p++ = 0x2C; /* IE keypad */ + *p++ = strlen(teln); + while (*teln) + *p++ = (*teln++) & 0x7F; + } + + /* * What about info2? Mapping to High-Layer-Compatibility? */ - teln = pc->para.setup.phone; - if (*teln) { + if ((*teln) && (!send_keypad)) { /* parse number for special things */ if (!isdigit(*teln)) { switch (0x5f & *teln) { @@ -542,7 +1338,8 @@ case 'D': screen = 0x80; break; - default: + + default: if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "Wrong MSN Code"); break; @@ -558,11 +1355,11 @@ msn = pc->para.setup.eazmsn; sub = NULL; sp = msn; - while (*sp) { + while (*sp) { if ('.' == *sp) { sub = sp; *sp = 0; - } else + } else sp++; } if (*msn) { @@ -579,56 +1376,81 @@ } if (sub) { *sub++ = '.'; - *p++ = 0x6d; /* Calling party subaddress */ - *p++ = strlen(sub) + 2; + *p++ = 0x6d; /* Calling party subaddress */ + *p++ = strlen(sub) + 2; *p++ = 0x80; /* NSAP coded */ *p++ = 0x50; /* local IDI format */ - while (*sub) + while (*sub) *p++ = *sub++ & 0x7f; } sub = NULL; sp = teln; - while (*sp) { + while (*sp) { if ('.' == *sp) { sub = sp; *sp = 0; - } else + } else sp++; } - *p++ = 0x70; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - if (sub) { - *sub++ = '.'; - *p++ = 0x71; /* Called party subaddress */ - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } - -#ifdef EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) - { // sync. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; *p++ = 0x04; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); - } - else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) - { // sync. Bitratenadaption, V.120 - *p++ = 0x7c; *p++ = 0x05; *p++ = 0x88; *p++ = 0x90; *p++ = 0x28; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); - *p++ = 0x82; - } - else if (pc->para.setup.si2 >= 192) - { // async. Bitratenadaption, V.110/X.30 - *p++ = 0x7c; *p++ = 0x06; *p++ = 0x88; *p++ = 0x90; *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); + + if (!send_keypad) { + *p++ = 0x70; + *p++ = strlen(teln) + 1; + /* Classify as AnyPref. */ + *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ + while (*teln) + *p++ = *teln++ & 0x7f; + + if (sub) { + *sub++ = '.'; + *p++ = 0x71; /* Called party subaddress */ + *p++ = strlen(sub) + 2; + *p++ = 0x80; /* NSAP coded */ + *p++ = 0x50; /* local IDI format */ + while (*sub) + *p++ = *sub++ & 0x7f; + } } +#if EXT_BEARER_CAPS + if (send_keypad) { /* special handling independant of si2 */ + *p++ = 0x7c; + *p++ = 0x03; + *p++ = 0x80; + *p++ = 0x90; + *p++ = 0xa3; + } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 + + *p++ = 0x7c; + *p++ = 0x04; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); + } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 + + *p++ = 0x7c; + *p++ = 0x05; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x28; + *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); + *p++ = 0x82; + } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 + + *p++ = 0x7c; + *p++ = 0x06; + *p++ = 0x88; + *p++ = 0x90; + *p++ = 0x21; + p = EncodeASyncParams(p, pc->para.setup.si2 - 192); +#if HISAX_SEND_STD_LLC_IE + } else { + *p++ = 0x7c; + *p++ = 0x02; + *p++ = 0x88; + *p++ = 0x90; +#endif + } #endif l = p - tmp; if (!(skb = l3_alloc_skb(l))) @@ -637,227 +1459,276 @@ L3DelTimer(&pc->timer); L3AddTimer(&pc->timer, T303, CC_T303); newl3state(pc, 1); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); } static void l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; struct sk_buff *skb = arg; + int id, ret; + if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3dss1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer without chid (ret %d)", id); + pc->para.cause = 96; + l3dss1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - pc->para.bchannel = p[2] & 0x3; - if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN)) - l3_debug(pc->st, "setup answer without bchannel"); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); - dev_kfree_skb(skb); newl3state(pc, 3); L3AddTimer(&pc->timer, T310, CC_T310); - pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); } static void l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; struct sk_buff *skb = arg; + int id, ret; + if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer with wrong chid %x", id); + pc->para.cause = 100; + l3dss1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup answer without chid (ret %d)", id); + pc->para.cause = 96; + l3dss1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - pc->para.bchannel = p[2] & 0x3; - if ((!pc->para.bchannel) && (pc->debug & L3_DEB_WARN)) - l3_debug(pc->st, "setup answer without bchannel"); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer without bchannel"); - dev_kfree_skb(skb); newl3state(pc, 2); L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); } static void l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; struct sk_buff *skb = arg; - int cause = -1; + u_char *p; + int ret; + u_char cause = 0; StopAllL3Timer(pc); - p = skb->data; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - if (*p++ == 2) - pc->para.loc = *p++; - cause = *p & 0x7f; - } - dev_kfree_skb(skb); + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "DISC get_cause ret(%d)", ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3dss1_parse_facility(pc->st, pc, pc->callref, p); + ret = check_infoelements(pc, skb, ie_DISCONNECT); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) + cause = 99; + ret = pc->state; newl3state(pc, 12); - pc->para.cause = cause; - pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL); + if (cause) + newl3state(pc, 19); + if (11 != ret) + pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); + else if (!cause) + l3dss1_release_req(pc, pr, NULL); + if (cause) { + l3dss1_message_cause(pc, MT_RELEASE, cause); + L3AddTimer(&pc->timer, T308, CC_T308_1); + } } static void l3dss1_connect(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; + int ret; - dev_kfree_skb(skb); + ret = check_infoelements(pc, skb, ie_CONNECT); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } L3DelTimer(&pc->timer); /* T310 */ newl3state(pc, 10); pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL); + /* here should inserted COLP handling KKe */ + if (ret) + l3dss1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); } static void l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; + int ret; - dev_kfree_skb(skb); + ret = check_infoelements(pc, skb, ie_ALERTING); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } L3DelTimer(&pc->timer); /* T304 */ newl3state(pc, 4); - pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL); -} - -static void -l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) -{ - /* This routine is called if here was no SETUP made (checks in dss1up and in - * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * It is called after it is veryfied that Layer2 is up. - * The cause value is allready in pc->para.cause - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ - u_char tmp[16]; - u_char *p=tmp; - int l; - struct sk_buff *skb; - - switch (pc->para.cause) { - case 81: /* 0x51 invalid callreference */ - case 96: /* 0x60 mandory IE missing */ - case 101: /* 0x65 incompatible Callstate */ - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - break; - default: - printk(KERN_ERR "HiSax internal error l3dss1_msg_without_setup\n"); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); - release_l3_process(pc); + if (ret) + l3dss1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); } static void l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) { - u_char *p, *ptmp[8]; - int i; + u_char *p; int bcfound = 0; char tmp[80]; struct sk_buff *skb = arg; - - /* ETS 300-104 1.3.4 and 1.3.5 - * we need to detect unknown inform. element from 0 to 7 - */ - p = skb->data; - for(i = 0; i < 8; i++) - ptmp[i] = skb->data; - if (findie(ptmp[1], skb->len, 0x01, 0) - || findie(ptmp[2], skb->len, 0x02, 0) - || findie(ptmp[3], skb->len, 0x03, 0) - || findie(ptmp[5], skb->len, 0x05, 0) - || findie(ptmp[6], skb->len, 0x06, 0) - || findie(ptmp[7], skb->len, 0x07, 0)) { - /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE - * cause 0x60 - */ - pc->para.cause = 0x60; - dev_kfree_skb(skb); - if (pc->state == 0) - pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL); - else - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - - /* - * Channel Identification - */ - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - pc->para.bchannel = p[2] & 0x3; - if (pc->para.bchannel) - bcfound++; - else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel"); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel"); + int id; + int err = 0; /* - * Bearer Capabilities + * Bearer Capabilities */ p = skb->data; + /* only the first occurence 'll be detected ! */ if ((p = findie(p, skb->len, 0x04, 0))) { - pc->para.setup.si2 = 0; - switch (p[2] & 0x1f) { - case 0x00: - /* Speech */ - case 0x10: - /* 3.1 Khz audio */ - pc->para.setup.si1 = 1; - break; - case 0x08: - /* Unrestricted digital information */ - pc->para.setup.si1 = 7; + if ((p[1] < 2) || (p[1] > 11)) + err = 1; + else { + pc->para.setup.si2 = 0; + switch (p[2] & 0x7f) { + case 0x00: /* Speech */ + case 0x10: /* 3.1 Khz audio */ + pc->para.setup.si1 = 1; + break; + case 0x08: /* Unrestricted digital information */ + pc->para.setup.si1 = 7; /* JIM, 05.11.97 I wanna set service indicator 2 */ -#ifdef EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); - printk(KERN_DEBUG "HiSax: SI=%d, AI=%d\n", - pc->para.setup.si1, pc->para.setup.si2); +#if EXT_BEARER_CAPS + pc->para.setup.si2 = DecodeSI2(skb); + if (pc->debug & L3_DEB_SI) + l3_debug(pc->st, "SI=%d, AI=%d", + pc->para.setup.si1, + pc->para.setup.si2); #endif - break; - case 0x09: - /* Restricted digital information */ - pc->para.setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with tones/announcements */ - pc->para.setup.si1 = 3; - break; - case 0x18: - /* Video */ - pc->para.setup.si1 = 4; - break; - default: - pc->para.setup.si1 = 0; + break; + case 0x09: /* Restricted digital information */ + pc->para.setup.si1 = 2; + break; + case 0x11: + /* Unrestr. digital information with + * tones/announcements ( or 7 kHz audio + */ + pc->para.setup.si1 = 3; + break; + case 0x18: /* Video */ + pc->para.setup.si1 = 4; + break; + default: + err = 2; + break; + } + switch (p[3] & 0x7f) { + case 0x40: /* packed mode */ + break; + case 0x10: /* 64 kbit */ + case 0x11: /* 2*64 kbit */ + case 0x13: /* 384 kbit */ + case 0x15: /* 1536 kbit */ + case 0x17: /* 1920 kbit */ + pc->para.moderate = p[3] & 0x7f; + break; + default: + err = 3; + break; + } + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", + p[1], p[2], p[3]); + pc->para.cause = 100; + l3dss1_msg_without_setup(pc, pr, NULL); + return; } } else { if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "setup without bearer capabilities"); /* ETS 300-104 1.3.3 */ - pc->para.cause = 0x60; - dev_kfree_skb(skb); - if (pc->state == 0) - pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL); - else - l3dss1_msg_without_setup(pc, pr, NULL); + pc->para.cause = 96; + l3dss1_msg_without_setup(pc, pr, NULL); return; } - + /* + * Channel Identification + */ + if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { + if ((pc->para.bchannel = id)) { + if ((3 == id) && (0x10 == pc->para.moderate)) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid %x", + id); + pc->para.cause = 100; + l3dss1_msg_without_setup(pc, pr, NULL); + return; + } + bcfound++; + } else + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup without bchannel, call waiting"); + bcfound++; + } + } else { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "setup with wrong chid ret %d", id); + pc->para.cause = 96; + l3dss1_msg_without_setup(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ +#if 1 +/* !!!!!! this check seems to be a problem ? info bugfix to Karsten */ + err = check_infoelements(pc, skb, ie_SETUP); + if (ERR_IE_COMPREHENSION == err) { + pc->para.cause = 96; + l3dss1_msg_without_setup(pc, pr, NULL); + return; + } +#endif p = skb->data; if ((p = findie(p, skb->len, 0x70, 0))) iecpy(pc->para.setup.eazmsn, p, 1); @@ -867,8 +1738,8 @@ p = skb->data; if ((p = findie(p, skb->len, 0x71, 0))) { /* Called party subaddress */ - if ((p[1]>=2) && (p[2]==0x80) && (p[3]==0x50)) { - tmp[0]='.'; + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; iecpy(&tmp[1], p, 2); strcat(pc->para.setup.eazmsn, tmp); } else if (pc->debug & L3_DEB_WARN) @@ -892,65 +1763,54 @@ p = skb->data; if ((p = findie(p, skb->len, 0x6d, 0))) { /* Calling party subaddress */ - if ((p[1]>=2) && (p[2]==0x80) && (p[3]==0x50)) { - tmp[0]='.'; + if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { + tmp[0] = '.'; iecpy(&tmp[1], p, 2); strcat(pc->para.setup.phone, tmp); } else if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "wrong calling subaddress"); } - dev_kfree_skb(skb); - +#if 0 if (bcfound) { if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) { - sprintf(tmp, "non-digital call: %s -> %s", - pc->para.setup.phone, pc->para.setup.eazmsn); - l3_debug(pc->st, tmp); + l3_debug(pc->st, "non-digital call: %s -> %s", + pc->para.setup.phone, pc->para.setup.eazmsn); + } + if ((pc->para.setup.si1 != 7) && + test_bit(FLG_PTP, &pc->st->l2.flag)) { + pc->para.cause = 88; /* incompatible destination */ + l3dss1_msg_without_setup(pc, pr, NULL); + return; } newl3state(pc, 6); - pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); } else - release_l3_process(pc); + dss1_release_l3_process(pc); +#else + newl3state(pc, 6); + if (err) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, err); + pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); +#endif } static void l3dss1_reset(struct l3_process *pc, u_char pr, void *arg) { - release_l3_process(pc); -} - -static void -l3dss1_setup_rsp(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 8); - l3dss1_message(pc, MT_CONNECT); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - newl3state(pc, 10); - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL); + dss1_release_l3_process(pc); } static void l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; - u_char tmp[16]; + u_char tmp[16+40]; u_char *p = tmp; int l; - u_char cause = 0x10; + u_char cause = 16; - if (pc->para.cause > 0) + if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; StopAllL3Timer(pc); @@ -962,25 +1822,68 @@ *p++ = 0x80; *p++ = cause | 0x80; + if (pc->prot.dss1.uus1_data[0]) + { *p++ = IE_USER_USER; /* UUS info element */ + *p++ = strlen(pc->prot.dss1.uus1_data) + 1; + *p++ = 0x04; /* IA5 chars */ + strcpy(p,pc->prot.dss1.uus1_data); + p += strlen(pc->prot.dss1.uus1_data); + pc->prot.dss1.uus1_data[0] = '\0'; + } + l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 11); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T305, CC_T305); } static void +l3dss1_setup_rsp(struct l3_process *pc, u_char pr, + void *arg) +{ + if (!pc->para.bchannel) + { if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "D-chan connect for waiting call"); + l3dss1_disconnect_req(pc, pr, arg); + return; + } + newl3state(pc, 8); + l3dss1_message(pc, MT_CONNECT); + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T313, CC_T313); +} + +static void +l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } + newl3state(pc, 10); + L3DelTimer(&pc->timer); + if (ret) + l3dss1_std_ie_err(pc, ret); + pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); +} + +static void l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) { struct sk_buff *skb; u_char tmp[16]; u_char *p = tmp; int l; - u_char cause = 0x95; + u_char cause = 21; - if (pc->para.cause > 0) + if (pc->para.cause != NO_CAUSE) cause = pc->para.cause; MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); @@ -988,47 +1891,50 @@ *p++ = IE_CAUSE; *p++ = 0x2; *p++ = 0x80; - *p++ = cause; + *p++ = cause | 0x80; l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); - release_l3_process(pc); + dss1_release_l3_process(pc); } static void l3dss1_release(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; struct sk_buff *skb = arg; - int cause = -1; + u_char *p; + int ret, cause=0; - p = skb->data; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - if (*p++ == 2) - pc->para.loc = *p++; - cause = *p & 0x7f; - } - p = skb->data; - if ((p = findie(p, skb->len, IE_FACILITY, 0))) { -#ifdef HISAX_DE_AOC - l3dss1_parse_facility(pc,p); -#else - p = NULL; -#endif - } - dev_kfree_skb(skb); StopAllL3Timer(pc); - pc->para.cause = cause; - l3dss1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + if ((ret = l3dss1_get_cause(pc, skb))>0) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "REL get_cause ret(%d)", ret); + } else if (ret<0) + pc->para.cause = NO_CAUSE; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3dss1_parse_facility(pc->st, pc, pc->callref, p); + } + if ((ret<0) && (pc->state != 11)) + cause = 96; + else if (ret>0) + cause = 100; + ret = check_infoelements(pc, skb, ie_RELEASE); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) + cause = 99; + if (cause) + l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause); + else + l3dss1_message(pc, MT_RELEASE_COMPLETE); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); - release_l3_process(pc); + dss1_release_l3_process(pc); } static void @@ -1036,66 +1942,350 @@ void *arg) { newl3state(pc, 7); - l3dss1_message(pc, MT_ALERTING); + if (!pc->prot.dss1.uus1_data[0]) + l3dss1_message(pc, MT_ALERTING); + else + l3dss1_msg_with_uus(pc, MT_ALERTING); +} + +static void +l3dss1_proceed_req(struct l3_process *pc, u_char pr, + void *arg) +{ + newl3state(pc, 9); + l3dss1_message(pc, MT_CALL_PROCEEDING); + pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); +} + +/********************************************/ +/* deliver a incoming display message to HL */ +/********************************************/ +static void +l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp) +{ u_char len; + isdn_ctrl ic; + struct IsdnCardState *cs; + char *p; + + if (*infp++ != IE_DISPLAY) return; + if ((len = *infp++) > 80) return; /* total length <= 82 */ + if (!pc->chan) return; + + p = ic.parm.display; + while (len--) + *p++ = *infp++; + *p = '\0'; + ic.command = ISDN_STAT_DISPLAY; + cs = pc->st->l1.hardware; + ic.driver = cs->myid; + ic.arg = pc->chan->chan; + cs->iif.statcallb(&ic); +} /* l3dss1_deliver_display */ + + +static void +l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { + if (p[1] != 4) { + err = 1; + pc->para.cause = 100; + } else if (p[2] & 0x60) { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + case 0x84: + case 0x85: + case 0x87: + case 0x8a: + switch (p[3]) { + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x88: + break; + default: + err = 2; + pc->para.cause = 100; + break; + } + break; + default: + err = 3; + pc->para.cause = 100; + break; + } + } + } else { + pc->para.cause = 96; + err = 4; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "progress error %d", err); + l3dss1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_PROGRESS); + if (err) + l3dss1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); +} + +static void +l3dss1_notify(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int err = 0; + u_char *p; + + if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { + if (p[1] != 1) { + err = 1; + pc->para.cause = 100; + } else { + switch (p[2]) { + case 0x80: + case 0x81: + case 0x82: + break; + default: + pc->para.cause = 100; + err = 2; + break; + } + } + } else { + pc->para.cause = 96; + err = 3; + } + if (err) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "notify error %d", err); + l3dss1_status_send(pc, pr, NULL); + return; + } + /* Now we are on none mandatory IEs */ + err = check_infoelements(pc, skb, ie_NOTIFY); + if (err) + l3dss1_std_ie_err(pc, err); + if (ERR_IE_COMPREHENSION != err) + pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); } static void l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) { - u_char tmp[16]; - u_char *p = tmp; - int l; + int ret; struct sk_buff *skb = arg; - dev_kfree_skb(skb); - - MsgHead(p, pc->callref, MT_STATUS); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 0x9E; /* answer status enquire */ + ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); + l3dss1_std_ie_err(pc, ret); - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = pc->state & 0x3f; + idev_kfree_skb(skb, FREE_READ); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3dss1_status_send(pc, 0x1E, NULL); /* answer status enquire */ } -static void -l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg) +/******************************/ +/* handle deflection requests */ +/******************************/ +static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg) { - /* ETS 300-104 7.4.1, 8.4.1, 10.3.1, 11.4.1, 12.4.1, 13.4.1, 14.4.1... - if setup has been made and a non expected message type is received, we must send MT_STATUS cause 0x62 */ - u_char tmp[16]; + struct sk_buff *skb; + u_char tmp[128]; u_char *p = tmp; - int l; - struct sk_buff *skb = arg; + u_char *subp; + u_char len_phone = 0; + u_char len_sub = 0; + int l; + + + strcpy(pc->prot.dss1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ + if (!pc->chan->setup.phone[0]) + { pc->para.cause = -1; + l3dss1_disconnect_req(pc,pr,arg); /* disconnect immediately */ + return; + } /* only uus */ + + if (pc->prot.dss1.invoke_id) + free_invoke_id(pc->st,pc->prot.dss1.invoke_id); + + if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st))) + return; + + MsgHead(p, pc->callref, MT_FACILITY); + + for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + + *p++ = 0x1c; /* Facility info element */ + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ + *p++ = 0x91; /* remote operations protocol */ + *p++ = 0xa1; /* invoke component */ + + *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ + *p++ = 0x02; /* invoke id tag, integer */ + *p++ = 0x01; /* length */ + *p++ = pc->prot.dss1.invoke_id; /* invoke id */ + *p++ = 0x02; /* operation value tag, integer */ + *p++ = 0x01; /* length */ + *p++ = 0x0D; /* Call Deflect */ + + *p++ = 0x30; /* sequence phone number */ + *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ + + *p++ = 0x30; /* Deflected to UserNumber */ + *p++ = len_phone+2+len_sub; /* length */ + *p++ = 0x80; /* NumberDigits */ + *p++ = len_phone; /* length */ + for (l = 0; l < len_phone; l++) + *p++ = pc->chan->setup.phone[l]; + + if (len_sub) + { *p++ = 0x04; /* called party subadress */ + *p++ = len_sub - 2; + while (*subp) *p++ = *subp++; + } - dev_kfree_skb(skb); + *p++ = 0x01; /* screening identifier */ + *p++ = 0x01; + *p++ = pc->chan->setup.screen; - MsgHead(p, pc->callref, MT_STATUS); + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) return; + memcpy(skb_put(skb, l), tmp, l); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 0x62 | 0x80; /* status sending */ + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} /* l3dss1_redir_req */ - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = pc->state & 0x3f; +/********************************************/ +/* handle deflection request in early state */ +/********************************************/ +static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) +{ + l3dss1_proceed_req(pc,pr,arg); + l3dss1_redir_req(pc,pr,arg); +} /* l3dss1_redir_req_early */ + +/***********************************************/ +/* handle special commands for this protocol. */ +/* Examples are call independant services like */ +/* remote operations with dummy callref. */ +/***********************************************/ +static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) +{ u_char id; + u_char temp[265]; + u_char *p = temp; + int i, l, proc_len; + struct sk_buff *skb; + struct l3_process *pc = NULL; + + switch (ic->arg) + { case DSS1_CMD_INVOKE: + if (ic->parm.dss1_io.datalen < 0) return(-2); /* invalid parameter */ + + for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++) + i = i >> 8; /* add one byte */ + l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */ + if (l > 255) + return(-2); /* too long */ + + if (!(id = new_invoke_id(st))) + return(0); /* first get a invoke id -> return if no available */ + + i = -1; + MsgHead(p, i, MT_FACILITY); /* build message head */ + *p++ = 0x1C; /* Facility IE */ + *p++ = l; /* length of ie */ + *p++ = 0x91; /* remote operations */ + *p++ = 0xA1; /* invoke */ + *p++ = l - 3; /* length of invoke */ + *p++ = 0x02; /* invoke id tag */ + *p++ = 0x01; /* length is 1 */ + *p++ = id; /* invoke id */ + *p++ = 0x02; /* operation */ + *p++ = proc_len; /* length of operation */ + + for (i = proc_len; i; i--) + *p++ = (ic->parm.dss1_io.proc >> (i-1)) & 0xFF; + memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */ + l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */ + + if (ic->parm.dss1_io.timeout > 0) + if (!(pc = dss1_new_l3_process(st, -1))) + { free_invoke_id(st, id); + return(-2); + } + pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */ + pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */ + + if (!(skb = l3_alloc_skb(l))) + { free_invoke_id(st, id); + if (pc) dss1_release_l3_process(pc); + return(-2); + } + memcpy(skb_put(skb, l), temp, l); + + if (pc) + { pc->prot.dss1.invoke_id = id; /* remember id */ + L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST); + } + + l3_msg(st, DL_DATA | REQUEST, skb); + ic->parm.dss1_io.hl_id = id; /* return id */ + return(0); + + case DSS1_CMD_INVOKE_ABORT: + if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id))) + { L3DelTimer(&pc->timer); /* remove timer */ + dss1_release_l3_process(pc); + return(0); + } + else + { l3_debug(st, "l3dss1_cmd_global abort unknown id"); + return(-2); + } + break; + + default: + l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg); + return(-1); + } /* switch ic-> arg */ + return(-1); +} /* l3dss1_cmd_global */ + +static void +l3dss1_io_timer(struct l3_process *pc) +{ isdn_ctrl ic; + struct IsdnCardState *cs = pc->st->l1.hardware; + + L3DelTimer(&pc->timer); /* remove timer */ + + ic.driver = cs->myid; + ic.command = ISDN_STAT_PROT; + ic.arg = DSS1_STAT_INVOKE_ERR; + ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; + ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; + ic.parm.dss1_io.proc = pc->prot.dss1.proc; + ic.parm.dss1_io.timeout= -1; + ic.parm.dss1_io.datalen = 0; + ic.parm.dss1_io.data = NULL; + free_invoke_id(pc->st, pc->prot.dss1.invoke_id); + pc->prot.dss1.invoke_id = 0; /* reset id */ - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - memcpy(skb_put(skb, l), tmp, l); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); -} + cs->iif.statcallb(&ic); + + dss1_release_l3_process(pc); +} /* l3dss1_io_timer */ static void l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg) @@ -1107,22 +2297,27 @@ if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { p++; - if (1== *p++) + if (1 == *p++) callState = *p; } - if(callState == 0) { + if (callState == 0) { /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 * set down layer 3 without sending any message */ - pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); newl3state(pc, 0); - release_l3_process(pc); + dss1_release_l3_process(pc); } else { - pc->st->l3.l3l4(pc, CC_IGNORE, NULL); + pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); } } static void +l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) +{ +} + +static void l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) { if (pc->N303 > 0) { @@ -1131,8 +2326,8 @@ l3dss1_setup_req(pc, pr, arg); } else { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL); - release_l3_process(pc); + pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); + dss1_release_l3_process(pc); } } @@ -1140,9 +2335,9 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; + pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } @@ -1153,25 +2348,25 @@ u_char *p = tmp; int l; struct sk_buff *skb; - u_char cause = 0x90; + u_char cause = 16; L3DelTimer(&pc->timer); - if (pc->para.cause > 0) - cause = pc->para.cause | 0x80; + if (pc->para.cause != NO_CAUSE) + cause = pc->para.cause; MsgHead(p, pc->callref, MT_RELEASE); *p++ = IE_CAUSE; *p++ = 0x2; *p++ = 0x80; - *p++ = cause; + *p++ = cause | 0x80; l = p - tmp; if (!(skb = l3_alloc_skb(l))) return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 19); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); L3AddTimer(&pc->timer, T308, CC_T308_1); } @@ -1179,18 +2374,18 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; + pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); } static void l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; + pc->para.cause = 102; l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL); + pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); } static void @@ -1206,118 +2401,315 @@ l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL); - release_l3_process(pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); + dss1_release_l3_process(pc); +} + +static void +l3dss1_t318(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 19); + l3dss1_message(pc, MT_RELEASE); + L3AddTimer(&pc->timer, T308, CC_T308_1); +} + +static void +l3dss1_t319(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + pc->para.cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); } static void l3dss1_restart(struct l3_process *pc, u_char pr, void *arg) { L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc, CC_DLRL, NULL); - release_l3_process(pc); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + dss1_release_l3_process(pc); } static void l3dss1_status(struct l3_process *pc, u_char pr, void *arg) { u_char *p; - char tmp[64], *t; - int l; struct sk_buff *skb = arg; - int cause, callState; - - cause = callState = -1; - p = skb->data; - t = tmp; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { + int ret; + u_char cause = 0, callState = 0; + + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); + if (ret < 0) + cause = 96; + else if (ret > 0) + cause = 100; + } + if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { p++; - l = *p++; - t += sprintf(t,"Status CR %x Cause:", pc->callref); - while (l--) { - cause = *p; - t += sprintf(t," %2x",*p++); - } + if (1 == *p++) { + callState = *p; + if (!ie_in_set(pc, *p, l3_valid_states)) + cause = 100; + } else + cause = 100; } else - sprintf(t,"Status CR %x no Cause", pc->callref); - l3_debug(pc->st, tmp); - p = skb->data; - t = tmp; - t += sprintf(t,"Status state %x ", pc->state); - if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1== *p++) { - callState = *p; - t += sprintf(t,"peer state %x" , *p); - } + cause = 96; + if (!cause) { /* no error before */ + ret = check_infoelements(pc, skb, ie_STATUS); + if (ERR_IE_COMPREHENSION == ret) + cause = 96; + else if (ERR_IE_UNRECOGNIZED == ret) + cause = 99; + } + if (cause) { + u_char tmp; + + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); + tmp = pc->para.cause; + pc->para.cause = cause; + l3dss1_status_send(pc, 0, NULL); + if (cause == 99) + pc->para.cause = tmp; else - t += sprintf(t,"peer state len error"); - } else - sprintf(t,"no peer state"); - l3_debug(pc->st, tmp); - if(((cause & 0x7f) == 0x6f) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 0x6f and call + return; + } + cause = pc->para.cause; + if (((cause & 0x7f) == 111) && (callState == 0)) { + /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... + * if received MT_STATUS with cause == 111 and call * state == 0, then we must set down layer 3 */ - l3dss1_release_ind(pc, pr, arg); - } else - dev_kfree_skb(skb); + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + newl3state(pc, 0); + dss1_release_l3_process(pc); + } } static void l3dss1_facility(struct l3_process *pc, u_char pr, void *arg) { - u_char *p; struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_FACILITY); + l3dss1_std_ie_err(pc, ret); + { + u_char *p; + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) + l3dss1_parse_facility(pc->st, pc, pc->callref, p); + } +} - p = skb->data; - if ((p = findie(p, skb->len, IE_FACILITY, 0))) { -#ifdef HISAX_DE_AOC - l3dss1_parse_facility(pc,p); -#else - p = NULL; -#endif +static void +l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->chan->setup.phone; + + MsgHead(p, pc->callref, MT_SUSPEND); + + *p++ = IE_CALL_ID; + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else { + l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); + return; } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 15); + L3AddTimer(&pc->timer, T319, CC_T319); } +static void +l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + L3DelTimer(&pc->timer); + newl3state(pc, 0); + pc->para.cause = NO_CAUSE; + pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); + /* We don't handle suspend_ack for IE errors now */ + if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSPACK check ie(%d)",ret); + dss1_release_l3_process(pc); +} + +static void +l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3dss1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb; + u_char tmp[32]; + u_char *p = tmp; + u_char i, l; + u_char *msg = pc->para.setup.phone; + + MsgHead(p, pc->callref, MT_RESUME); + + *p++ = IE_CALL_ID; + l = *msg++; + if (l && (l <= 10)) { /* Max length 10 octets */ + *p++ = l; + for (i = 0; i < l; i++) + *p++ = *msg++; + } else { + l3_debug(pc->st, "RES wrong CALL_ID len %d", l); + return; + } + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(pc->st, DL_DATA | REQUEST, skb); + newl3state(pc, 17); + L3AddTimer(&pc->timer, T319, CC_T319); +} + +static void +l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int id, ret; + + if ((id = l3dss1_get_channel_id(pc, skb)) > 0) { + if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack with wrong chid %x", id); + pc->para.cause = 100; + l3dss1_status_send(pc, pr, NULL); + return; + } + pc->para.bchannel = id; + } else if (1 == pc->state) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "resume ack without chid (ret %d)", id); + pc->para.cause = 96; + l3dss1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); + newl3state(pc, 10); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->debug & L3_DEB_WARN) + l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); + if (ret < 0) + pc->para.cause = 96; + else + pc->para.cause = 100; + l3dss1_status_send(pc, pr, NULL); + return; + } + ret = check_infoelements(pc, skb, ie_RESUME_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + return; + } + L3DelTimer(&pc->timer); + pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); + newl3state(pc, 0); + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); + dss1_release_l3_process(pc); +} - static void l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) { u_char tmp[32]; u_char *p; - u_char ri, chan=0; + u_char ri, ch = 0, chan = 0; int l; struct sk_buff *skb = arg; struct l3_process *up; - + newl3state(pc, 2); L3DelTimer(&pc->timer); p = skb->data; if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { - ri = p[2]; - sprintf(tmp, "Restart %x", ri); + ri = p[2]; + l3_debug(pc->st, "Restart %x", ri); } else { - sprintf(tmp, "Restart without restart IE"); + l3_debug(pc->st, "Restart without restart IE"); ri = 0x86; } - l3_debug(pc->st, tmp); p = skb->data; if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { chan = p[2] & 3; - sprintf(tmp, "Restart for channel %d", chan); - l3_debug(pc->st, tmp); + ch = p[2]; + if (pc->st->l3.debug) + l3_debug(pc->st, "Restart for channel %d", chan); } - dev_kfree_skb(skb); newl3state(pc, 2); up = pc->st->l3.proc; while (up) { - if ((ri & 7)==7) - up->st->lli.l4l3(up->st, CC_RESTART, up); + if ((ri & 7) == 7) + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); else if (up->para.bchannel == chan) - up->st->lli.l4l3(up->st, CC_RESTART, up); + up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); up = up->next; } p = tmp; @@ -1325,9 +2717,9 @@ if (chan) { *p++ = IE_CHANNEL_ID; *p++ = 1; - *p++ = chan | 0x80; + *p++ = ch | 0x80; } - *p++ = 0x79; /* RESTART Ind */ + *p++ = 0x79; /* RESTART Ind */ *p++ = 1; *p++ = ri; l = p - tmp; @@ -1335,32 +2727,75 @@ return; memcpy(skb_put(skb, l), tmp, l); newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_DATA, skb); + l3_msg(pc->st, DL_DATA | REQUEST, skb); +} + +static void +l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg) +{ + pc->para.cause = 0x29; /* Temporary failure */ + l3dss1_disconnect_req(pc, pr, NULL); + pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); +} + +static void +l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg) +{ + newl3state(pc, 0); + pc->para.cause = 0x1b; /* Destination out of order */ + pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); + release_l3_process(pc); +} + +static void +l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + L3AddTimer(&pc->timer, T309, CC_T309); + l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); +} + +static void +l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->timer); + + l3dss1_status_send(pc, 0x1F, NULL); /* normal, unspecified */ } /* *INDENT-OFF* */ static struct stateentry downstatelist[] = { {SBIT(0), - CC_ESTABLISH, l3dss1_msg_without_setup}, + CC_SETUP | REQUEST, l3dss1_setup_req}, {SBIT(0), - CC_SETUP_REQ, l3dss1_setup_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10), - CC_DISCONNECT_REQ, l3dss1_disconnect_req}, + CC_RESUME | REQUEST, l3dss1_resume_req}, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(12), - CC_RELEASE_REQ, l3dss1_release_req}, + CC_RELEASE | REQUEST, l3dss1_release_req}, {ALL_STATES, - CC_DLRL, l3dss1_reset}, - {ALL_STATES, - CC_RESTART, l3dss1_restart}, + CC_RESTART | REQUEST, l3dss1_restart}, {SBIT(6), - CC_IGNORE, l3dss1_reset}, + CC_IGNORE | REQUEST, l3dss1_reset}, {SBIT(6), - CC_REJECT_REQ, l3dss1_reject_req}, + CC_REJECT | REQUEST, l3dss1_reject_req}, {SBIT(6), - CC_ALERTING_REQ, l3dss1_alert_req}, - {SBIT(6) | SBIT(7), - CC_SETUP_RSP, l3dss1_setup_rsp}, + CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, + {SBIT(6) | SBIT(9), + CC_ALERTING | REQUEST, l3dss1_alert_req}, + {SBIT(6) | SBIT(7) | SBIT(9), + CC_SETUP | RESPONSE, l3dss1_setup_rsp}, + {SBIT(10), + CC_SUSPEND | REQUEST, l3dss1_suspend_req}, + {SBIT(6), + CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, + {SBIT(7) | SBIT(9), + CC_REDIR | REQUEST, l3dss1_redir_req}, + {SBIT(6), + CC_REDIR | REQUEST, l3dss1_redir_req_early}, + {SBIT(9) | SBIT(25), + CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, {SBIT(1), CC_T303, l3dss1_t303}, {SBIT(2), @@ -1371,14 +2806,20 @@ CC_T313, l3dss1_t313}, {SBIT(11), CC_T305, l3dss1_t305}, + {SBIT(15), + CC_T319, l3dss1_t319}, + {SBIT(17), + CC_T318, l3dss1_t318}, {SBIT(19), CC_T308_1, l3dss1_t308_1}, {SBIT(19), CC_T308_2, l3dss1_t308_2}, + {SBIT(10), + CC_T309, l3dss1_dl_release}, }; -static int downsllen = sizeof(downstatelist) / -sizeof(struct stateentry); +#define DOWNSLLEN \ + (sizeof(downstatelist) / sizeof(struct stateentry)) static struct stateentry datastatelist[] = { @@ -1394,90 +2835,109 @@ MT_SETUP, l3dss1_setup}, {SBIT(1) | SBIT(2), MT_CALL_PROCEEDING, l3dss1_call_proc}, - {SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), - MT_CALL_PROCEEDING, l3dss1_status_req}, {SBIT(1), MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack}, - {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), - MT_SETUP_ACKNOWLEDGE, l3dss1_status_req}, - {SBIT(1) | SBIT(2) | SBIT(3), + {SBIT(2) | SBIT(3), MT_ALERTING, l3dss1_alerting}, - {SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), - MT_ALERTING, l3dss1_status_req}, + {SBIT(2) | SBIT(3), + MT_PROGRESS, l3dss1_progress}, + {SBIT(10) | SBIT(11) | SBIT(15), + MT_NOTIFY, l3dss1_notify}, {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19), MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) /*| SBIT(19)*/, + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) /* | SBIT(17) | SBIT(19)*/, MT_RELEASE, l3dss1_release}, {SBIT(19), MT_RELEASE, l3dss1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), + {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15), MT_DISCONNECT, l3dss1_disconnect}, - {SBIT(11), - MT_DISCONNECT, l3dss1_release_req}, +// {SBIT(11), +// MT_DISCONNECT, l3dss1_release_req}, + {SBIT(19), + MT_DISCONNECT, l3dss1_dummy}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), MT_CONNECT, l3dss1_connect}, - {SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), - MT_CONNECT, l3dss1_status_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(11) | SBIT(19), - MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req}, {SBIT(8), MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19), - MT_INVALID, l3dss1_status_req}, + {SBIT(15), + MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack}, + {SBIT(15), + MT_SUSPEND_REJECT, l3dss1_suspend_rej}, + {SBIT(17), + MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, + {SBIT(17), + MT_RESUME_REJECT, l3dss1_resume_rej}, }; -static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry); +#define DATASLLEN \ + (sizeof(datastatelist) / sizeof(struct stateentry)) static struct stateentry globalmes_list[] = { {ALL_STATES, - MT_STATUS, l3dss1_status}, + MT_STATUS, l3dss1_status}, {SBIT(0), MT_RESTART, l3dss1_global_restart}, /* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, + MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, */ }; -static int globalm_len = sizeof(globalmes_list) / sizeof(struct stateentry); +#define GLOBALM_LEN \ + (sizeof(globalmes_list) / sizeof(struct stateentry)) -#if 0 -static struct stateentry globalcmd_list[] = +static struct stateentry manstatelist[] = { - {ALL_STATES, - CC_STATUS, l3dss1_status_req}, - {SBIT(0), - CC_RESTART, l3dss1_restart_req}, + {SBIT(2), + DL_ESTABLISH | INDICATION, l3dss1_dl_reset}, + {SBIT(10), + DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status}, + {SBIT(10), + DL_RELEASE | INDICATION, l3dss1_dl_reestablish}, + {ALL_STATES, + DL_RELEASE | INDICATION, l3dss1_dl_release}, }; -static int globalc_len = sizeof(globalcmd_list) / sizeof(struct stateentry); -#endif +#define MANSLLEN \ + (sizeof(manstatelist) / sizeof(struct stateentry)) /* *INDENT-ON* */ + static void global_handler(struct PStack *st, int mt, struct sk_buff *skb) { + u_char tmp[16]; + u_char *p = tmp; + int l; int i; - char tmp[64]; struct l3_process *proc = st->l3.global; - - for (i = 0; i < globalm_len; i++) + + proc->callref = skb->data[2]; /* cr flag */ + for (i = 0; i < GLOBALM_LEN; i++) if ((mt == globalmes_list[i].primitive) && ((1 << proc->state) & globalmes_list[i].state)) break; - if (i == globalm_len) { - dev_kfree_skb(skb); + if (i == GLOBALM_LEN) { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1 global state %d mt %x unhandled", + l3_debug(st, "dss1 global state %d mt %x unhandled", proc->state, mt); - l3_debug(st, tmp); } - return; + MsgHead(p, proc->callref, MT_STATUS); + *p++ = IE_CAUSE; + *p++ = 0x2; + *p++ = 0x80; + *p++ = 81 |0x80; /* invalid cr */ + *p++ = 0x14; /* CallState */ + *p++ = 0x1; + *p++ = proc->state & 0x3f; + l = p - tmp; + if (!(skb = l3_alloc_skb(l))) + return; + memcpy(skb_put(skb, l), tmp, l); + l3_msg(proc->st, DL_DATA | REQUEST, skb); } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1 global %d mt %x", + l3_debug(st, "dss1 global %d mt %x", proc->state, mt); - l3_debug(st, tmp); } globalmes_list[i].rout(proc, mt, skb); } @@ -1488,124 +2948,166 @@ { int i, mt, cr, cause, callState; char *ptr; + u_char *p; struct sk_buff *skb = arg; struct l3_process *proc; - char tmp[80]; + + switch (pr) { + case (DL_DATA | INDICATION): + case (DL_UNIT_DATA | INDICATION): + break; + case (DL_ESTABLISH | CONFIRM): + case (DL_ESTABLISH | INDICATION): + case (DL_RELEASE | INDICATION): + case (DL_RELEASE | CONFIRM): + l3_msg(st, pr, arg); + return; + break; + default: + printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr); + return; + } + if (skb->len < 3) { + l3_debug(st, "dss1up frame too short(%d)", skb->len); + idev_kfree_skb(skb, FREE_READ); + return; + } if (skb->data[0] != PROTO_DIS_EURO) { if (st->l3.debug & L3_DEB_PROTERR) { - sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d", - (pr == DL_DATA) ? " " : "(broadcast) ", - skb->data[0], skb->len); - l3_debug(st, tmp); + l3_debug(st, "dss1up%sunexpected discriminator %x message len %d", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", + skb->data[0], skb->len); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } cr = getcallref(skb->data); + if (skb->len < ((skb->data[1] & 0x0f) + 3)) { + l3_debug(st, "dss1up frame too short(%d)", skb->len); + idev_kfree_skb(skb, FREE_READ); + return; + } mt = skb->data[skb->data[1] + 2]; - if (!cr) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "dss1up cr %d", cr); + if (cr == -2) { /* wrong Callref */ + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "dss1up wrong Callref"); + idev_kfree_skb(skb, FREE_READ); + return; + } else if (cr == -1) { /* Dummy Callref */ + if (mt == MT_FACILITY) + if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { + l3dss1_parse_facility(st, NULL, + (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); + idev_kfree_skb(skb, FREE_READ); + return; + } + if (st->l3.debug & L3_DEB_WARN) + l3_debug(st, "dss1up dummy Callref (no facility msg or ie)"); + idev_kfree_skb(skb, FREE_READ); + return; + } else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || + (((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) { /* Global CallRef */ + if (st->l3.debug & L3_DEB_STATE) + l3_debug(st, "dss1up Global CallRef"); global_handler(st, mt, skb); - return; - } else if (cr == -1) { /* Dummy Callref */ - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } else if (!(proc = getl3proc(st, cr))) { /* No transaction process exist, that means no call with * this callreference is active */ if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ - if (!(proc = new_l3_process(st, cr))) { + /* Setup creates a new transaction process */ + if (!(proc = dss1_new_l3_process(st, cr))) { /* May be to answer with RELEASE_COMPLETE and * CAUSE 0x2f "Resource unavailable", but this * need a new_l3_process too ... arghh */ - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); return; } } else if (mt == MT_STATUS) { cause = 0; - if((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - cause = *ptr & 0x7f; + if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { + ptr++; + if (*ptr++ == 2) + ptr++; + cause = *ptr & 0x7f; } callState = 0; - if((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { + if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { ptr++; if (*ptr++ == 2) ptr++; callState = *ptr; } - if (callState == 0) { - /* ETS 300-104 part 2.4.1 - * if setup has not been made and a message type - * MT_STATUS is received with call state == 0, - * we must send nothing - */ - dev_kfree_skb(skb); - return; - } else { + /* ETS 300-104 part 2.4.1 + * if setup has not been made and a message type + * MT_STATUS is received with call state == 0, + * we must send nothing + */ + if (callState != 0) { /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type + * if setup has not been made and a message type * MT_STATUS is received with call state != 0, * we must send MT_RELEASE_COMPLETE cause 101 */ - dev_kfree_skb(skb); - if ((proc = new_l3_process(st, cr))) { - proc->para.cause = 0x65; /* 101 */ - proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL); + if ((proc = dss1_new_l3_process(st, cr))) { + proc->para.cause = 101; + l3dss1_msg_without_setup(proc, 0, NULL); } - return; } - } else if (mt == MT_RELEASE_COMPLETE){ - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); + return; + } else if (mt == MT_RELEASE_COMPLETE) { + idev_kfree_skb(skb, FREE_READ); return; } else { /* ETS 300-104 part 2 - * if setup has not been made and a message type + * if setup has not been made and a message type * (except MT_SETUP and RELEASE_COMPLETE) is received, * we must send MT_RELEASE_COMPLETE cause 81 */ - dev_kfree_skb(skb); - if ((proc = new_l3_process(st, cr))) { - proc->para.cause = 0x51; /* 81 */ - proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL); + idev_kfree_skb(skb, FREE_READ); + if ((proc = dss1_new_l3_process(st, cr))) { + proc->para.cause = 81; + l3dss1_msg_without_setup(proc, 0, NULL); } return; } - } else if (!l3dss1_check_messagetype_validity(mt)) { - /* ETS 300-104 7.4.2, 8.4.2, 10.3.2, 11.4.2, 12.4.2, 13.4.2, - * 14.4.2... - * if setup has been made and invalid message type is received, - * we must send MT_STATUS cause 0x62 - */ - mt = MT_INVALID; /* sorry, not clean, but do the right thing ;-) */ } - - for (i = 0; i < datasllen; i++) + if (l3dss1_check_messagetype_validity(proc, mt, skb)) { + idev_kfree_skb(skb, FREE_READ); + return; + } + if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) + l3dss1_deliver_display(proc, pr, p); /* Display IE included */ + for (i = 0; i < DATASLLEN; i++) if ((mt == datastatelist[i].primitive) && ((1 << proc->state) & datastatelist[i].state)) break; - if (i == datasllen) { - dev_kfree_skb(skb); + if (i == DATASLLEN) { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1up%sstate %d mt %x unhandled", - (pr == DL_DATA) ? " " : "(broadcast) ", + l3_debug(st, "dss1up%sstate %d mt %#x unhandled", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); - l3_debug(st, tmp); } - return; + if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { + proc->para.cause = 101; + l3dss1_status_send(proc, pr, skb); + } } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1up%sstate %d mt %x", - (pr == DL_DATA) ? " " : "(broadcast) ", + l3_debug(st, "dss1up%sstate %d mt %x", + (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", proc->state, mt); - l3_debug(st, tmp); } datastatelist[i].rout(proc, pr, skb); } + idev_kfree_skb(skb, FREE_READ); + return; } static void @@ -1614,13 +3116,15 @@ int i, cr; struct l3_process *proc; struct Channel *chan; - char tmp[80]; - if (CC_SETUP_REQ == pr) { + if ((DL_ESTABLISH | REQUEST) == pr) { + l3_msg(st, pr, NULL); + return; + } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { chan = arg; cr = newcallref(); cr |= 0x80; - if ((proc = new_l3_process(st, cr))) { + if ((proc = dss1_new_l3_process(st, cr))) { proc->chan = chan; chan->proc = proc; proc->para.setup = chan->setup; @@ -1630,37 +3134,78 @@ proc = arg; } if (!proc) { - printk(KERN_ERR "HiSax internal error dss1down without proc\n"); + printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr); return; } - for (i = 0; i < downsllen; i++) + + if ( pr == (CC_TDSS1_IO | REQUEST)) { + l3dss1_io_timer(proc); /* timer expires */ + return; + } + + for (i = 0; i < DOWNSLLEN; i++) if ((pr == downstatelist[i].primitive) && ((1 << proc->state) & downstatelist[i].state)) break; - if (i == downsllen) { + if (i == DOWNSLLEN) { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1down state %d prim %d unhandled", + l3_debug(st, "dss1down state %d prim %#x unhandled", proc->state, pr); - l3_debug(st, tmp); } } else { if (st->l3.debug & L3_DEB_STATE) { - sprintf(tmp, "dss1down state %d prim %d", + l3_debug(st, "dss1down state %d prim %#x", proc->state, pr); - l3_debug(st, tmp); } downstatelist[i].rout(proc, pr, arg); } } +static void +dss1man(struct PStack *st, int pr, void *arg) +{ + int i; + struct l3_process *proc = arg; + + if (!proc) { + printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); + return; + } + for (i = 0; i < MANSLLEN; i++) + if ((pr == manstatelist[i].primitive) && + ((1 << proc->state) & manstatelist[i].state)) + break; + if (i == MANSLLEN) { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", + proc->callref & 0x7f, proc->state, pr); + } + } else { + if (st->l3.debug & L3_DEB_STATE) { + l3_debug(st, "cr %d dss1man state %d prim %#x", + proc->callref & 0x7f, proc->state, pr); + } + manstatelist[i].rout(proc, pr, arg); + } +} + void setstack_dss1(struct PStack *st) { char tmp[64]; + int i; st->lli.l4l3 = dss1down; + st->lli.l4l3_proto = l3dss1_cmd_global; st->l2.l2l3 = dss1up; + st->l3.l3ml3 = dss1man; st->l3.N303 = 1; + st->prot.dss1.last_invoke_id = 0; + st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ + i = 1; + while (i < 32) + st->prot.dss1.invoke_used[i++] = 0; + if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n"); } else { @@ -1670,8 +3215,15 @@ st->l3.global->debug = L3_DEB_WARN; st->l3.global->st = st; st->l3.global->N303 = 1; + st->l3.global->prot.dss1.invoke_id = 0; + L3InitTimer(st->l3.global, &st->l3.global->timer); } strcpy(tmp, dss1_revision); printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp)); } + + + + + diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h --- v2.2.10/linux/drivers/isdn/hisax/l3dss1.h Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/l3dss1.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,15 @@ -/* $Id: l3dss1.h,v 1.5 1998/02/02 13:34:30 keil Exp $ +/* $Id: l3dss1.h,v 1.7 1999/07/01 08:12:02 keil Exp $ * * DSS1 (Euro) D-channel protocol defines * * $Log: l3dss1.h,v $ + * Revision 1.7 1999/07/01 08:12:02 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.6 1998/03/19 13:18:50 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 1.5 1998/02/02 13:34:30 keil * Support australian Microlink net and german AOCD * @@ -21,10 +28,14 @@ * * */ + +#ifndef l3dss1_process + #define T303 4000 #define T304 30000 #define T305 30000 #define T308 4000 +#define T309 40000 #define T310 30000 #define T313 4000 #define T318 4000 @@ -34,38 +45,99 @@ * Message-Types */ -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 - -#define MT_INVALID 0xff - -#define IE_CAUSE 0x08 -#define IE_BEARER 0x04 -#define IE_FACILITY 0x1c -#define IE_CALL_STATE 0x14 -#define IE_CHANNEL_ID 0x18 -#define IE_RESTART_IND 0x79 +#define MT_ALERTING 0x01 +#define MT_CALL_PROCEEDING 0x02 +#define MT_CONNECT 0x07 +#define MT_CONNECT_ACKNOWLEDGE 0x0f +#define MT_PROGRESS 0x03 +#define MT_SETUP 0x05 +#define MT_SETUP_ACKNOWLEDGE 0x0d +#define MT_RESUME 0x26 +#define MT_RESUME_ACKNOWLEDGE 0x2e +#define MT_RESUME_REJECT 0x22 +#define MT_SUSPEND 0x25 +#define MT_SUSPEND_ACKNOWLEDGE 0x2d +#define MT_SUSPEND_REJECT 0x21 +#define MT_USER_INFORMATION 0x20 +#define MT_DISCONNECT 0x45 +#define MT_RELEASE 0x4d +#define MT_RELEASE_COMPLETE 0x5a +#define MT_RESTART 0x46 +#define MT_RESTART_ACKNOWLEDGE 0x4e +#define MT_SEGMENT 0x60 +#define MT_CONGESTION_CONTROL 0x79 +#define MT_INFORMATION 0x7b +#define MT_FACILITY 0x62 +#define MT_NOTIFY 0x6e +#define MT_STATUS 0x7d +#define MT_STATUS_ENQUIRY 0x75 + +#define IE_SEGMENT 0x00 +#define IE_BEARER 0x04 +#define IE_CAUSE 0x08 +#define IE_CALL_ID 0x10 +#define IE_CALL_STATE 0x14 +#define IE_CHANNEL_ID 0x18 +#define IE_FACILITY 0x1c +#define IE_PROGRESS 0x1e +#define IE_NET_FAC 0x20 +#define IE_NOTIFY 0x27 +#define IE_DISPLAY 0x28 +#define IE_DATE 0x29 +#define IE_KEYPAD 0x2c +#define IE_SIGNAL 0x34 +#define IE_INFORATE 0x40 +#define IE_E2E_TDELAY 0x42 +#define IE_TDELAY_SEL 0x43 +#define IE_PACK_BINPARA 0x44 +#define IE_PACK_WINSIZE 0x45 +#define IE_PACK_SIZE 0x46 +#define IE_CUG 0x47 +#define IE_REV_CHARGE 0x4a +#define IE_CONNECT_PN 0x4c +#define IE_CONNECT_SUB 0x4d +#define IE_CALLING_PN 0x6c +#define IE_CALLING_SUB 0x6d +#define IE_CALLED_PN 0x70 +#define IE_CALLED_SUB 0x71 +#define IE_REDIR_NR 0x74 +#define IE_TRANS_SEL 0x78 +#define IE_RESTART_IND 0x79 +#define IE_LLC 0x7c +#define IE_HLC 0x7d +#define IE_USER_USER 0x7e +#define IE_ESCAPE 0x7f +#define IE_SHIFT 0x90 +#define IE_MORE_DATA 0xa0 +#define IE_COMPLETE 0xa1 +#define IE_CONGESTION 0xb0 +#define IE_REPEAT 0xd0 + +#define IE_MANDATORY 0x0100 +/* mandatory not in every case */ +#define IE_MANDATORY_1 0x0200 + +#define ERR_IE_COMPREHENSION 1 +#define ERR_IE_UNRECOGNIZED -1 +#define ERR_IE_LENGTH -2 +#define ERR_IE_SEQUENCE -3 + +#else /* only l3dss1_process */ + +/* l3dss1 specific data in l3 process */ +typedef struct + { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ + ulong ll_id; /* remebered ll id */ + u_char remote_operation; /* handled remote operation, 0 = not active */ + int proc; /* rememered procedure */ + ulong remote_result; /* result of remote operation for statcallb */ + char uus1_data[35]; /* data send during alerting or disconnect */ + } dss1_proc_priv; + +/* l3dss1 specific data in protocol stack */ +typedef struct + { unsigned char last_invoke_id; /* last used value for invoking */ + unsigned char invoke_used[32]; /* 256 bits for 256 values */ + } dss1_stk_priv; + +#endif /* only l3dss1_process */ diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/lmgr.c linux/drivers/isdn/hisax/lmgr.c --- v2.2.10/linux/drivers/isdn/hisax/lmgr.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/lmgr.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,24 @@ -/* $Id: lmgr.c,v 1.2 1997/10/29 19:09:34 keil Exp $ +/* $Id: lmgr.c,v 1.6 1999/07/01 08:12:04 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * Layermanagement module * * $Log: lmgr.c,v $ + * Revision 1.6 1999/07/01 08:12:04 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.5 1998/11/15 23:55:12 keil + * changes from 2.0 + * + * Revision 1.4 1998/05/25 12:58:19 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.3 1998/03/07 22:57:06 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 1.2 1997/10/29 19:09:34 keil * new L1 * @@ -26,7 +39,7 @@ case 'D': case 'G': case 'H': - st->l2.l2tei(st, MDL_ERROR_REQ, NULL); + st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL); break; } } @@ -34,17 +47,15 @@ static void hisax_manager(struct PStack *st, int pr, void *arg) { - char tm[32], str[256]; - int Code; + long Code; switch (pr) { - case MDL_ERROR_IND: - Code = (int) arg; - jiftime(tm, jiffies); - sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm, - Code, test_bit(FLG_LAPD, &st->l2.flag) ? + case (MDL_ERROR | INDICATION): + Code = (long) arg; + HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR", + " %c %s", (char)Code, + test_bit(FLG_LAPD, &st->l2.flag) ? "D-channel" : "B-channel"); - HiSax_putstatus(st->l1.hardware, str); if (test_bit(FLG_LAPD, &st->l2.flag)) error_handling_dchan(st, Code); break; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.2.10/linux/drivers/isdn/hisax/md5sums.asc Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/md5sums.asc Mon Aug 9 12:04:39 1999 @@ -0,0 +1,29 @@ +-----BEGIN PGP SIGNED MESSAGE----- + +# This are valid md5sums for certificated HiSax driver. +# The certification is valid only if the md5sums of all files match. +# The certification is valid only for ELSA QuickStep cards in the moment. +# Read ../../../Documentation/isdn/HiSax.cert for more informations. +# +7b86f7c9709d1a96f2591b76db297116 isac.c +773fb8b13e20ef92c0bc991fea23c673 isdnl1.c +f2ef2bc94883f818d0beb184688786bc isdnl2.c +c7b9992f966c645e0eea548b0d3655a0 isdnl3.c +df3c2d2bc312af0689ed97a1fe7ad2df tei.c +94facb2403188ddfb6b83a890a5e7fa0 callc.c +f3ec2a634f06074d16167aaba02b6dc1 cert.c +e69680e894417b00949473ce38259e2a l3dss1.c +04082bae9726b7c34adb008d3752ac73 l3_1tr6.c +6705bf924beeb147d80dc91fa0aa25ee elsa.c +# end of md5sums + +-----BEGIN PGP SIGNATURE----- +Version: 2.6.3i +Charset: noconv + +iQCVAwUBN3FBezpxHvX/mS9tAQGs9wQAk4pSCWvx5CMheSRedQ7nTtIoVQKPiAEx +6/0DWE5hu5IsSOG4ZbLG/ISdad4OOZjWfMpeeIwsHVGVSspGvo9lpIMOS9EqEvr8 +I+kCrPQwKaEN675U2m0ofsELAPOyH2JICjKdbW+iipWI+6oqGta7aw/tbgDqykVr +vz2L4uxmgUY= +=r0Yz +-----END PGP SIGNATURE----- diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c --- v2.2.10/linux/drivers/isdn/hisax/mic.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/mic.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: mic.c,v 1.6 1998/02/17 15:39:57 keil Exp $ +/* $Id: mic.c,v 1.8 1999/07/12 21:05:20 keil Exp $ * mic.c low level stuff for mic cards * @@ -8,6 +8,13 @@ * * * $Log: mic.c,v $ + * Revision 1.8 1999/07/12 21:05:20 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.7 1998/04/15 16:44:32 keil + * new init code + * * Revision 1.6 1998/02/17 15:39:57 keil * fix reset problem * @@ -37,7 +44,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.6 $"; +const char *mic_revision = "$Revision: 1.8 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -155,7 +162,7 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "mic: Spurious interrupt!\n"); @@ -163,16 +170,12 @@ } val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) @@ -185,16 +188,12 @@ debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); - } - if (stat & 2) { - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); - } + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); } void @@ -215,15 +214,9 @@ case CARD_RELEASE: release_io_mic(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &mic_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: inithscx(cs); /* /RTSA := ISAC RST */ - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -273,6 +266,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &mic_card_msg; + cs->irq_func = &mic_interrupt; ISACVersion(cs, "mic:"); if (HscxVersion(cs, "mic:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.2.10/linux/drivers/isdn/hisax/netjet.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/netjet.c Mon Aug 9 12:04:39 1999 @@ -1,13 +1,37 @@ -/* $Id: netjet.c,v 1.3 1998/02/12 23:08:05 keil Exp $ +/* $Id: netjet.c,v 1.10 1999/07/12 21:05:22 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * Thanks to Traverse Technologie Australia for documents and informations * * * $Log: netjet.c,v $ + * Revision 1.10 1999/07/12 21:05:22 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.9 1999/07/01 08:12:05 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.8 1998/11/15 23:55:14 keil + * changes from 2.0 + * + * Revision 1.7 1998/09/30 22:24:48 keil + * Fix missing line in setstack* + * + * Revision 1.6 1998/08/13 23:36:54 keil + * HiSax 3.1 - don't work stable with current LinkLevel + * + * Revision 1.5 1998/05/25 12:58:21 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 1.4 1998/04/15 16:42:35 keil + * new init code + * new PCI init (2.1.94) + * * Revision 1.3 1998/02/12 23:08:05 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -25,15 +49,23 @@ #include "hscx.h" #include "isdnl1.h" #include +#ifndef COMPAT_HAS_NEW_PCI #include +#endif #include -#define fcstab ppp_crc16_table #include -extern __u16 ppp_crc16_table[256]; /* from ppp code */ + +#ifndef bus_to_virt +#define bus_to_virt (u_int *) +#endif + +#ifndef virt_to_bus +#define virt_to_bus (u_int) +#endif extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.3 $"; +const char *NETjet_revision = "$Revision: 1.10 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -62,6 +94,12 @@ #define NETJET_ISAC_OFF 0xc0 #define NETJET_ISACIRQ 0x10 +#define NETJET_IRQM0_READ 0x0c +#define NETJET_IRQM0_READ_1 0x04 +#define NETJET_IRQM0_READ_2 0x08 +#define NETJET_IRQM0_WRITE 0x03 +#define NETJET_IRQM0_WRITE_1 0x01 +#define NETJET_IRQM0_WRITE_2 0x02 #define NETJET_DMA_SIZE 512 @@ -115,6 +153,42 @@ insb(cs->hw.njet.isac, data, size); } +__u16 fcstab[256] = +{ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) { @@ -146,25 +220,20 @@ mode_tiger(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; - char tmp[64]; - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "Tiger mode %d bchan %d/%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "Tiger mode %d bchan %d/%d", mode, bc, bcs->channel); - debugl1(cs, tmp); - } bcs->mode = mode; bcs->channel = bc; switch (mode) { case (L1_MODE_NULL): fill_mem(bcs, bcs->hw.tiger.send, NETJET_DMA_SIZE, bc, 0xff); - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "Tiger stat rec %d/%d send %d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "Tiger stat rec %d/%d send %d", bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err, bcs->hw.tiger.s_tot); - debugl1(cs, tmp); - } if ((cs->bcs[0].mode == L1_MODE_NULL) && (cs->bcs[1].mode == L1_MODE_NULL)) { cs->hw.njet.dmactrl = 0; @@ -197,16 +266,14 @@ test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); break; } - if (cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "tiger: set %x %x %x %x/%x pulse=%d", + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d", bytein(cs->hw.njet.base + NETJET_DMACTRL), bytein(cs->hw.njet.base + NETJET_IRQMASK0), bytein(cs->hw.njet.base + NETJET_IRQSTAT0), inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - debugl1(cs, tmp); - } } static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) @@ -266,7 +333,7 @@ val >>= 1;\ } -static void make_raw_data(struct BCState *bcs) { +static int make_raw_data(struct BCState *bcs) { register u_int i,s_cnt=0; register u_char j; register u_char val; @@ -274,13 +341,15 @@ register u_char s_val = 0; register u_char bitcnt = 0; u_int fcs; - char tmp[64]; - + if (!bcs->tx_skb) { + debugl1(bcs->cs, "tiger make_raw: NULL skb"); + return(1); + } bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE; fcs = PPP_INITFCS; - for (i=0; ihw.tiger.tx_skb->len; i++) { - val = bcs->hw.tiger.tx_skb->data[i]; + for (i=0; itx_skb->len; i++) { + val = bcs->tx_skb->data[i]; fcs = PPP_FCS (fcs, val); MAKE_RAW_BYTE; } @@ -303,11 +372,9 @@ } val >>= 1; } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger make_raw: in %d out %d.%d", - bcs->hw.tiger.tx_skb->len, s_cnt, bitcnt); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d", + bcs->tx_skb->len, s_cnt, bitcnt); if (bitcnt) { while (8>bitcnt++) { s_val >>= 1; @@ -316,8 +383,9 @@ bcs->hw.tiger.sendbuf[s_cnt++] = s_val; } bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->hw.tiger.tx_skb->len; + bcs->tx_cnt -= bcs->tx_skb->len; bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; + return(0); } static void got_frame(struct BCState *bcs, int count) { @@ -326,6 +394,7 @@ if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "TIGER: receive out of memory\n"); else { + SET_SKB_FREE(skb); memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } @@ -349,7 +418,6 @@ register u_char r_val = bcs->hw.tiger.r_val; register u_int bitcnt = bcs->hw.tiger.r_bitcnt; u_int *p = buf; - char tmp[64]; for (i=0;ichannel ? ((*p>>8) & 0xff) : (*p & 0xff); @@ -370,11 +438,9 @@ } else { r_one=0; state= HDLC_FLAG_SEARCH; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: zBit(%d,%d,%d) %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: zBit(%d,%d,%d) %x", bcs->hw.tiger.r_tot,i,j,val); - debugl1(bcs->cs,tmp); - } } } else if (state == HDLC_FLAG_SEARCH) { if (val & 1) { @@ -387,11 +453,9 @@ bitcnt=0; r_val=0; state=HDLC_FLAG_FOUND; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: flag(%d,%d,%d) %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: flag(%d,%d,%d) %x", bcs->hw.tiger.r_tot,i,j,val); - debugl1(bcs->cs,tmp); - } } r_one=0; } @@ -425,12 +489,10 @@ bcs->hw.tiger.r_fcs = PPP_INITFCS; bcs->hw.tiger.rcvbuf[0] = r_val; bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", bcs->hw.tiger.r_tot,i,j,r_val,val, bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs,tmp); - } } } else if (state == HDLC_FRAME_FOUND) { if (val & 1) { @@ -453,11 +515,9 @@ state=HDLC_FLAG_SEARCH; bcs->hw.tiger.r_err++; } else { - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger frame end(%d,%d): fcs(%x) i %x", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x", i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs, tmp); - } if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) { got_frame(bcs, (bitcnt>>3)-3); } else @@ -509,7 +569,15 @@ u_int *p; int cnt = NETJET_DMA_SIZE/2; - if (cs->hw.njet.irqstat0 & 4) + if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) { + debugl1(cs,"tiger warn read double dma %x/%x", + cs->hw.njet.irqstat0, cs->hw.njet.last_is0); + return; + } else { + cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ; + cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ); + } + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1) p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1; else p = cs->bcs[0].hw.tiger.rec + cnt - 1; @@ -517,32 +585,28 @@ read_raw(cs->bcs, p, cnt); if (cs->bcs[1].mode == L1_MODE_HDLC) read_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= 0xf3; + cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; } static void write_raw(struct BCState *bcs, u_int *buf, int cnt); static void fill_dma(struct BCState *bcs) { - char tmp[64]; register u_int *p, *sp; register int cnt; - if (!bcs->hw.tiger.tx_skb) + if (!bcs->tx_skb) return; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma1: c%d %4x", bcs->channel, + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) return; - make_raw_data(bcs); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma2: c%d %4x", bcs->channel, + if (make_raw_data(bcs)) + return; + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { @@ -582,17 +646,14 @@ } write_raw(bcs, p, cnt); } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger fill_dma3: c%d %4x", bcs->channel, + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel, bcs->Flag); - debugl1(bcs->cs,tmp); - } } static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { u_int mask, val, *p=buf; u_int i, s_cnt; - char tmp[64]; if (cnt <= 0) return; @@ -617,26 +678,23 @@ p = bcs->hw.tiger.send; } bcs->hw.tiger.s_tot += s_cnt; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel, - (u_int)buf, (u_int)p, s_cnt, cnt, bcs->hw.tiger.sendcnt, - bcs->cs->hw.njet.irqstat0); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: c%d %x-%x %d/%d %d %x", bcs->channel, + (u_int)buf, (u_int)p, s_cnt, cnt, + bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0); if (bcs->cs->debug & L1_DEB_HSCX_FIFO) printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd"); bcs->hw.tiger.sp += s_cnt; bcs->hw.tiger.sendp = p; if (!bcs->hw.tiger.sendcnt) { - if (!bcs->hw.tiger.tx_skb) { - sprintf(tmp,"tiger write_raw: NULL skb s_cnt %d", s_cnt); - debugl1(bcs->cs, tmp); + if (!bcs->tx_skb) { + debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); } else { if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->hw.tiger.tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.tiger.tx_skb->len); - dev_kfree_skb(bcs->hw.tiger.tx_skb); - bcs->hw.tiger.tx_skb = NULL; + (PACKET_NOACK != bcs->tx_skb->pkt_type)) + bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->hw.tiger.free = cnt - s_cnt; @@ -646,7 +704,7 @@ test_and_clear_bit(BC_FLG_HALF, &bcs->Flag); test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); } - if ((bcs->hw.tiger.tx_skb = skb_dequeue(&bcs->squeue))) { + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { fill_dma(bcs); } else { mask ^= 0xffffffff; @@ -656,11 +714,9 @@ if (p>bcs->hw.tiger.s_end) p = bcs->hw.tiger.send; } - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp, "tiger write_raw: fill rest %d", + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs, "tiger write_raw: fill rest %d", cnt - s_cnt); - debugl1(bcs->cs,tmp); - } } bcs->event |= 1 << B_XMTBUFREADY; queue_task(&bcs->tqueue, &tq_immediate); @@ -671,24 +727,28 @@ test_and_set_bit(BC_FLG_HALF, &bcs->Flag); fill_mem(bcs, buf, cnt, bcs->channel, 0xff); bcs->hw.tiger.free += cnt; - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: fill half"); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: fill half"); } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - if (bcs->cs->debug & L1_DEB_HSCX) { - sprintf(tmp,"tiger write_raw: fill full"); - debugl1(bcs->cs,tmp); - } + if (bcs->cs->debug & L1_DEB_HSCX) + debugl1(bcs->cs,"tiger write_raw: fill full"); } } static void write_tiger(struct IsdnCardState *cs) { u_int *p, cnt = NETJET_DMA_SIZE/2; - if (cs->hw.njet.irqstat0 & 1) + if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { + debugl1(cs,"tiger warn write double dma %x/%x", + cs->hw.njet.irqstat0, cs->hw.njet.last_is0); + return; + } else { + cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE; + cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE); + } + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1) p = cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1; else p = cs->bcs[0].hw.tiger.send + cnt - 1; @@ -696,7 +756,7 @@ write_raw(cs->bcs, p, cnt); if (cs->bcs[1].mode == L1_MODE_HDLC) write_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= 0xfc; + cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; } static void @@ -706,45 +766,58 @@ long flags; switch (pr) { - case (PH_DATA_REQ): + case (PH_DATA | REQUEST): save_flags(flags); cli(); - if (st->l1.bcs->hw.tiger.tx_skb) { + if (st->l1.bcs->tx_skb) { skb_queue_tail(&st->l1.bcs->squeue, skb); restore_flags(flags); } else { - st->l1.bcs->hw.tiger.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); } break; - case (PH_PULL_IND): - if (st->l1.bcs->hw.tiger.tx_skb) { + case (PH_PULL | INDICATION): + if (st->l1.bcs->tx_skb) { printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); break; } save_flags(flags); cli(); - st->l1.bcs->hw.tiger.tx_skb = skb; + st->l1.bcs->tx_skb = skb; st->l1.bcs->cs->BC_Send_Data(st->l1.bcs); restore_flags(flags); break; - case (PH_PULL_REQ): - if (!st->l1.bcs->hw.tiger.tx_skb) { + case (PH_PULL | REQUEST): + if (!st->l1.bcs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL_CNF, NULL); + st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; + case (PH_ACTIVATE | REQUEST): + test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc); + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | REQUEST): + l1_msg_b(st, pr, arg); + break; + case (PH_DEACTIVATE | CONFIRM): + test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); + test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag); + mode_tiger(st->l1.bcs, 0, st->l1.bc); + st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); + break; } } + void close_tigerstate(struct BCState *bcs) { - struct sk_buff *skb; - - mode_tiger(bcs, 0, 0); + mode_tiger(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { if (bcs->hw.tiger.rcvbuf) { kfree(bcs->hw.tiger.rcvbuf); @@ -754,32 +827,26 @@ kfree(bcs->hw.tiger.sendbuf); bcs->hw.tiger.sendbuf = NULL; } - while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); - } - if (bcs->hw.tiger.tx_skb) { - dev_kfree_skb(bcs->hw.tiger.tx_skb); - bcs->hw.tiger.tx_skb = NULL; + discard_queue(&bcs->rqueue); + discard_queue(&bcs->squeue); + if (bcs->tx_skb) { + idev_kfree_skb(bcs->tx_skb, FREE_WRITE); + bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } } } static int -open_tigerstate(struct IsdnCardState *cs, int bc) +open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) { - struct BCState *bcs = cs->bcs + bc; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_KERNEL))) { + if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for tiger.rcvbuf\n"); return (1); } - if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_KERNEL))) { + if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { printk(KERN_WARNING "HiSax: No memory for tiger.sendbuf\n"); return (1); @@ -787,7 +854,7 @@ skb_queue_head_init(&bcs->rqueue); skb_queue_head_init(&bcs->squeue); } - bcs->hw.tiger.tx_skb = NULL; + bcs->tx_skb = NULL; bcs->hw.tiger.sendcnt = 0; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); bcs->event = 0; @@ -795,34 +862,17 @@ return (0); } -static void -tiger_manl1(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (PH_ACTIVATE_REQ): - test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc); - st->l1.l1man(st, PH_ACTIVATE_CNF, NULL); - break; - case (PH_DEACTIVATE_REQ): - if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) - mode_tiger(st->l1.bcs, 0, 0); - test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag); - break; - } -} - int setstack_tiger(struct PStack *st, struct BCState *bcs) { - if (open_tigerstate(st->l1.hardware, bcs->channel)) + bcs->channel = st->l1.bc; + if (open_tigerstate(st->l1.hardware, bcs)) return (-1); st->l1.bcs = bcs; st->l2.l2l1 = tiger_l2l1; - st->ma.manl1 = tiger_manl1; setstack_manager(st); bcs->st = st; + setstack_l1_B(st); return (0); } @@ -830,8 +880,6 @@ __initfunc(void inittiger(struct IsdnCardState *cs)) { - char tmp[128]; - if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_SIZE * sizeof(unsigned int), GFP_KERNEL | GFP_DMA))) { printk(KERN_WARNING @@ -845,9 +893,8 @@ cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int)); - sprintf(tmp, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send, + debugl1(cs, "tiger: send buf %x - %x", (u_int)cs->bcs[0].hw.tiger.send, (u_int)(cs->bcs[0].hw.tiger.send + NETJET_DMA_SIZE - 1)); - debugl1(cs, tmp); outl(virt_to_bus(cs->bcs[0].hw.tiger.send), cs->hw.njet.base + NETJET_DMA_READ_START); outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), @@ -860,9 +907,8 @@ "HiSax: No memory for tiger.rec\n"); return; } - sprintf(tmp, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec, + debugl1(cs, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec, (u_int)(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1)); - debugl1(cs, tmp); cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_SIZE * sizeof(unsigned int)); outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), @@ -871,11 +917,10 @@ cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_SIZE - 1), cs->hw.njet.base + NETJET_DMA_WRITE_END); - sprintf(tmp, "tiger: dmacfg %x/%x pulse=%d", + debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - debugl1(cs, tmp); cs->hw.njet.last_is0 = 0; cs->bcs[0].BC_SetStack = setstack_tiger; cs->bcs[1].BC_SetStack = setstack_tiger; @@ -906,8 +951,8 @@ netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, sval, stat = 1; - char tmp[128]; + u_char val, sval; + long flags; if (!cs) { printk(KERN_WARNING "NETjet: Spurious interrupt!\n"); @@ -916,49 +961,49 @@ if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & NETJET_ISACIRQ)) { val = ReadISAC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "tiger: i1 %x %x", sval, val); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "tiger: i1 %x %x", sval, val); if (val) { isac_interrupt(cs, val); - stat |= 2; + WriteISAC(cs, ISAC_MASK, 0xFF); + WriteISAC(cs, ISAC_MASK, 0x0); } } - if ((cs->hw.njet.irqstat0 = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { -/* sprintf(tmp, "tiger: ist0 %x %x %x %x/%x pulse=%d", + save_flags(flags); + cli(); + if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) { + if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { + restore_flags(flags); + return; + } + cs->hw.njet.irqstat0 = sval; + restore_flags(flags); +/* debugl1(cs, "tiger: ist0 %x %x %x %x/%x pulse=%d", sval, bytein(cs->hw.njet.base + NETJET_DMACTRL), bytein(cs->hw.njet.base + NETJET_IRQMASK0), inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - debugl1(cs, tmp); */ - if (cs->hw.njet.last_is0 & cs->hw.njet.irqstat0 & 0xf) { - sprintf(tmp, "tiger: ist0 %x->%x irq lost", - cs->hw.njet.last_is0, cs->hw.njet.irqstat0); - debugl1(cs, tmp); - } - cs->hw.njet.last_is0 = cs->hw.njet.irqstat0; /* cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30; */ byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0); /* byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0); -*/ if (cs->hw.njet.irqstat0 & 0x0c) +*/ if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) read_tiger(cs); - if (cs->hw.njet.irqstat0 & 0x03) + if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) write_tiger(cs); - } + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); + } else + restore_flags(flags); + /* if (!testcnt--) { cs->hw.njet.dmactrl = 0; byteout(cs->hw.njet.base + NETJET_DMACTRL, cs->hw.njet.dmactrl); byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); } -*/ if (stat & 2) { - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - } +*/ } static void @@ -1004,13 +1049,12 @@ case CARD_RELEASE: release_io_netjet(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &netjet_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: inittiger(cs); clear_pending_isac_ints(cs); initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); return(0); case CARD_TEST: return(0); @@ -1018,9 +1062,11 @@ return(0); } - - -static int pci_index __initdata = 0; +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_netjet __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif __initfunc(int setup_netjet(struct IsdnCard *card)) @@ -1029,15 +1075,40 @@ struct IsdnCardState *cs = card->cs; char tmp[64]; #if CONFIG_PCI +#ifndef COMPAT_HAS_NEW_PCI u_char pci_bus, pci_device_fn, pci_irq; u_int pci_ioaddr, found; #endif - +#endif strcpy(tmp, NETjet_revision); printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp)); if (cs->typ != ISDN_CTYPE_NETJET) return(0); + test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); #if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "Netjet: no PCI bus present\n"); + return(0); + } + if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH, + PCI_NETJET_ID, dev_netjet))) { + cs->irq = dev_netjet->irq; + if (!cs->irq) { + printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.njet.base = dev_netjet->base_address[0] + & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.njet.base) { + printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); + return(0); + } + } else { + printk(KERN_WARNING "NETjet: No PCI card found\n"); + return(0); + } +#else found = 0; for (; pci_index < 0xff; pci_index++) { if (pcibios_find_device(PCI_VENDOR_TRAVERSE_TECH, @@ -1045,7 +1116,7 @@ == PCIBIOS_SUCCESSFUL) found = 1; else - break; + continue; /* get IRQ */ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq); @@ -1060,6 +1131,7 @@ printk(KERN_WARNING "NETjet: No PCI card found\n"); return(0); } + pci_index++; if (!pci_irq) { printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n"); return(0); @@ -1068,11 +1140,11 @@ printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n"); return(0); } - pci_ioaddr &= ~3; /* remove io/mem flag */ - cs->hw.njet.base = pci_ioaddr; - cs->hw.njet.auxa = pci_ioaddr + NETJET_AUXDATA; - cs->hw.njet.isac = pci_ioaddr | NETJET_ISAC_OFF; + cs->hw.njet.base = pci_ioaddr & PCI_BASE_ADDRESS_IO_MASK; cs->irq = pci_irq; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; + cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; bytecnt = 256; #else printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n"); @@ -1101,6 +1173,8 @@ cs->BC_Write_Reg = &dummywr; cs->BC_Send_Data = &fill_dma; cs->cardmsg = &NETjet_card_msg; + cs->irq_func = &netjet_interrupt; + cs->irq_flags |= SA_SHIRQ; ISACVersion(cs, "NETjet:"); return (1); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.2.10/linux/drivers/isdn/hisax/niccy.c Tue Apr 7 07:52:04 1998 +++ linux/drivers/isdn/hisax/niccy.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.2 1998/02/11 17:31:04 keil Exp $ +/* $Id: niccy.c,v 1.6 1999/07/12 21:05:23 keil Exp $ * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -8,24 +8,38 @@ * Thanks to Dr. Neuhaus and SAGEM for informations * * $Log: niccy.c,v $ - * Revision 1.2 1998/02/11 17:31:04 keil - * new file + * Revision 1.6 1999/07/12 21:05:23 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.5 1999/07/01 08:12:07 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * + * Revision 1.4 1998/04/16 19:16:48 keil + * need config.h * + * Revision 1.3 1998/04/15 16:42:59 keil + * new init code + * + * Revision 1.2 1998/02/11 17:31:04 keil + * new file * */ -#include + #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" #include "hscx.h" #include "isdnl1.h" #include +#ifndef COMPAT_HAS_NEW_PCI #include +#endif extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.2 $"; +const char *niccy_revision = "$Revision: 1.6 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -44,6 +58,10 @@ /* PCI stuff */ #define PCI_VENDOR_DR_NEUHAUS 0x1267 #define PCI_NICCY_ID 0x1016 +#define PCI_IRQ_CTRL_REG 0x38 +#define PCI_IRQ_ENABLE 0x1f00 +#define PCI_IRQ_DISABLE 0xff0000 +#define PCI_IRQ_ASSERT 0x800000 static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -146,24 +164,27 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "Niccy: Spurious interrupt!\n"); return; } + if (cs->subtyp == NICCY_PCI) { + int ival; + ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */ + return; + outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + } val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) @@ -176,24 +197,26 @@ debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); - } - if (stat & 2) { - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); - } + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); + writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); } void release_io_niccy(struct IsdnCardState *cs) { - if (cs->subtyp == NICCY_PCI) + if (cs->subtyp == NICCY_PCI) { + int val; + + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + val &= PCI_IRQ_DISABLE; + outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + release_region(cs->hw.niccy.cfg_reg, 0x80); release_region(cs->hw.niccy.isac, 4); - else { + } else { release_region(cs->hw.niccy.isac, 2); release_region(cs->hw.niccy.isac_ale, 2); } @@ -202,7 +225,13 @@ static void niccy_reset(struct IsdnCardState *cs) { - // No reset procedure known + int val, nval; + + val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + nval = val | PCI_IRQ_ENABLE; + outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); + + inithscxisac(cs, 3); } static int @@ -215,14 +244,8 @@ case CARD_RELEASE: release_io_niccy(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &niccy_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + niccy_reset(cs); return(0); case CARD_TEST: return(0); @@ -230,7 +253,11 @@ return(0); } -static int pci_index __initdata = 0; +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *niccy_dev __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif __initfunc(int setup_niccy(struct IsdnCard *card)) @@ -272,8 +299,38 @@ request_region(cs->hw.niccy.isac_ale, 2, "niccy addr"); } else { #if CONFIG_PCI - u_char pci_bus, pci_device_fn, pci_irq; u_int pci_ioaddr; +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "Niccy: no PCI bus present\n"); + return(0); + } + cs->subtyp = 0; + if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS, + PCI_NICCY_ID, niccy_dev))) { + /* get IRQ */ + if (!niccy_dev->irq) { + printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); + return(0); + } + cs->irq = niccy_dev->irq; + if (!niccy_dev->base_address[0]) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); + return(0); + } + cs->hw.niccy.cfg_reg = niccy_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + if (!niccy_dev->base_address[1]) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); + return(0); + } + pci_ioaddr = niccy_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + cs->subtyp = NICCY_PCI; + } else { + printk(KERN_WARNING "Niccy: No PCI card found\n"); + return(0); + } +#else + u_char pci_bus, pci_device_fn, pci_irq; cs->subtyp = 0; for (; pci_index < 0xff; pci_index++) { @@ -282,17 +339,22 @@ == PCIBIOS_SUCCESSFUL) cs->subtyp = NICCY_PCI; else - break; + continue; /* get IRQ */ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq); + /* get IO pci AMCC address */ + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + if (!pci_ioaddr) { + printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n"); + return(0); + } + cs->hw.niccy.cfg_reg = pci_ioaddr & ~3 ; /* get IO address */ - /* if it won't work try the other PCI addresses - * PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5 - */ pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_2, &pci_ioaddr); + PCI_BASE_ADDRESS_1, &pci_ioaddr); if (cs->subtyp) break; } @@ -300,21 +362,23 @@ printk(KERN_WARNING "Niccy: No PCI card found\n"); return(0); } + pci_index++; if (!pci_irq) { printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n"); return(0); } - if (!pci_ioaddr) { printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n"); return(0); } pci_ioaddr &= ~3; /* remove io/mem flag */ + cs->irq = pci_irq; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->irq_flags |= SA_SHIRQ; cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; - cs->irq = pci_irq; if (check_region((cs->hw.niccy.isac), 4)) { printk(KERN_WARNING "HiSax: %s data port %x-%x already in use\n", @@ -324,6 +388,17 @@ return (0); } else request_region(cs->hw.niccy.isac, 4, "niccy"); + if (check_region(cs->hw.niccy.cfg_reg, 0x80)) { + printk(KERN_WARNING + "HiSax: %s pci port %x-%x already in use\n", + CardType[card->typ], + cs->hw.niccy.cfg_reg, + cs->hw.niccy.cfg_reg + 0x80); + release_region(cs->hw.niccy.isac, 4); + return (0); + } else { + request_region(cs->hw.niccy.cfg_reg, 0x80, "niccy pci"); + } #else printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); @@ -334,7 +409,6 @@ "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n", CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI", cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); - niccy_reset(cs); cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; @@ -343,6 +417,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &niccy_card_msg; + cs->irq_func = &niccy_interrupt; ISACVersion(cs, "Niccy:"); if (HscxVersion(cs, "Niccy:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.2.10/linux/drivers/isdn/hisax/q931.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/q931.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: q931.c,v 1.6 1997/07/27 21:09:44 keil Exp $ +/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $ * q931.c code to decode ITU Q.931 call control messages * @@ -14,6 +14,9 @@ * * * $Log: q931.c,v $ + * Revision 1.7 1998/11/15 23:55:17 keil + * changes from 2.0 + * * Revision 1.6 1997/07/27 21:09:44 keil * move functions to isdnl3.c * @@ -159,7 +162,7 @@ {MT_N0_CLO_ACK, "CLOse ACKnowledge"} }; -int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType)); +#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) static struct MessageType mt_n1[] = @@ -196,7 +199,7 @@ {MT_N1_STAT, "STATus"} }; -int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType)); +#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) static struct MessageType fac_1tr6[] = { @@ -220,9 +223,7 @@ {FAC_Rueckwechsel, "Rueckwechsel"}, {FAC_Umleitung, "Umleitung"} }; -int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType)); - - +#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType)) static int prbits(char *dest, u_char b, int start, int len) @@ -925,7 +926,7 @@ {WE0_userInfo, "User Info", general} }; -static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement)); +#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) static struct InformationElement we_6[] = { @@ -937,7 +938,7 @@ {WE6_statusCalled, "Status Called", general}, {WE6_addTransAttr, "Additional Transmission Attributes", general} }; -static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); +#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) int QuickHex(char *txt, u_char * p, int cnt) @@ -964,39 +965,92 @@ } void -LogFrame(struct IsdnCardState *sp, u_char * buf, int size) +LogFrame(struct IsdnCardState *cs, u_char * buf, int size) { char *dp; if (size < 1) return; - dp = sp->dlogspace; - if (size < 4096 / 3 - 10) { - dp += sprintf(dp, "HEX:"); + dp = cs->dlog; + if (size < MAX_DLOG_SPACE / 3 - 10) { + *dp++ = 'H'; + *dp++ = 'E'; + *dp++ = 'X'; + *dp++ = ':'; dp += QuickHex(dp, buf, size); dp--; *dp++ = '\n'; *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); } else - sprintf(dp, "LogFrame: warning Frame too big (%d)\n", - size); - HiSax_putstatus(sp, sp->dlogspace); + HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); } void -dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment) +dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) { - u_char *bend = buf + size; + u_char *bend, *buf; char *dp; unsigned char pd, cr_l, cr, mt; - int i, cs = 0, cs_old = 0, cs_fest = 0; + unsigned char sapi, tei, ftyp; + int i, cset = 0, cs_old = 0, cs_fest = 0; + int size, finish = 0; - if (size < 1) + if (skb->len < 3) return; /* display header */ - dp = sp->dlogspace; - dp += sprintf(dp, "%s\n", comment); - + dp = cs->dlog; + dp += jiftime(dp, jiffies); + *dp++ = ' '; + sapi = skb->data[0] >> 2; + tei = skb->data[1] >> 1; + ftyp = skb->data[2]; + buf = skb->data; + dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); + size = skb->len; + + if (tei == GROUP_TEI) { + if (sapi == CTRL_SAPI) { /* sapi 0 */ + if (ftyp == 3) { + dp += sprintf(dp, "broadcast\n"); + buf += 3; + size -= 3; + } else { + dp += sprintf(dp, "no UI broadcast\n"); + finish = 1; + } + } else if (sapi == TEI_SAPI) { + dp += sprintf(dp, "tei managment\n"); + finish = 1; + } else { + dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); + finish = 1; + } + } else { + if (sapi == CTRL_SAPI) { + if (!(ftyp & 1)) { /* IFrame */ + dp += sprintf(dp, "with tei %d\n", tei); + buf += 4; + size -= 4; + } else { + dp += sprintf(dp, "SFrame with tei %d\n", tei); + finish = 1; + } + } else { + dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); + finish = 1; + } + } + bend = skb->data + skb->len; + if (buf >= bend) { + dp += sprintf(dp, "frame too short\n"); + finish = 1; + } + if (finish) { + *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); + return; + } if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ /* locate message type */ pd = *buf++; @@ -1007,11 +1061,11 @@ cr = 0; mt = *buf++; if (pd == PROTO_DIS_N0) { /* N0 */ - for (i = 0; i < mt_n0_len; i++) + for (i = 0; i < MT_N0_LEN; i++) if (mt_n0[i].nr == mt) break; /* display message type if it exists */ - if (i == mt_n0_len) + if (i == MT_N0_LEN) dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt); @@ -1020,11 +1074,11 @@ cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt_n0[i].descr); } else { /* N1 */ - for (i = 0; i < mt_n1_len; i++) + for (i = 0; i < MT_N1_LEN; i++) if (mt_n1[i].nr == mt) break; /* display message type if it exists */ - if (i == mt_n1_len) + if (i == MT_N1_LEN) dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", cr & 0x7f, (cr & 0x80) ? "called" : "caller", size, mt); @@ -1041,8 +1095,8 @@ switch ((*buf >> 4) & 7) { case 1: dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cs; - cs = *buf & 7; + cs_old = cset; + cset = *buf & 7; cs_fest = *buf & 8; break; case 3: @@ -1066,33 +1120,33 @@ continue; } /* No, locate it in the table */ - if (cs == 0) { - for (i = 0; i < we_0_len; i++) + if (cset == 0) { + for (i = 0; i < WE_0_LEN; i++) if (*buf == we_0[i].nr) break; /* When found, give appropriate msg */ - if (i != we_0_len) { + if (i != WE_0_LEN) { dp += sprintf(dp, " %s\n", we_0[i].descr); dp += we_0[i].f(dp, buf); } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); - } else if (cs == 6) { - for (i = 0; i < we_6_len; i++) + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); + } else if (cset == 6) { + for (i = 0; i < WE_6_LEN; i++) if (*buf == we_6[i].nr) break; /* When found, give appropriate msg */ - if (i != we_6_len) { + if (i != WE_6_LEN) { dp += sprintf(dp, " %s\n", we_6[i].descr); dp += we_6[i].f(dp, buf); } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); + dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); /* Skip to next element */ if (cs_fest == 8) { - cs = cs_old; + cset = cs_old; cs_old = 0; cs_fest = 0; } @@ -1170,6 +1224,6 @@ } else { dp += sprintf(dp, "Unknown protocol %x!", buf[0]); } - dp += sprintf(dp, "\n"); - HiSax_putstatus(sp, sp->dlogspace); + *dp = 0; + HiSax_putstatus(cs, NULL, cs->dlog); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/rawhdlc.c linux/drivers/isdn/hisax/rawhdlc.c --- v2.2.10/linux/drivers/isdn/hisax/rawhdlc.c Wed May 20 18:54:37 1998 +++ linux/drivers/isdn/hisax/rawhdlc.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: rawhdlc.c,v 1.2 1998/02/09 10:53:51 keil Exp $ +/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $ * rawhdlc.c support routines for cards that don't support HDLC * diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c --- v2.2.10/linux/drivers/isdn/hisax/s0box.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/s0box.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,267 @@ +/* $Id: s0box.c,v 2.2 1999/07/12 21:05:25 keil Exp $ + + * s0box.c low level stuff for Creatix S0BOX + * + * Author S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de) + * + * + */ +#define __NO_VERSION__ +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "isdnl1.h" + +extern const char *CardType[]; +const char *s0box_revision = "$Revision: 2.2 $"; + +static inline void +writereg(unsigned int padr, signed int addr, u_char off, u_char val) { + unsigned long flags; + + save_flags(flags); + cli(); + outb_p(0x1c,padr+2); + outb_p(0x14,padr+2); + outb_p((addr+off)&0x7f,padr); + outb_p(0x16,padr+2); + outb_p(val,padr); + outb_p(0x17,padr+2); + outb_p(0x14,padr+2); + outb_p(0x1c,padr+2); + restore_flags(flags); +} + +static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ; + +static inline u_char +readreg(unsigned int padr, signed int addr, u_char off) { + register u_char n1, n2; + unsigned long flags; + + save_flags(flags); + cli(); + outb_p(0x1c,padr+2); + outb_p(0x14,padr+2); + outb_p((addr+off)|0x80,padr); + outb_p(0x16,padr+2); + outb_p(0x17,padr+2); + n1 = (inb_p(padr+1) >> 3) & 0x17; + outb_p(0x16,padr+2); + n2 = (inb_p(padr+1) >> 3) & 0x17; + outb_p(0x14,padr+2); + outb_p(0x1c,padr+2); + restore_flags(flags); + return nibtab[n1] | (nibtab[n2] << 4); +} + +static inline void +read_fifo(unsigned int padr, signed int adr, u_char * data, int size) +{ + int i; + register u_char n1, n2; + + outb_p(0x1c, padr+2); + outb_p(0x14, padr+2); + outb_p(adr|0x80, padr); + outb_p(0x16, padr+2); + for (i=0; i> 3) & 0x17; + outb_p(0x16,padr+2); + n2 = (inb_p(padr+1) >> 3) & 0x17; + *(data++)=nibtab[n1] | (nibtab[n2] << 4); + } + outb_p(0x14,padr+2); + outb_p(0x1c,padr+2); + return; +} + +static inline void +write_fifo(unsigned int padr, signed int adr, u_char * data, int size) +{ + int i; + outb_p(0x1c, padr+2); + outb_p(0x14, padr+2); + outb_p(adr&0x7f, padr); + for (i=0; ihw.teles3.cfg_reg, cs->hw.teles3.isac, offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); +} + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset)); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) + +#include "hscx_irq.c" + +static void +s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 5 + struct IsdnCardState *cs = dev_id; + u_char val; + int count = 0; + + if (!cs) { + printk(KERN_WARNING "Teles: Spurious interrupt!\n"); + return; + } + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + count++; + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); + if (val && count < MAXCOUNT) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (count >= MAXCOUNT) + printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); +} + +void +release_io_s0box(struct IsdnCardState *cs) +{ + release_region(cs->hw.teles3.cfg_reg, 8); +} + +static int +S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + break; + case CARD_RELEASE: + release_io_s0box(cs); + break; + case CARD_INIT: + inithscxisac(cs, 3); + break; + case CARD_TEST: + break; + } + return(0); +} + +__initfunc(int +setup_s0box(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, s0box_revision); + printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_S0BOX) + return (0); + + cs->hw.teles3.cfg_reg = card->para[1]; + cs->hw.teles3.hscx[0] = -0x20; + cs->hw.teles3.hscx[1] = 0x0; + cs->hw.teles3.isac = 0x20; + cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; + cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; + cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; + cs->irq = card->para[0]; + if (check_region(cs->hw.teles3.cfg_reg,8)) { + printk(KERN_WARNING + "HiSax: %s ports %x-%x already in use\n", + CardType[cs->typ], + cs->hw.teles3.cfg_reg, + cs->hw.teles3.cfg_reg + 7); + return 0; + } else + request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O"); + printk(KERN_INFO + "HiSax: %s config irq:%d isac:0x%x cfg:0x%x\n", + CardType[cs->typ], cs->irq, + cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); + printk(KERN_INFO + "HiSax: hscx A:0x%x hscx B:0x%x\n", + cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &S0Box_card_msg; + cs->irq_func = &s0box_interrupt; + ISACVersion(cs, "S0Box:"); + if (HscxVersion(cs, "S0Box:")) { + printk(KERN_WARNING + "S0Box: wrong HSCX versions check IO address\n"); + release_io_s0box(cs); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c --- v2.2.10/linux/drivers/isdn/hisax/saphir.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/saphir.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,326 @@ +/* $Id: saphir.c,v 1.3 1999/07/12 21:05:26 keil Exp $ + + * saphir.c low level stuff for HST Saphir 1 + * + * Author Karsten Keil (keil@isdn4linux.de) + * + * Thanks to HST High Soft Tech GmbH + * + * + * $Log: saphir.c,v $ + * Revision 1.3 1999/07/12 21:05:26 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.2 1999/07/01 08:07:55 keil + * Initial version + * + * + */ + + +#define __NO_VERSION__ +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "isdnl1.h" + +extern const char *CardType[]; +static char *saphir_rev = "$Revision: 1.3 $"; + +#define byteout(addr,val) outb(val,addr) +#define bytein(addr) inb(addr) + +#define ISAC_DATA 0 +#define HSCX_DATA 1 +#define ADDRESS_REG 2 +#define IRQ_REG 3 +#define SPARE_REG 4 +#define RESET_REG 5 + +static inline u_char +readreg(unsigned int ale, unsigned int adr, u_char off) +{ + register u_char ret; + long flags; + + save_flags(flags); + cli(); + byteout(ale, off); + ret = bytein(adr); + restore_flags(flags); + return (ret); +} + +static inline void +readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo read without cli because it's allready done */ + + byteout(ale, off); + insb(adr, data, size); +} + + +static inline void +writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +{ + long flags; + + save_flags(flags); + cli(); + byteout(ale, off); + byteout(adr, data); + restore_flags(flags); +} + +static inline void +writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +{ + /* fifo write without cli because it's allready done */ + byteout(ale, off); + outsb(adr, data, size); +} + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); +} + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, + offset + (hscx ? 0x40 : 0))); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, + offset + (hscx ? 0x40 : 0), value); +} + +#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) +#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) + +#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ + cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) + +#include "hscx_irq.c" + +static void +saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + + if (!cs) { + printk(KERN_WARNING "saphir: Spurious interrupt!\n"); + return; + } + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); + Start_HSCX: + if (val) + hscx_int_main(cs, val); + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); + if (val) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "HSCX IntStat after IntRoutine"); + goto Start_HSCX; + } + val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); + if (val) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + /* Watchdog */ + if (cs->hw.saphir.timer.function) { + del_timer(&cs->hw.saphir.timer); + cs->hw.saphir.timer.expires = jiffies + 1*HZ; + add_timer(&cs->hw.saphir.timer); + } else + printk(KERN_WARNING "saphir: Spurious timer!\n"); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); + writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); +} + +static void +SaphirWatchDog(struct IsdnCardState *cs) +{ + /* 5 sec WatchDog, so read at least every 4 sec */ + cs->readisac(cs, ISAC_RBCH); + del_timer(&cs->hw.saphir.timer); + cs->hw.saphir.timer.expires = jiffies + 1*HZ; + add_timer(&cs->hw.saphir.timer); +} + +void +release_io_saphir(struct IsdnCardState *cs) +{ + long flags; + + save_flags(flags); + cli(); + byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); + del_timer(&cs->hw.saphir.timer); + cs->hw.saphir.timer.function = NULL; + restore_flags(flags); + if (cs->hw.saphir.cfg_reg) + release_region(cs->hw.saphir.cfg_reg, 6); +} + +static int +saphir_reset(struct IsdnCardState *cs) +{ + long flags; + u_char irq_val; + + switch(cs->irq) { + case 5: irq_val = 0; + break; + case 3: irq_val = 1; + break; + case 11: + irq_val = 2; + break; + case 12: + irq_val = 3; + break; + case 15: + irq_val = 4; + break; + default: + printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n", + cs->irq); + return (1); + } + byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); + save_flags(flags); + sti(); + byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ + byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((30*HZ)/1000); /* Timeout 30ms */ + restore_flags(flags); + byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); + byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); + return (0); +} + +static int +saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + saphir_reset(cs); + return(0); + case CARD_RELEASE: + release_io_saphir(cs); + return(0); + case CARD_INIT: + inithscxisac(cs, 3); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + + +__initfunc(int +setup_saphir(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; + + strcpy(tmp, saphir_rev); + printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_HSTSAPHIR) + return (0); + + /* IO-Ports */ + cs->hw.saphir.cfg_reg = card->para[1]; + cs->hw.saphir.isac = card->para[1] + ISAC_DATA; + cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; + cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; + cs->irq = card->para[0]; + if (check_region((cs->hw.saphir.cfg_reg), 6)) { + printk(KERN_WARNING + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.saphir.cfg_reg, + cs->hw.saphir.cfg_reg + 5); + return (0); + } else + request_region(cs->hw.saphir.cfg_reg,6, "saphir"); + + printk(KERN_INFO + "HiSax: %s config irq:%d io:0x%X\n", + CardType[cs->typ], cs->irq, + cs->hw.saphir.cfg_reg); + + cs->hw.saphir.timer.function = (void *) SaphirWatchDog; + cs->hw.saphir.timer.data = (long) cs; + init_timer(&cs->hw.saphir.timer); + cs->hw.saphir.timer.expires = jiffies + 4*HZ; + add_timer(&cs->hw.saphir.timer); + if (saphir_reset(cs)) { + release_io_saphir(cs); + return (0); + } + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &saphir_card_msg; + cs->irq_func = &saphir_interrupt; + ISACVersion(cs, "saphir:"); + if (HscxVersion(cs, "saphir:")) { + printk(KERN_WARNING + "saphir: wrong HSCX versions check IO address\n"); + release_io_saphir(cs); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.2.10/linux/drivers/isdn/hisax/sedlbauer.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/sedlbauer.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,14 @@ -/* $Id: sedlbauer.c,v 1.6 1998/02/09 18:46:06 keil Exp $ +/* $Id: sedlbauer.c,v 1.11 1999/07/12 21:05:27 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards - * includes Support for the Sedlbauer Speed Star - * derived from the original file dynalink.c from Karsten Keil + * includes support for the Sedlbauer speed star (speed star II), + * support for the Sedlbauer speed fax+, + * support for the Sedlbauer ISDN-Controller PC/104 and + * support for the Sedlbauer speed pci + * derived from the original file asuscom.c from Karsten Keil * * Copyright (C) 1997,1998 Marcus Niemann (for the modifications to - * the original file dynalink.c) + * the original file asuscom.c) * * Author Marcus Niemann (niemann@www-bib.fh-bielefeld.de) * @@ -14,6 +17,22 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.11 1999/07/12 21:05:27 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.10 1999/07/01 08:12:09 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.9 1998/11/15 23:55:20 keil + * changes from 2.0 + * + * Revision 1.8 1998/08/13 23:34:51 keil + * starting speedfax+ (ISAR) support + * + * Revision 1.7 1998/04/15 16:44:33 keil + * new init code + * * Revision 1.6 1998/02/09 18:46:06 keil * Support for Sedlbauer PCMCIA (Marcus Niemann) * @@ -35,36 +54,94 @@ * */ +/* Supported cards: + * Card: Chip: Configuration: Comment: + * --------------------------------------------------------------------- + * Speed Card ISAC_HSCX DIP-SWITCH + * Speed Win ISAC_HSCX ISAPNP + * Speed Fax+ ISAC_ISAR ISAPNP #HDLC works# + * Speed Star ISAC_HSCX CARDMGR + * Speed Win2 IPAC ISAPNP + * ISDN PC/104 IPAC DIP-SWITCH + * Speed Star2 IPAC CARDMGR + * Speed PCI IPAC PNP + * + * Important: + * For the sedlbauer speed fax+ to work properly you have to download + * the firmware onto the card. + * For example: hisaxctrl 9 ISAR.BIN +*/ + +#define SEDLBAUER_PCI 1 + #define __NO_VERSION__ +#include #include "hisax.h" #include "isac.h" +#include "ipac.h" #include "hscx.h" +#include "isar.h" #include "isdnl1.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.6 $"; +const char *Sedlbauer_revision = "$Revision: 1.11 $"; const char *Sedlbauer_Types[] = -{"None", "Speed Card", "Speed Win", "Speed Star"}; + {"None", "speed card/win", "speed star", "speed fax+", + "speed win II / ISDN PC/104", "speed star II", "speed pci"}; + +#ifdef SEDLBAUER_PCI +#define PCI_VENDOR_SEDLBAUER 0xe159 +#define PCI_SPEEDPCI_ID 0x02 +#endif -#define SEDL_SPEED_CARD 1 -#define SEDL_SPEED_WIN 2 -#define SEDL_SPEED_STAR 3 +#define SEDL_SPEED_CARD_WIN 1 +#define SEDL_SPEED_STAR 2 +#define SEDL_SPEED_FAX 3 +#define SEDL_SPEED_WIN2_PC104 4 +#define SEDL_SPEED_STAR2 5 +#define SEDL_SPEED_PCI 6 + +#define SEDL_CHIP_TEST 0 +#define SEDL_CHIP_ISAC_HSCX 1 +#define SEDL_CHIP_ISAC_ISAR 2 +#define SEDL_CHIP_IPAC 3 + +#define SEDL_BUS_ISA 1 +#define SEDL_BUS_PCI 2 +#define SEDL_BUS_PCMCIA 3 #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -#define SEDL_RESET_ON 0 -#define SEDL_RESET_OFF 1 -#define SEDL_ISAC 2 -#define SEDL_HSCX 3 -#define SEDL_ADR 4 - -#define SEDL_PCMCIA_RESET 0 -#define SEDL_PCMCIA_ISAC 1 -#define SEDL_PCMCIA_HSCX 2 -#define SEDL_PCMCIA_ADR 4 +#define SEDL_HSCX_ISA_RESET_ON 0 +#define SEDL_HSCX_ISA_RESET_OFF 1 +#define SEDL_HSCX_ISA_ISAC 2 +#define SEDL_HSCX_ISA_HSCX 3 +#define SEDL_HSCX_ISA_ADR 4 + +#define SEDL_HSCX_PCMCIA_RESET 0 +#define SEDL_HSCX_PCMCIA_ISAC 1 +#define SEDL_HSCX_PCMCIA_HSCX 2 +#define SEDL_HSCX_PCMCIA_ADR 4 + +#define SEDL_ISAR_ISA_ISAC 4 +#define SEDL_ISAR_ISA_ISAR 6 +#define SEDL_ISAR_ISA_ADR 8 +#define SEDL_ISAR_ISA_ISAR_RESET_ON 10 +#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12 + +#define SEDL_IPAC_ANY_ADR 0 +#define SEDL_IPAC_ANY_IPAC 2 + +#define SEDL_IPAC_PCI_BASE 0 +#define SEDL_IPAC_PCI_ADR 0xc0 +#define SEDL_IPAC_PCI_IPAC 0xc8 #define SEDL_RESET 0x3 /* same as DOS driver */ @@ -139,6 +216,29 @@ } static u_char +ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) +{ + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));} + +static void +WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value); +} + +static void +ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); +} + +static void +WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size) +{ + writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); +} + +static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) { return (readreg(cs->hw.sedl.adr, @@ -152,6 +252,34 @@ cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); } +/* ISAR access routines + * mode = 0 access with IRQ on + * mode = 1 access with IRQ off + * mode = 2 access with IRQ off and using last offset + */ + +static u_char +ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) +{ + if (mode == 0) + return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset)); + else if (mode == 1) + byteout(cs->hw.sedl.adr, offset); + return(bytein(cs->hw.sedl.hscx)); +} + +static void +WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) +{ + if (mode == 0) + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value); + else { + if (mode == 1) + byteout(cs->hw.sedl.adr, offset); + byteout(cs->hw.sedl.hscx, value); + } +} + /* * fast interrupt HSCX stuff goes here */ @@ -173,14 +301,14 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n"); return; } - if ((cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) && (*cs->busy_flag == 1)) { + if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { /* The card tends to generate interrupts while being removed causing us to just crash the kernel. bad. */ printk(KERN_WARNING "Sedlbauer: card not available!\n"); @@ -189,16 +317,12 @@ val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); if (val) { if (cs->debug & L1_DEB_HSCX) @@ -211,23 +335,109 @@ debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0); - } - if (stat & 2) { - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0); +} + +static void +sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char ista, val, icnt = 5; + + if (!cs) { + printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n"); + return; + } + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); +Start_IPAC: + if (cs->debug & L1_DEB_IPAC) + debugl1(cs, "IPAC ISTA %02X", ista); + if (ista & 0x0f) { + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); + if (ista & 0x01) + val |= 0x01; + if (ista & 0x04) + val |= 0x02; + if (ista & 0x08) + val |= 0x04; + if (val) + hscx_int_main(cs, val); + } + if (ista & 0x20) { + val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80); + if (val) { + isac_interrupt(cs, val); + } + } + if (ista & 0x10) { + val = 0x01; + isac_interrupt(cs, val); } + ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); + if ((ista & 0x3f) && icnt) { + icnt--; + goto Start_IPAC; + } + if (!icnt) + printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); +} + +static void +sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) +{ + struct IsdnCardState *cs = dev_id; + u_char val; + int cnt = 5; + + if (!cs) { + printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n"); + return; + } + + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); + Start_ISAR: + if (val & ISAR_IRQSTA) + isar_int_main(cs); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + Start_ISAC: + if (val) + isac_interrupt(cs, val); + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); + if ((val & ISAR_IRQSTA) && --cnt) { + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "ISAR IntStat after IntRoutine"); + goto Start_ISAR; + } + val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); + if (val && --cnt) { + if (cs->debug & L1_DEB_ISAC) + debugl1(cs, "ISAC IntStat after IntRoutine"); + goto Start_ISAC; + } + if (!cnt) + printk(KERN_WARNING "Sedlbauer IRQ LOOP\n"); + + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK); } void release_io_sedlbauer(struct IsdnCardState *cs) { - int bytecnt = 8; + int bytecnt = (cs->subtyp == SEDL_SPEED_FAX) ? 16 : 8; + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + bytecnt = 256; + } if (cs->hw.sedl.cfg_reg) release_region(cs->hw.sedl.cfg_reg, bytecnt); } @@ -237,16 +447,36 @@ { long flags; - if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA) { - byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ - save_flags(flags); - sti(); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - restore_flags(flags); + printk(KERN_INFO "Sedlbauer: resetting card\n"); + + if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && + (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) { + if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); + writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); + restore_flags(flags); + } else { + byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ + save_flags(flags); + sti(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((10*HZ)/1000); + restore_flags(flags); + } } } @@ -260,95 +490,274 @@ case CARD_RELEASE: release_io_sedlbauer(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &sedlbauer_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + clear_pending_isac_ints(cs); + writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, + ISAR_IRQBIT, 0); + initisac(cs); + initisar(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + /* RESET Receiver and Transmitter */ + cs->writeisac(cs, ISAC_CMDR, 0x41); + } else { + inithscxisac(cs, 3); + } return(0); case CARD_TEST: return(0); + case CARD_LOAD_FIRM: + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + if (isar_load_firmware(cs, arg)) + return(1); + else + ll_run(cs); + } + return(0); } return(0); } + +#ifdef SEDLBAUER_PCI +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_sedl __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif +#endif + __initfunc(int setup_sedlbauer(struct IsdnCard *card)) { - int bytecnt; + int bytecnt, ver, val; struct IsdnCardState *cs = card->cs; char tmp[64]; strcpy(tmp, Sedlbauer_revision); printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ == ISDN_CTYPE_SEDLBAUER) { - cs->subtyp = SEDL_SPEED_CARD; + cs->subtyp = SEDL_SPEED_CARD_WIN; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { cs->subtyp = SEDL_SPEED_STAR; + cs->hw.sedl.bus = SEDL_BUS_PCMCIA; + cs->hw.sedl.chip = SEDL_CHIP_TEST; + } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { + cs->subtyp = SEDL_SPEED_FAX; + cs->hw.sedl.bus = SEDL_BUS_ISA; + cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; } else return (0); bytecnt = 8; - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->subtyp == SEDL_SPEED_STAR) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_PCMCIA_RESET; + if (card->para[1]) { + cs->hw.sedl.cfg_reg = card->para[1]; + cs->irq = card->para[0]; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + bytecnt = 16; + } } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_RESET_OFF; - } - - /* In case of the sedlbauer pcmcia card, this region is in use, +/* Probe for Sedlbauer speed pci */ +#if SEDLBAUER_PCI +#if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "FritzPCI: no PCI bus present\n"); + return(0); + } + if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER, + PCI_SPEEDPCI_ID, dev_sedl))) { + cs->irq = dev_sedl->irq; + if (!cs->irq) { + printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.sedl.cfg_reg = dev_sedl->base_address[0] & + PCI_BASE_ADDRESS_IO_MASK; + } else { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } +#else + for (; pci_index < 255; pci_index++) { + unsigned char pci_bus, pci_device_fn; + unsigned int ioaddr; + unsigned char irq; + + if (pcibios_find_device (PCI_VENDOR_SEDLBAUER, + PCI_SPEEDPCI_ID, pci_index, + &pci_bus, &pci_device_fn) != 0) { + continue; + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &irq); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &ioaddr); + cs->irq = irq; + cs->hw.sedl.cfg_reg = ioaddr & PCI_BASE_ADDRESS_IO_MASK; + if (!cs->hw.sedl.cfg_reg) { + printk(KERN_WARNING "Sedlbauer: No IO-Adr for PCI card found\n"); + return(0); + } + break; + } + if (pci_index == 255) { + printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); + return(0); + } + pci_index++; +#endif /* COMPAT_HAS_NEW_PCI */ + cs->irq_flags |= SA_SHIRQ; + cs->hw.sedl.bus = SEDL_BUS_PCI; + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + cs->subtyp = SEDL_SPEED_PCI; + bytecnt = 256; + byteout(cs->hw.sedl.cfg_reg, 0xff); + byteout(cs->hw.sedl.cfg_reg, 0x00); + byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd); + byteout(cs->hw.sedl.cfg_reg+ 5, 0x02); +#else + printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n"); + return (0); +#endif /* CONFIG_PCI */ +#endif /* SEDLBAUER_PCI */ + } + + /* In case of the sedlbauer pcmcia card, this region is in use, reserved for us by the card manager. So we do not check it here, it would fail. */ - if (cs->typ != ISDN_CTYPE_SEDLBAUER_PCMCIA && - check_region((cs->hw.sedl.cfg_reg), bytecnt)) { + if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && + check_region((cs->hw.sedl.cfg_reg), bytecnt)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - return (0); + "HiSax: %s config port %x-%x already in use\n", + CardType[card->typ], + cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt); + return (0); } else { request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn"); } printk(KERN_INFO - "Sedlbauer: defined at 0x%x IRQ %d\n", + "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n", cs->hw.sedl.cfg_reg, + cs->hw.sedl.cfg_reg + bytecnt, cs->irq); - printk(KERN_WARNING - "Sedlbauer %s uses ports 0x%x-0x%x\n", - Sedlbauer_Types[cs->subtyp], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - printk(KERN_INFO "Sedlbauer: resetting card\n"); - reset_sedlbauer(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; cs->BC_Read_Reg = &ReadHSCX; cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Sedl_card_msg; - ISACVersion(cs, "Sedlbauer:"); - if (HscxVersion(cs, "Sedlbauer:")) { - printk(KERN_WARNING - "Sedlbauer: wrong HSCX versions check IO address\n"); - release_io_sedlbauer(cs); - return (0); + +/* + * testing ISA and PCMCIA Cards for IPAC, default is ISAC + * do not test for PCI card, because ports are different + * and PCI card uses only IPAC (for the moment) + */ + if (cs->hw.sedl.bus != SEDL_BUS_PCI) { + val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, + cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); + if (val == 1) { + /* IPAC */ + cs->subtyp = SEDL_SPEED_WIN2_PC104; + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->subtyp = SEDL_SPEED_STAR2; + } + cs->hw.sedl.chip = SEDL_CHIP_IPAC; + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { + cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; + } + } + } + +/* + * hw.sedl.chip is now properly set + */ + printk(KERN_INFO "Sedlbauer: %s detected\n", + Sedlbauer_Types[cs->subtyp]); + + + if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { + /* IPAC */ + if (cs->hw.sedl.bus == SEDL_BUS_PCI) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + } + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &sedlbauer_interrupt_ipac; + + val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID); + printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); + reset_sedlbauer(cs); + } else { + /* ISAC_HSCX oder ISAC_ISAR */ + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF; + cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; + cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; + test_and_set_bit(HW_ISAR, &cs->HW_Flags); + cs->irq_func = &sedlbauer_interrupt_isar; + + ISACVersion(cs, "Sedlbauer:"); + + cs->BC_Read_Reg = &ReadISAR; + cs->BC_Write_Reg = &WriteISAR; + cs->BC_Send_Data = &isar_fill_fifo; + ver = ISARVersion(cs, "Sedlbauer:"); + if (ver < 0) { + printk(KERN_WARNING + "Sedlbauer: wrong ISAR version (ret = %d)\n", ver); + release_io_sedlbauer(cs); + return (0); + } + } else { + if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; + } else { + cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; + cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; + cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; + } + cs->irq_func = &sedlbauer_interrupt; + ISACVersion(cs, "Sedlbauer:"); + + if (HscxVersion(cs, "Sedlbauer:")) { + printk(KERN_WARNING + "Sedlbauer: wrong HSCX versions check IO address\n"); + release_io_sedlbauer(cs); + return (0); + } + reset_sedlbauer(cs); + } } return (1); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.2.10/linux/drivers/isdn/hisax/sportster.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/sportster.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: sportster.c,v 1.5 1998/02/02 13:29:46 keil Exp $ +/* $Id: sportster.c,v 1.9 1999/07/12 21:05:29 keil Exp $ * sportster.c low level stuff for USR Sportster internal TA * @@ -7,6 +7,19 @@ * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation * * $Log: sportster.c,v $ + * Revision 1.9 1999/07/12 21:05:29 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.8 1999/07/01 08:12:10 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.7 1998/11/15 23:55:22 keil + * changes from 2.0 + * + * Revision 1.6 1998/04/15 16:44:35 keil + * new init code + * * Revision 1.5 1998/02/02 13:29:46 keil * fast io * @@ -30,7 +43,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.5 $"; +const char *sportster_revision = "$Revision: 1.9 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -165,11 +178,11 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout((10*HZ)/1000); cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -183,16 +196,11 @@ case CARD_RELEASE: release_io_sportster(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &sportster_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 1); cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); + inithscxisac(cs, 2); return(0); case CARD_TEST: return(0); @@ -278,6 +286,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Sportster_card_msg; + cs->irq_func = &sportster_interrupt; ISACVersion(cs, "Sportster:"); if (HscxVersion(cs, "Sportster:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.2.10/linux/drivers/isdn/hisax/tei.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/tei.c Mon Aug 9 12:04:39 1999 @@ -1,12 +1,37 @@ -/* $Id: tei.c,v 2.7 1998/02/12 23:08:11 keil Exp $ +/* $Id: tei.c,v 2.12 1999/07/01 08:12:11 keil Exp $ - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * + * This file is (c) under GNU PUBLIC LICENSE + * For changes and modifications please read + * ../../../Documentation/isdn/HiSax.cert + * * Thanks to Jan den Ouden * Fritz Elfert * * $Log: tei.c,v $ + * Revision 2.12 1999/07/01 08:12:11 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.11 1998/11/15 23:55:24 keil + * changes from 2.0 + * + * Revision 2.10 1998/05/25 14:08:10 keil + * HiSax 3.0 + * fixed X.75 and leased line to work again + * Point2Point and fixed TEI are runtime options now: + * hisaxctrl 7 1 set PTP + * hisaxctrl 8 + * set fixed TEI to TEIVALUE (0-63) + * + * Revision 2.9 1998/05/25 12:58:23 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.8 1998/03/07 22:57:07 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.7 1998/02/12 23:08:11 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -50,7 +75,7 @@ #include "isdnl2.h" #include -const char *tei_revision = "$Revision: 2.7 $"; +const char *tei_revision = "$Revision: 2.12 $"; #define ID_REQUEST 1 #define ID_ASSIGNED 2 @@ -141,6 +166,7 @@ printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); return; } + SET_SKB_FREE(skb); bp = skb_put(skb, 3); bp[0] = (TEI_SAPI << 2); bp[1] = (GROUP_TEI << 1) | 0x1; @@ -151,26 +177,24 @@ bp[2] = ri & 0xff; bp[3] = m_id; bp[4] = (tei << 1) | 1; - st->l2.l2l1(st, PH_DATA_REQ, skb); + st->l2.l2l1(st, PH_DATA | REQUEST, skb); } static void tei_id_request(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; if (st->l2.tei != -1) { - sprintf(tmp, "assign request for allready asigned tei %d", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign request for allready asigned tei %d", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); return; } st->ma.ri = random_ri(); - if (st->ma.debug) { - sprintf(tmp, "assign request ri %d", st->ma.ri); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign request ri %d", st->ma.ri); put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1); @@ -184,26 +208,24 @@ struct sk_buff *skb = arg; struct IsdnCardState *cs; int ri, tei; - char tmp[64]; ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity assign ri %d tei %d", ri, tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity assign ri %d tei %d", ri, tei); if ((ost = findtei(st, tei))) { /* same tei is in use */ if (ri != ost->ma.ri) { - sprintf(tmp, "possible duplicate assignment tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - ost->l2.l2tei(ost, MDL_ERROR_REQ, NULL); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "possible duplicate assignment tei %d", tei); + ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL); } } else if (ri == st->ma.ri) { FsmDelTimer(&st->ma.t202, 1); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN_REQ, NULL); + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); } } @@ -213,14 +235,12 @@ struct PStack *st = fi->userdata; struct sk_buff *skb = arg; int ri, tei; - char tmp[64]; ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity denied ri %d tei %d", ri, tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity denied ri %d tei %d", ri, tei); } static void @@ -229,13 +249,11 @@ struct PStack *st = fi->userdata; struct sk_buff *skb = arg; int tei; - char tmp[64]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity check req tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity check req tei %d", tei); if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 4); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); @@ -250,19 +268,17 @@ struct sk_buff *skb = arg; struct IsdnCardState *cs; int tei; - char tmp[64]; tei = skb->data[4] >> 1; - if (st->ma.debug) { - sprintf(tmp, "identity remove tei %d", tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "identity remove tei %d", tei); if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 5); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->ma.manl2(st, MDL_REMOVE_REQ, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); } } @@ -270,12 +286,10 @@ tei_id_verify(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; - if (st->ma.debug) { - sprintf(tmp, "id verify request for tei %d", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "id verify request for tei %d", st->l2.tei); put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2); @@ -286,24 +300,21 @@ tei_id_req_tout(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; struct IsdnCardState *cs; if (--st->ma.N202) { st->ma.ri = random_ri(); - if (st->ma.debug) { - sprintf(tmp, "assign req(%d) ri %d", - 4 - st->ma.N202, st->ma.ri); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "assign req(%d) ri %d", 4 - st->ma.N202, + st->ma.ri); put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); } else { - sprintf(tmp, "assign req failed"); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - st->ma.manl2(st, MDL_ERROR_IND, 0); + st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); + st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -312,23 +323,21 @@ tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - char tmp[64]; struct IsdnCardState *cs; if (--st->ma.N202) { - if (st->ma.debug) { - sprintf(tmp, "id verify req(%d) for tei %d", + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "id verify req(%d) for tei %d", 3 - st->ma.N202, st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4); } else { - sprintf(tmp, "verify req for tei %d failed", st->l2.tei); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - st->ma.manl2(st, MDL_REMOVE_REQ, 0); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "verify req for tei %d failed", st->l2.tei); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE_REQ, NULL); + cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); } } @@ -338,31 +347,34 @@ { struct sk_buff *skb = arg; int mt; - char tmp[64]; - if (pr == PH_DATA_IND) { + if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { + idev_kfree_skb(skb, FREE_READ); + return; + } + + if (pr == (PH_DATA | INDICATION)) { if (skb->len < 3) { - sprintf(tmp, "short mgr frame %d/3", skb->len); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } else if (((skb->data[0] >> 2) != TEI_SAPI) || - ((skb->data[1] >> 1) != GROUP_TEI)) { - sprintf(tmp, "wrong mgr sapi/tei %x/%x", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "short mgr frame %ld/3", skb->len); + } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) || + (skb->data[1] != ((GROUP_TEI << 1) | 1))) { + st->ma.tei_m.printdebug(&st->ma.tei_m, + "wrong mgr sapi/tei %x/%x", skb->data[0], skb->data[1]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); } else if ((skb->data[2] & 0xef) != UI) { - sprintf(tmp, "mgr frame is not ui %x", - skb->data[2]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "mgr frame is not ui %x", skb->data[2]); } else { skb_pull(skb, 3); if (skb->len < 5) { - sprintf(tmp, "short mgr frame %d/5", skb->len); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "short mgr frame %ld/5", skb->len); } else if (skb->data[0] != TEI_ENTITY_ID) { /* wrong management entity identifier, ignore */ - sprintf(tmp, "tei handler wrong entity id %x\n", + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong entity id %x", skb->data[0]); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); } else { mt = skb->data[3]; if (mt == ID_ASSIGNED) @@ -374,36 +386,39 @@ else if (mt == ID_REMOVE) FsmEvent(&st->ma.tei_m, EV_REMOVE, skb); else { - sprintf(tmp, "tei handler wrong mt %x\n", - mt); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong mt %x\n", mt); } } } } else { - sprintf(tmp, "tei handler wrong pr %x\n", pr); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); + st->ma.tei_m.printdebug(&st->ma.tei_m, + "tei handler wrong pr %x\n", pr); } - dev_kfree_skb(skb); + idev_kfree_skb(skb, FREE_READ); } static void tei_l2tei(struct PStack *st, int pr, void *arg) { + struct IsdnCardState *cs; + + if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { + if (pr == (MDL_ASSIGN | INDICATION)) { + if (st->ma.debug) + st->ma.tei_m.printdebug(&st->ma.tei_m, + "fixed assign tei %d", st->l2.tei); + st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); + cs = (struct IsdnCardState *) st->l1.hardware; + cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); + } + return; + } switch (pr) { - case (MDL_ASSIGN_IND): -#ifdef TEI_FIXED - if (st->ma.debug) { - char tmp[64]; - sprintf(tmp, "fixed assign tei %d", TEI_FIXED); - st->ma.tei_m.printdebug(&st->ma.tei_m, tmp); - } - st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) TEI_FIXED); -#else + case (MDL_ASSIGN | INDICATION): FsmEvent(&st->ma.tei_m, EV_IDREQ, arg); -#endif break; - case (MDL_ERROR_REQ): + case (MDL_ERROR | REQUEST): FsmEvent(&st->ma.tei_m, EV_VERIFY, arg); break; default: @@ -412,14 +427,14 @@ } static void -tei_debug(struct FsmInst *fi, char *s) +tei_debug(struct FsmInst *fi, char *fmt, ...) { + va_list args; struct PStack *st = fi->userdata; - char tm[32], str[256]; - jiftime(tm, jiffies); - sprintf(str, "%s Tei %s\n", tm, s); - HiSax_putstatus(st->l1.hardware, str); + va_start(args, fmt); + VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args); + va_end(args); } void @@ -439,9 +454,8 @@ } void -init_tei(struct IsdnCardState *sp, int protocol) +init_tei(struct IsdnCardState *cs, int protocol) { - } void diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.2.10/linux/drivers/isdn/hisax/teleint.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/teleint.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,24 @@ -/* $Id: teleint.c,v 1.5 1998/02/02 13:40:47 keil Exp $ +/* $Id: teleint.c,v 1.9 1999/07/12 21:05:30 keil Exp $ * teleint.c low level stuff for TeleInt isdn cards * - * Author Karsten Keil (keil@temic-ech.spacenet.de) + * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: teleint.c,v $ + * Revision 1.9 1999/07/12 21:05:30 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 1.8 1999/07/01 08:12:12 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 1.7 1998/11/15 23:55:26 keil + * changes from 2.0 + * + * Revision 1.6 1998/04/15 16:45:31 keil + * new init code + * * Revision 1.5 1998/02/02 13:40:47 keil * fast io * @@ -32,7 +45,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.5 $"; +const char *TeleInt_revision = "$Revision: 1.9 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -64,17 +77,20 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) { register u_char ret; - int max_delay = 2000; + register int max_delay = 20000; + register int i; + byteout(ale, off); - - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) + for (i = 0; ihw.hfc.cip = reg; byteout(cs->hw.hfc.addr | 1, reg); ret = bytein(cs->hw.hfc.addr); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "hfc RD %02x %02x", reg, ret); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "hfc RD %02x %02x", reg, ret); } else ret = bytein(cs->hw.hfc.addr | 1); return (ret); @@ -174,18 +190,15 @@ cs->hw.hfc.cip = reg; if (data) byteout(cs->hw.hfc.addr, value); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) { - char tmp[32]; - sprintf(tmp, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); - debugl1(cs, tmp); - } + if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) + debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); } static void TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; if (!cs) { printk(KERN_WARNING "TeleInt: Spurious interrupt!\n"); @@ -193,20 +206,16 @@ } val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); if (val) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 2) { - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); - } + writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); + writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); } static void @@ -246,11 +255,11 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3); + schedule_timeout((30*HZ)/1000); cs->hw.hfc.cirm &= ~HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout((10*HZ)/1000); restore_flags(flags); } @@ -264,13 +273,13 @@ case CARD_RELEASE: release_io_TeleInt(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &TeleInt_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: inithfc(cs); clear_pending_isac_ints(cs); initisac(cs); + /* Reenable all IRQ */ + cs->writeisac(cs, ISAC_MASK, 0); + cs->writeisac(cs, ISAC_CMDR, 0x41); cs->hw.hfc.timer.expires = jiffies + 1; add_timer(&cs->hw.hfc.timer); return(0); @@ -356,6 +365,7 @@ cs->BC_Read_Reg = &ReadHFC; cs->BC_Write_Reg = &WriteHFC; cs->cardmsg = &TeleInt_card_msg; + cs->irq_func = &TeleInt_interrupt; ISACVersion(cs, "TeleInt:"); return (1); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.2.10/linux/drivers/isdn/hisax/teles0.c Wed Apr 1 16:21:02 1998 +++ linux/drivers/isdn/hisax/teles0.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 2.6 1998/02/03 23:27:47 keil Exp $ +/* $Id: teles0.c,v 2.9 1999/07/12 21:05:31 keil Exp $ * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden @@ -10,6 +10,16 @@ * Beat Doebeli * * $Log: teles0.c,v $ + * Revision 2.9 1999/07/12 21:05:31 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.8 1998/04/15 16:44:28 keil + * new init code + * + * Revision 2.7 1998/03/07 22:57:08 tsbogend + * made HiSax working on Linux/Alpha + * * Revision 2.6 1998/02/03 23:27:47 keil * IRQ 9 * @@ -48,7 +58,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.6 $"; +const char *teles0_revision = "$Revision: 2.9 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -62,7 +72,7 @@ static inline void writeisac(unsigned int adr, u_char off, u_char data) { - writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); + writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); } @@ -77,14 +87,14 @@ writehscx(unsigned int adr, int hscx, u_char off, u_char data) { writeb(data, adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); + ((off & 1) ? 0x1ff : 0) + off); mb(); } static inline void read_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + 0x100); + register u_char *ad = (u_char *) ((long)adr + 0x100); for (i = 0; i < size; i++) data[i] = readb(ad); } @@ -93,16 +103,17 @@ write_fifo_isac(unsigned int adr, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + 0x100); - for (i = 0; i < size; i++) - writeb(data[i], ad); + register u_char *ad = (u_char *) ((long)adr + 0x100); + for (i = 0; i < size; i++) { + writeb(data[i], ad); mb(); + } } static inline void read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { register int i; - register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); + register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); for (i = 0; i < size; i++) data[i] = readb(ad); } @@ -111,9 +122,10 @@ write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) { int i; - register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180)); - for (i = 0; i < size; i++) - writeb(data[i], ad); + register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180)); + for (i = 0; i < size; i++) { + writeb(data[i], ad); mb(); + } } /* Interface functions */ @@ -169,7 +181,7 @@ teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; int count = 0; if (!cs) { @@ -178,39 +190,31 @@ } val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readisac(cs->hw.teles0.membase, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } count++; val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); - if (val && count < 20) { + if (val && count < 5) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX IntStat after IntRoutine"); goto Start_HSCX; } val = readisac(cs->hw.teles0.membase, ISAC_ISTA); - if (val && count < 20) { + if (val && count < 5) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC IntStat after IntRoutine"); goto Start_ISAC; } - if (stat & 1) { - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); - } - if (stat & 2) { - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); - } + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); } void @@ -264,9 +268,9 @@ byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); HZDELAY(HZ / 10 + 1); } - writeb(0, cs->hw.teles0.membase + 0x80); + writeb(0, cs->hw.teles0.membase + 0x80); mb(); HZDELAY(HZ / 5 + 1); - writeb(1, cs->hw.teles0.membase + 0x80); + writeb(1, cs->hw.teles0.membase + 0x80); mb(); HZDELAY(HZ / 5 + 1); restore_flags(flags); return(0); @@ -282,14 +286,8 @@ case CARD_RELEASE: release_io_teles0(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &teles0_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -377,6 +375,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Teles_card_msg; + cs->irq_func = &teles0_interrupt; ISACVersion(cs, "Teles0:"); if (HscxVersion(cs, "Teles0:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.2.10/linux/drivers/isdn/hisax/teles3.c Thu May 14 18:44:53 1998 +++ linux/drivers/isdn/hisax/teles3.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 2.7 1998/02/02 13:29:48 keil Exp $ +/* $Id: teles3.c,v 2.12 1999/07/12 21:05:32 keil Exp $ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * @@ -11,6 +11,22 @@ * Beat Doebeli * * $Log: teles3.c,v $ + * Revision 2.12 1999/07/12 21:05:32 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.11 1999/07/01 08:12:14 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.10 1999/02/15 14:37:15 cpetig + * oops, missed something in last commit + * + * Revision 2.9 1999/02/15 14:11:02 cpetig + * fixed a bug with Teles PCMCIA, it doesn't have a config register + * + * Revision 2.8 1998/04/15 16:44:30 keil + * new init code + * * Revision 2.7 1998/02/02 13:29:48 keil * fast io * @@ -69,7 +85,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.7 $"; +const char *teles3_revision = "$Revision: 2.12 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -151,9 +167,9 @@ static void teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs) { -#define MAXCOUNT 20 +#define MAXCOUNT 5 struct IsdnCardState *cs = dev_id; - u_char val, stat = 0; + u_char val; int count = 0; if (!cs) { @@ -162,16 +178,12 @@ } val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); Start_HSCX: - if (val) { + if (val) hscx_int_main(cs, val); - stat |= 1; - } val = readreg(cs->hw.teles3.isac, ISAC_ISTA); Start_ISAC: - if (val) { + if (val) isac_interrupt(cs, val); - stat |= 2; - } count++; val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); if (val && count < MAXCOUNT) { @@ -187,16 +199,12 @@ } if (count >= MAXCOUNT) printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); - if (stat & 1) { - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); - } - if (stat & 2) { - writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); - } + writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); + writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); + writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); + writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); + writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); } inline static void @@ -213,9 +221,9 @@ void release_io_teles3(struct IsdnCardState *cs) { - if (cs->typ == ISDN_CTYPE_TELESPCMCIA) - release_region(cs->hw.teles3.cfg_reg, 97); - else { + if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { + release_region(cs->hw.teles3.hscx[0], 97); + } else { if (cs->hw.teles3.cfg_reg) { if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { release_region(cs->hw.teles3.cfg_reg, 1); @@ -301,14 +309,8 @@ case CARD_RELEASE: release_io_teles3(cs); return(0); - case CARD_SETIRQ: - return(request_irq(cs->irq, &teles3_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); case CARD_INIT: - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); + inithscxisac(cs, 3); return(0); case CARD_TEST: return(0); @@ -342,7 +344,7 @@ cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - cs->hw.teles3.cfg_reg = card->para[1]; + cs->hw.teles3.cfg_reg = 0; cs->hw.teles3.hscx[0] = card->para[1] - 0x20; cs->hw.teles3.hscx[1] = card->para[1]; cs->hw.teles3.isac = card->para[1] + 0x20; @@ -362,12 +364,12 @@ cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (check_region((cs->hw.teles3.cfg_reg), 97)) { + if (check_region((cs->hw.teles3.hscx[0]), 97)) { printk(KERN_WARNING "HiSax: %s ports %x-%x already in use\n", CardType[cs->typ], - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 96); + cs->hw.teles3.hscx[0], + cs->hw.teles3.hscx[0] + 96); return (0); } else request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA"); @@ -492,6 +494,7 @@ cs->BC_Write_Reg = &WriteHSCX; cs->BC_Send_Data = &hscx_fill_fifo; cs->cardmsg = &Teles_card_msg; + cs->irq_func = &teles3_interrupt; ISACVersion(cs, "Teles3:"); if (HscxVersion(cs, "Teles3:")) { printk(KERN_WARNING diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/teles3c.c linux/drivers/isdn/hisax/teles3c.c --- v2.2.10/linux/drivers/isdn/hisax/teles3c.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/hisax/teles3c.c Wed Dec 31 16:00:00 1969 @@ -1,196 +0,0 @@ -/* $Id: teles3c.c,v 1.2 1998/02/02 13:27:07 keil Exp $ - - * teles3c.c low level stuff for teles 16.3c - * - * Author Karsten Keil (keil@temic-ech.spacenet.de) - * - * - * $Log: teles3c.c,v $ - * Revision 1.2 1998/02/02 13:27:07 keil - * New - * - * - * - */ - -#define __NO_VERSION__ -#include "hisax.h" -#include "hfc_2bds0.h" -#include "isdnl1.h" - -extern const char *CardType[]; - -const char *teles163c_revision = "$Revision: 1.2 $"; - -static void -t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - struct IsdnCardState *cs = dev_id; - u_char val, stat; - char tmp[32]; - - if (!cs) { - printk(KERN_WARNING "teles3c: Spurious interrupt!\n"); - return; - } - if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & - (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { - val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "teles3c: stat(%02x) s1(%02x)", stat, val); - debugl1(cs, tmp); - } - hfc2bds0_interrupt(cs, val); - } else { - if (cs->debug & L1_DEB_ISAC) { - sprintf(tmp, "teles3c: irq_no_irq stat(%02x)", stat); - debugl1(cs, tmp); - } - } -} - -static void -t163c_Timer(struct IsdnCardState *cs) -{ - cs->hw.hfcD.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); - add_timer(&cs->hw.hfcD.timer); -*/ -} - -void -release_io_t163c(struct IsdnCardState *cs) -{ - release2bds0(cs); - del_timer(&cs->hw.hfcD.timer); - if (cs->hw.hfcD.addr) - release_region(cs->hw.hfcD.addr, 2); -} - -static void -reset_t163c(struct IsdnCardState *cs) -{ - long flags; - - printk(KERN_INFO "teles3c: resetting card\n"); - cs->hw.hfcD.cirm = HFCD_RESET | HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ - save_flags(flags); - sti(); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(3); - cs->hw.hfcD.cirm = HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - cs->hw.hfcD.cirm |= HFCD_INTB; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* INT B */ - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ - cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; - cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | - HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | - HFCD_INTS_DREC | HFCD_INTS_L1STATE; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcD.mst_m = 0; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, HFCD_MASTER); /* HFC Master */ - cs->hw.hfcD.sctrl = 0; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); - restore_flags(flags); -} - -static int -t163c_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - long flags; - char tmp[32]; - - if (cs->debug & L1_DEB_ISAC) { - - sprintf(tmp, "teles3c: card_msg %x", mt); - debugl1(cs, tmp); - } - switch (mt) { - case CARD_RESET: - reset_t163c(cs); - return(0); - case CARD_RELEASE: - release_io_t163c(cs); - return(0); - case CARD_SETIRQ: - cs->hw.hfcD.timer.expires = jiffies + 75; - add_timer(&cs->hw.hfcD.timer); - return(request_irq(cs->irq, &t163c_interrupt, - I4L_IRQ_FLAG, "HiSax", cs)); - case CARD_INIT: - init2bds0(cs); - save_flags(flags); - sti(); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((80*HZ)/1000); - cs->hw.hfcD.ctmt |= HFCD_TIM800; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - restore_flags(flags); - return(0); - case CARD_TEST: - return(0); - } - return(0); -} - -__initfunc(int -setup_t163c(struct IsdnCard *card)) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, teles163c_revision); - printk(KERN_INFO "HiSax: Teles 16.3c driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_TELES3C) - return (0); - cs->debug = 0xff; - cs->hw.hfcD.addr = card->para[1] & 0xfffe; - cs->irq = card->para[0]; - cs->hw.hfcD.cip = 0; - cs->hw.hfcD.int_s1 = 0; - cs->hw.hfcD.send = NULL; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfcD.bfifosize = 1024 + 512; - cs->hw.hfcD.dfifosize = 512; - cs->ph_state = 0; - cs->hw.hfcD.fifo = 255; - if (check_region((cs->hw.hfcD.addr), 2)) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.hfcD.addr, - cs->hw.hfcD.addr + 2); - return (0); - } else { - request_region(cs->hw.hfcD.addr, 2, "teles3c isdn"); - } - /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x56, cs->hw.hfcD.addr | 1); - printk(KERN_INFO - "teles3c: defined at 0x%x IRQ %d HZ %d\n", - cs->hw.hfcD.addr, - cs->irq, HZ); - - set_cs_func(cs); - cs->hw.hfcD.timer.function = (void *) t163c_Timer; - cs->hw.hfcD.timer.data = (long) cs; - init_timer(&cs->hw.hfcD.timer); - reset_t163c(cs); - cs->cardmsg = &t163c_card_msg; - return (1); -} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.2.10/linux/drivers/isdn/hisax/telespci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/telespci.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,406 @@ +/* $Id: telespci.c,v 2.7 1999/07/12 21:05:34 keil Exp $ + + * telespci.c low level stuff for Teles PCI isdn cards + * + * Author Ton van Rosmalen + * Karsten Keil (keil@temic-ech.spacenet.de) + * + * + * $Log: telespci.c,v $ + * Revision 2.7 1999/07/12 21:05:34 keil + * fix race in IRQ handling + * added watchdog for lost IRQs + * + * Revision 2.6 1999/07/01 08:12:15 keil + * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel + * + * Revision 2.5 1998/11/15 23:55:28 keil + * changes from 2.0 + * + * Revision 2.4 1998/10/05 09:38:08 keil + * Fix register addressing + * + * Revision 2.3 1998/05/25 12:58:26 keil + * HiSax golden code from certification, Don't use !!! + * No leased lines, no X75, but many changes. + * + * Revision 2.1 1998/04/15 16:38:23 keil + * Add S0Box and Teles PCI support + * + * + */ +#define __NO_VERSION__ +#include +#include "hisax.h" +#include "isac.h" +#include "hscx.h" +#include "isdnl1.h" +#include +#ifndef COMPAT_HAS_NEW_PCI +#include +#endif + +extern const char *CardType[]; +const char *telespci_revision = "$Revision: 2.7 $"; + +#define ZORAN_PO_RQ_PEN 0x02000000 +#define ZORAN_PO_WR 0x00800000 +#define ZORAN_PO_GID0 0x00000000 +#define ZORAN_PO_GID1 0x00100000 +#define ZORAN_PO_GREG0 0x00000000 +#define ZORAN_PO_GREG1 0x00010000 +#define ZORAN_PO_DMASK 0xFF + +#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) +#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) +#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) +#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0) +#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1) +#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1) + +#define ZORAN_WAIT_NOBUSY do { \ + portdata = readl(adr + 0x200); \ + } while (portdata & ZORAN_PO_RQ_PEN) + +static inline u_char +readisac(unsigned int adr, u_char off) +{ + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + + /* set address for ISAC */ + writel(WRITE_ADDR_ISAC | off, adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* read data from ISAC */ + writel(READ_DATA_ISAC, adr + 0x200); + ZORAN_WAIT_NOBUSY; + return((u_char)(portdata & ZORAN_PO_DMASK)); +} + +static inline void +writeisac(unsigned int adr, u_char off, u_char data) +{ + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + + /* set address for ISAC */ + writel(WRITE_ADDR_ISAC | off, adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* write data to ISAC */ + writel(WRITE_DATA_ISAC | data, adr + 0x200); + ZORAN_WAIT_NOBUSY; +} + +static inline u_char +readhscx(unsigned int adr, int hscx, u_char off) +{ + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + /* set address for HSCX */ + writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* read data from HSCX */ + writel(READ_DATA_HSCX, adr + 0x200); + ZORAN_WAIT_NOBUSY; + return ((u_char)(portdata & ZORAN_PO_DMASK)); +} + +static inline void +writehscx(unsigned int adr, int hscx, u_char off, u_char data) +{ + register unsigned int portdata; + + ZORAN_WAIT_NOBUSY; + /* set address for HSCX */ + writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200); + ZORAN_WAIT_NOBUSY; + + /* write data to HSCX */ + writel(WRITE_DATA_HSCX | data, adr + 0x200); + ZORAN_WAIT_NOBUSY; +} + +static inline void +read_fifo_isac(unsigned int adr, u_char * data, int size) +{ + register unsigned int portdata; + register int i; + + ZORAN_WAIT_NOBUSY; + /* read data from ISAC */ + for (i = 0; i < size; i++) { + /* set address for ISAC fifo */ + writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); + ZORAN_WAIT_NOBUSY; + writel(READ_DATA_ISAC, adr + 0x200); + ZORAN_WAIT_NOBUSY; + data[i] = (u_char)(portdata & ZORAN_PO_DMASK); + } +} + +static void +write_fifo_isac(unsigned int adr, u_char * data, int size) +{ + register unsigned int portdata; + register int i; + + ZORAN_WAIT_NOBUSY; + /* write data to ISAC */ + for (i = 0; i < size; i++) { + /* set address for ISAC fifo */ + writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); + ZORAN_WAIT_NOBUSY; + writel(WRITE_DATA_ISAC | data[i], adr + 0x200); + ZORAN_WAIT_NOBUSY; + } +} + +static inline void +read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +{ + register unsigned int portdata; + register int i; + + ZORAN_WAIT_NOBUSY; + /* read data from HSCX */ + for (i = 0; i < size; i++) { + /* set address for HSCX fifo */ + writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); + ZORAN_WAIT_NOBUSY; + writel(READ_DATA_HSCX, adr + 0x200); + ZORAN_WAIT_NOBUSY; + data[i] = (u_char) (portdata & ZORAN_PO_DMASK); + } +} + +static inline void +write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size) +{ + unsigned int portdata; + register int i; + + ZORAN_WAIT_NOBUSY; + /* write data to HSCX */ + for (i = 0; i < size; i++) { + /* set address for HSCX fifo */ + writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200); + ZORAN_WAIT_NOBUSY; + writel(WRITE_DATA_HSCX | data[i], adr + 0x200); + ZORAN_WAIT_NOBUSY; + udelay(10); + } +} + +/* Interface functions */ + +static u_char +ReadISAC(struct IsdnCardState *cs, u_char offset) +{ + return (readisac(cs->hw.teles0.membase, offset)); +} + +static void +WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) +{ + writeisac(cs->hw.teles0.membase, offset, value); +} + +static void +ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + read_fifo_isac(cs->hw.teles0.membase, data, size); +} + +static void +WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) +{ + write_fifo_isac(cs->hw.teles0.membase, data, size); +} + +static u_char +ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) +{ + return (readhscx(cs->hw.teles0.membase, hscx, offset)); +} + +static void +WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) +{ + writehscx(cs->hw.teles0.membase, hscx, offset, value); +} + +/* + * fast interrupt HSCX stuff goes here + */ + +#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) +#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) +#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) +#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) + +#include "hscx_irq.c" + +static void +telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs) +{ +#define MAXCOUNT 20 + struct IsdnCardState *cs = dev_id; + u_char val; + + if (!cs) { + printk(KERN_WARNING "TelesPCI: Spurious interrupt!\n"); + return; + } + val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); + if (val) + hscx_int_main(cs, val); + val = readisac(cs->hw.teles0.membase, ISAC_ISTA); + if (val) + isac_interrupt(cs, val); + /* Clear interrupt register for Zoran PCI controller */ + writel(0x70000000, cs->hw.teles0.membase + 0x3C); + + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); + writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); + writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); +} + +void +release_io_telespci(struct IsdnCardState *cs) +{ + iounmap((void *)cs->hw.teles0.membase); +} + +static int +TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) +{ + switch (mt) { + case CARD_RESET: + return(0); + case CARD_RELEASE: + release_io_telespci(cs); + return(0); + case CARD_INIT: + inithscxisac(cs, 3); + return(0); + case CARD_TEST: + return(0); + } + return(0); +} + +#ifdef COMPAT_HAS_NEW_PCI +static struct pci_dev *dev_tel __initdata = NULL; +#else +static int pci_index __initdata = 0; +#endif + +__initfunc(int +setup_telespci(struct IsdnCard *card)) +{ + struct IsdnCardState *cs = card->cs; + char tmp[64]; +#ifndef COMPAT_HAS_NEW_PCI + u_char pci_bus, pci_device_fn, pci_irq; + u_int pci_memaddr; + u_char found = 0; +#endif + + strcpy(tmp, telespci_revision); + printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); + if (cs->typ != ISDN_CTYPE_TELESPCI) + return (0); +#if CONFIG_PCI +#ifdef COMPAT_HAS_NEW_PCI + if (!pci_present()) { + printk(KERN_ERR "TelesPCI: no PCI bus present\n"); + return(0); + } + if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) { + cs->irq = dev_tel->irq; + if (!cs->irq) { + printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); + return(0); + } + cs->hw.teles0.membase = (u_int) ioremap(dev_tel->base_address[0], + PAGE_SIZE); + printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n", + dev_tel->base_address[0], dev_tel->irq); + } else { + printk(KERN_WARNING "TelesPCI: No PCI card found\n"); + return(0); + } +#else + for (; pci_index < 0xff; pci_index++) { + if (pcibios_find_device (0x11DE, 0x6120, + pci_index, &pci_bus, &pci_device_fn) + == PCIBIOS_SUCCESSFUL) { + found = 1; + } else { + break; + } + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_memaddr); + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq); + + printk(KERN_INFO "Found: Zoran, base-address: 0x%x," + " irq: 0x%x\n", pci_memaddr, pci_irq); + break; + } + if (!found) { + printk(KERN_WARNING "TelesPCI: No PCI card found\n"); + return(0); + } + pci_index++; + cs->irq = pci_irq; + cs->hw.teles0.membase = (u_int) vremap(pci_memaddr, PAGE_SIZE); +#endif /* COMPAT_HAS_NEW_PCI */ +#else + printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n"); + printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n"); + return (0); +#endif /* CONFIG_PCI */ + + /* Initialize Zoran PCI controller */ + writel(0x00000000, cs->hw.teles0.membase + 0x28); + writel(0x01000000, cs->hw.teles0.membase + 0x28); + writel(0x01000000, cs->hw.teles0.membase + 0x28); + writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); + writel(0x70000000, cs->hw.teles0.membase + 0x3C); + writel(0x61000000, cs->hw.teles0.membase + 0x40); + /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ + + printk(KERN_INFO + "HiSax: %s config irq:%d mem:%x\n", + CardType[cs->typ], cs->irq, + cs->hw.teles0.membase); + + cs->readisac = &ReadISAC; + cs->writeisac = &WriteISAC; + cs->readisacfifo = &ReadISACfifo; + cs->writeisacfifo = &WriteISACfifo; + cs->BC_Read_Reg = &ReadHSCX; + cs->BC_Write_Reg = &WriteHSCX; + cs->BC_Send_Data = &hscx_fill_fifo; + cs->cardmsg = &TelesPCI_card_msg; + cs->irq_func = &telespci_interrupt; + cs->irq_flags |= SA_SHIRQ; + ISACVersion(cs, "TelesPCI:"); + if (HscxVersion(cs, "TelesPCI:")) { + printk(KERN_WARNING + "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); + release_io_telespci(cs); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.2.10/linux/drivers/isdn/icn/icn.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/icn/icn.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.49 1998/02/13 11:14:15 keil Exp $ +/* $Id: icn.c,v 1.57 1999/07/06 16:15:30 detabc Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,29 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.57 1999/07/06 16:15:30 detabc + * remove unused messages + * + * Revision 1.56 1999/04/12 13:15:07 fritz + * Fixed a cast. + * + * Revision 1.55 1999/04/12 12:34:02 fritz + * Changes from 2.0 tree. + * + * Revision 1.54 1999/01/05 18:29:39 he + * merged remaining schedule_timeout() changes from 2.1.127 + * + * Revision 1.53 1998/06/17 19:51:28 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.52 1998/05/20 19:29:58 tsbogend + * fixed bug introduced by changes for new BSENT callback + * + * Revision 1.51 1998/03/07 22:29:55 fritz + * Adapted Detlef's chenges for 2.1. + * * Revision 1.49 1998/02/13 11:14:15 keil * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() * @@ -209,7 +232,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.49 $"; +*revision = "$Revision: 1.57 $"; static int icn_addcard(int, char *, char *); @@ -232,10 +255,10 @@ cli(); card->xlen[channel] = 0; card->sndcount[channel] = 0; - if (card->xskb[channel]) { + if ((skb = card->xskb[channel])) { card->xskb[channel] = NULL; restore_flags(flags); - dev_kfree_skb(card->xskb[channel]); + dev_kfree_skb(skb); } else restore_flags(flags); } @@ -529,6 +552,11 @@ cmd.parm.length = card->xlen[channel]; card->interface.statcallb(&cmd); } + } else { + save_flags(flags); + cli(); + card->xskb[channel] = skb; + restore_flags(flags); } card->xmit_lock[channel] = 0; if (!icn_trymaplock_channel(card, mch)) @@ -580,8 +608,11 @@ { {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ - {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ - {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ + /* + ** add d-channel connect and disconnect support to link-level + */ + {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */ + {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */ {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ @@ -630,7 +661,33 @@ cmd.driver = card->myid; cmd.arg = channel; switch (action) { + case 11: + save_flags(flags); + cli(); + icn_free_queue(card,channel); + card->rcvidx[channel] = 0; + + if (card->flags & + ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) { + + isdn_ctrl ncmd; + + card->flags &= ~((channel)? + ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE); + + memset(&ncmd, 0, sizeof(ncmd)); + + ncmd.driver = card->myid; + ncmd.arg = channel; + ncmd.command = ISDN_STAT_BHUP; + restore_flags(flags); + card->interface.statcallb(&cmd); + } else + restore_flags(flags); + + break; case 1: + icn_free_queue(card,channel); card->flags |= (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE; break; @@ -1539,7 +1596,7 @@ c->parm.num[0] ? "N" : "ALL", c->parm.num); } else sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : "0123456789"); + c->parm.num[0] ? (char *)(c->parm.num) : "0123456789"); i = icn_writecmd(cbuf, strlen(cbuf), 0, card); } break; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.2.10/linux/drivers/isdn/icn/icn.h Thu Jan 7 08:46:59 1999 +++ linux/drivers/isdn/icn/icn.h Mon Aug 9 12:04:39 1999 @@ -318,9 +318,9 @@ #ifdef MODULE MODULE_AUTHOR("Fritz Elfert"); MODULE_PARM(portbase, "i"); -MODULE_PARM_DESC(portbase, "Port address of first card"); +MODULE_PARM_DESC(portbase, "Port adress of first card"); MODULE_PARM(membase, "i"); -MODULE_PARM_DESC(membase, "Shared memory address of all cards"); +MODULE_PARM_DESC(membase, "Shared memory adress of all cards"); MODULE_PARM(icn_id, "s"); MODULE_PARM_DESC(icn_id, "ID-String of first card"); MODULE_PARM(icn_id2, "s"); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.2.10/linux/drivers/isdn/isdn_audio.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/isdn_audio.c Mon Aug 9 12:04:39 1999 @@ -1,9 +1,10 @@ -/* $Id: isdn_audio.c,v 1.10 1998/02/20 17:09:40 fritz Exp $ +/* $Id: isdn_audio.c,v 1.14 1999/07/11 17:14:06 armin Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) + * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) * * 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 @@ -20,6 +21,26 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.14 1999/07/11 17:14:06 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * + * Revision 1.13 1999/04/12 12:33:09 fritz + * Changes from 2.0 tree. + * + * Revision 1.12 1998/07/26 18:48:43 armin + * Added silence detection in voice receive mode. + * + * Revision 1.11 1998/04/10 10:35:10 paul + * fixed (silly?) warnings from egcs on Alpha. + * * Revision 1.10 1998/02/20 17:09:40 fritz * Changes for recent kernels. * @@ -61,7 +82,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.10 $"; +char *isdn_audio_revision = "$Revision: 1.14 $"; /* * Misc. lookup-tables. @@ -276,7 +297,7 @@ isdn_audio_tlookup(const char *table, char *buff, unsigned long n) { while (n--) - *buff++ = table[*buff]; + *buff++ = table[*(unsigned char *)buff]; } #endif @@ -659,4 +680,106 @@ } len -= c; } +} + +silence_state * +isdn_audio_silence_init(silence_state * s) +{ + if (!s) + s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC); + if (s) { + s->idx = 0; + s->state = 0; + } + return s; +} + +void +isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt) +{ + silence_state *s = info->silence_state; + int i; + signed char c; + + if (!info->emu.vpar[1]) return; + + for (i = 0; i < len; i++) { + if (fmt) + c = isdn_audio_alaw_to_ulaw[*buf++]; + else + c = *buf++; + + if (c > 0) c -= 128; + c = abs(c); + + if (c > (info->emu.vpar[1] * 4)) { + s->idx = 0; + s->state = 1; + } else { + if (s->idx < 210000) s->idx++; + } + } +} + +void +isdn_audio_put_dle_code(modem_info * info, u_char code) +{ + struct sk_buff *skb; + unsigned long flags; + int di; + int ch; + char *p; + + skb = dev_alloc_skb(2); + if (!skb) { + printk(KERN_WARNING + "isdn_audio: Could not alloc skb for ttyI%d\n", + info->line); + return; + } + p = (char *) skb_put(skb, 2); + p[0] = 0x10; + p[1] = code; + if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { + printk(KERN_WARNING + "isdn_audio: insufficient skb_headroom, dropping\n"); + kfree_skb(skb); + return; + } + ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; + ISDN_AUDIO_SKB_LOCK(skb) = 0; + save_flags(flags); + cli(); + di = info->isdn_driver; + ch = info->isdn_channel; + __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); + dev->drv[di]->rcvcount[ch] += 2; + restore_flags(flags); + /* Schedule dequeuing */ + if ((dev->modempoll) && (info->rcvsched)) + isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); + wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); +} + +void +isdn_audio_eval_silence(modem_info * info) +{ + silence_state *s = info->silence_state; + char what; + + what = ' '; + + if (s->idx > (info->emu.vpar[2] * 800)) { + s->idx = 0; + if (!s->state) { /* silence from beginning of rec */ + what = 's'; + } else { + what = 'q'; + } + } + if ((what == 's') || (what == 'q')) { + printk(KERN_DEBUG "ttyI%d: %s\n", info->line, + (what=='s') ? "silence":"quiet"); + isdn_audio_put_dle_code(info, what); + } } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_audio.h linux/drivers/isdn/isdn_audio.h --- v2.2.10/linux/drivers/isdn/isdn_audio.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/isdn_audio.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $ +/* $Id: isdn_audio.h,v 1.8 1999/07/11 17:14:07 armin Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,23 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.h,v $ + * Revision 1.8 1999/07/11 17:14:07 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * + * Revision 1.7 1999/04/12 12:33:11 fritz + * Changes from 2.0 tree. + * + * Revision 1.6 1998/07/26 18:48:44 armin + * Added silence detection in voice receive mode. + * * Revision 1.5 1997/02/03 22:45:21 fritz * Reformatted according CodingStyle * @@ -51,6 +68,11 @@ int buf[DTMF_NPOINTS]; } dtmf_state; +typedef struct silence_state { + int state; + unsigned int idx; +} silence_state; + extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); @@ -60,3 +82,7 @@ extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); extern void isdn_audio_eval_dtmf(modem_info *); dtmf_state *isdn_audio_dtmf_init(dtmf_state *); +extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); +extern void isdn_audio_eval_silence(modem_info *); +silence_state *isdn_audio_silence_init(silence_state *); +extern void isdn_audio_put_dle_code(modem_info *, u_char); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c --- v2.2.10/linux/drivers/isdn/isdn_bsdcomp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/isdn_bsdcomp.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,934 @@ +/* + * BSD compression module + * + * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp + * The whole module is now SKB based. + * + * Compile with: + * gcc -O2 -I/usr/src/linux/include -D__KERNEL__ -DMODULE -c isdn_bsdcomp.c + */ + +/* + * Original copyright notice: + * + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef MODULE +#error This file must be compiled as a module. +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* to get the struct task_struct */ +#include /* used in new tty drivers */ +#include /* used in new tty drivers */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +/* #include */ +#include +#include +#include +#include + +#include "isdn_ppp.h" + +#define BSD_VERSION(x) ((x) >> 5) +#define BSD_NBITS(x) ((x) & 0x1F) + +#define BSD_CURRENT_VERSION 1 + +#define DEBUG 1 + +/* + * A dictionary for doing BSD compress. + */ + +struct bsd_dict { + u32 fcode; + u16 codem1; /* output of hash table -1 */ + u16 cptr; /* map code to hash table entry */ +}; + +struct bsd_db { + int totlen; /* length of this structure */ + unsigned int hsize; /* size of the hash table */ + unsigned char hshift; /* used in hash function */ + unsigned char n_bits; /* current bits/code */ + unsigned char maxbits; /* maximum bits/code */ + unsigned char debug; /* non-zero if debug desired */ + unsigned char unit; /* ppp unit number */ + u16 seqno; /* sequence # of next packet */ + unsigned int mru; /* size of receive (decompress) bufr */ + unsigned int maxmaxcode; /* largest valid code */ + unsigned int max_ent; /* largest code in use */ + unsigned int in_count; /* uncompressed bytes, aged */ + unsigned int bytes_out; /* compressed bytes, aged */ + unsigned int ratio; /* recent compression ratio */ + unsigned int checkpoint; /* when to next check the ratio */ + unsigned int clear_count; /* times dictionary cleared */ + unsigned int incomp_count; /* incompressible packets */ + unsigned int incomp_bytes; /* incompressible bytes */ + unsigned int uncomp_count; /* uncompressed packets */ + unsigned int uncomp_bytes; /* uncompressed bytes */ + unsigned int comp_count; /* compressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned short *lens; /* array of lengths of codes */ + struct bsd_dict *dict; /* dictionary */ + int xmit; +}; + +#define BSD_OVHD 2 /* BSD compress overhead/packet */ +#define MIN_BSD_BITS 9 +#define BSD_INIT_BITS MIN_BSD_BITS +#define MAX_BSD_BITS 15 + +/* + * the next two codes should not be changed lightly, as they must not + * lie within the contiguous general code space. + */ +#define CLEAR 256 /* table clear output code */ +#define FIRST 257 /* first free entry */ +#define LAST 255 + +#define MAXCODE(b) ((1 << (b)) - 1) +#define BADCODEM1 MAXCODE(MAX_BSD_BITS); + +#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \ + ^ (unsigned long)(prefix)) +#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \ + + (unsigned long)(prefix)) + +#define CHECK_GAP 10000 /* Ratio check interval */ + +#define RATIO_SCALE_LOG 8 +#define RATIO_SCALE (1<>RATIO_SCALE_LOG) + +/* + * clear the dictionary + */ + +static void bsd_clear(struct bsd_db *db) +{ + db->clear_count++; + db->max_ent = FIRST-1; + db->n_bits = BSD_INIT_BITS; + db->bytes_out = 0; + db->in_count = 0; + db->incomp_count = 0; + db->ratio = 0; + db->checkpoint = CHECK_GAP; +} + +/* + * If the dictionary is full, then see if it is time to reset it. + * + * Compute the compression ratio using fixed-point arithmetic + * with 8 fractional bits. + * + * Since we have an infinite stream instead of a single file, + * watch only the local compression ratio. + * + * Since both peers must reset the dictionary at the same time even in + * the absence of CLEAR codes (while packets are incompressible), they + * must compute the same ratio. + */ +static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */ +{ + unsigned int new_ratio; + + if (db->in_count >= db->checkpoint) + { + /* age the ratio by limiting the size of the counts */ + if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) + { + db->in_count -= (db->in_count >> 2); + db->bytes_out -= (db->bytes_out >> 2); + } + + db->checkpoint = db->in_count + CHECK_GAP; + + if (db->max_ent >= db->maxmaxcode) + { + /* Reset the dictionary only if the ratio is worse, + * or if it looks as if it has been poisoned + * by incompressible data. + * + * This does not overflow, because + * db->in_count <= RATIO_MAX. + */ + + new_ratio = db->in_count << RATIO_SCALE_LOG; + if (db->bytes_out != 0) + { + new_ratio /= db->bytes_out; + } + + if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) + { + bsd_clear (db); + return 1; + } + db->ratio = new_ratio; + } + } + return 0; +} + +/* + * Return statistics. + */ + +static void bsd_stats (void *state, struct compstat *stats) +{ + struct bsd_db *db = (struct bsd_db *) state; + + stats->unc_bytes = db->uncomp_bytes; + stats->unc_packets = db->uncomp_count; + stats->comp_bytes = db->comp_bytes; + stats->comp_packets = db->comp_count; + stats->inc_bytes = db->incomp_bytes; + stats->inc_packets = db->incomp_count; + stats->in_count = db->in_count; + stats->bytes_out = db->bytes_out; +} + +/* + * Reset state, as on a CCP ResetReq. + */ +static void bsd_reset (void *state,unsigned char code, unsigned char id, + unsigned char *data, unsigned len, + struct isdn_ppp_resetparams *rsparm) +{ + struct bsd_db *db = (struct bsd_db *) state; + + bsd_clear(db); + db->seqno = 0; + db->clear_count = 0; +} + +/* + * Release the compression structure + */ +static void bsd_free (void *state) +{ + struct bsd_db *db = (struct bsd_db *) state; + + if (db) { + /* + * Release the dictionary + */ + if (db->dict) { + vfree (db->dict); + db->dict = NULL; + } + + /* + * Release the string buffer + */ + if (db->lens) { + vfree (db->lens); + db->lens = NULL; + } + + /* + * Finally release the structure itself. + */ + kfree (db); + MOD_DEC_USE_COUNT; + } +} + + +/* + * Allocate space for a (de) compressor. + */ +static void *bsd_alloc (struct isdn_ppp_comp_data *data) +{ + int bits; + unsigned int hsize, hshift, maxmaxcode; + struct bsd_db *db; + int decomp; + + static unsigned int htab[][2] = { + { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , + { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 } + }; + + if (data->optlen != 1 || data->num != CI_BSD_COMPRESS + || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) + return NULL; + + bits = BSD_NBITS(data->options[0]); + + if(bits < 9 || bits > 15) + return NULL; + + hsize = htab[bits-9][0]; + hshift = htab[bits-9][1]; + + /* + * Allocate the main control structure for this instance. + */ + maxmaxcode = MAXCODE(bits); + db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL); + if (!db) + return NULL; + + memset (db, 0, sizeof(struct bsd_db)); + + db->xmit = data->flags & IPPP_COMP_FLAG_XMIT; + decomp = db->xmit ? 0 : 1; + + /* + * Allocate space for the dictionary. This may be more than one page in + * length. + */ + db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict)); + if (!db->dict) { + bsd_free (db); + return NULL; + } + + MOD_INC_USE_COUNT; + + /* + * If this is the compression buffer then there is no length data. + * For decompression, the length information is needed as well. + */ + if (!decomp) + db->lens = NULL; + else { + db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) * + sizeof (db->lens[0])); + if (!db->lens) { + bsd_free (db); /* calls MOD_DEC_USE_COUNT; */ + return (NULL); + } + } + + /* + * Initialize the data information for the compression code + */ + db->totlen = sizeof (struct bsd_db) + (sizeof (struct bsd_dict) * hsize); + db->hsize = hsize; + db->hshift = hshift; + db->maxmaxcode = maxmaxcode; + db->maxbits = bits; + + return (void *) db; +} + +/* + * Initialize the database. + */ +static int bsd_init (void *state, struct isdn_ppp_comp_data *data, int unit, int debug) +{ + struct bsd_db *db = state; + int indx; + int decomp; + + if(!state || !data) { + printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n",unit,(long)state,(long)data); + return 0; + } + + decomp = db->xmit ? 0 : 1; + + if (data->optlen != 1 || data->num != CI_BSD_COMPRESS + || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) + || (BSD_NBITS(data->options[0]) != db->maxbits) + || (decomp && db->lens == NULL)) { + printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n",data->optlen,data->num,data->options[0],decomp,(unsigned long)db->lens); + return 0; + } + + if (decomp) + for(indx=LAST;indx>=0;indx--) + db->lens[indx] = 1; + + indx = db->hsize; + while (indx-- != 0) { + db->dict[indx].codem1 = BADCODEM1; + db->dict[indx].cptr = 0; + } + + db->unit = unit; + db->mru = 0; + + db->debug = 1; + + bsd_reset(db,0,0,NULL,0,NULL); + + return 1; +} + +/* + * Obtain pointers to the various structures in the compression tables + */ + +#define dict_ptrx(p,idx) &(p->dict[idx]) +#define lens_ptrx(p,idx) &(p->lens[idx]) + +#ifdef DEBUG +static unsigned short *lens_ptr(struct bsd_db *db, int idx) +{ + if ((unsigned int) idx > (unsigned int) db->maxmaxcode) { + printk (KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx); + idx = 0; + } + return lens_ptrx (db, idx); +} + +static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) +{ + if ((unsigned int) idx >= (unsigned int) db->hsize) { + printk (KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx); + idx = 0; + } + return dict_ptrx (db, idx); +} + +#else +#define lens_ptr(db,idx) lens_ptrx(db,idx) +#define dict_ptr(db,idx) dict_ptrx(db,idx) +#endif + +/* + * compress a packet + */ +static int bsd_compress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,int proto) +{ + struct bsd_db *db; + int hshift; + unsigned int max_ent; + unsigned int n_bits; + unsigned int bitno; + unsigned long accm; + int ent; + unsigned long fcode; + struct bsd_dict *dictp; + unsigned char c; + int hval,disp,ilen,mxcode; + unsigned char *rptr = skb_in->data; + int isize = skb_in->len; + +#define OUTPUT(ent) \ + { \ + bitno -= n_bits; \ + accm |= ((ent) << bitno); \ + do { \ + if(skb_out && skb_tailroom(skb_out) > 0) \ + *(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \ + accm <<= 8; \ + bitno += 8; \ + } while (bitno <= 24); \ + } + + /* + * If the protocol is not in the range we're interested in, + * just return without compressing the packet. If it is, + * the protocol becomes the first byte to compress. + */ + printk(KERN_DEBUG "bsd_compress called with %x\n",proto); + + ent = proto; + if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) ) + return 0; + + db = (struct bsd_db *) state; + hshift = db->hshift; + max_ent = db->max_ent; + n_bits = db->n_bits; + bitno = 32; + accm = 0; + mxcode = MAXCODE (n_bits); + + /* This is the PPP header information */ + if(skb_out && skb_tailroom(skb_out) >= 2) { + char *v = skb_put(skb_out,2); + /* we only push our own data on the header, + AC,PC and protos is pushed by caller */ + v[0] = db->seqno >> 8; + v[1] = db->seqno; + } + + ilen = ++isize; /* This is off by one, but that is what is in draft! */ + + while (--ilen > 0) { + c = *rptr++; + fcode = BSD_KEY (ent, c); + hval = BSD_HASH (ent, c, hshift); + dictp = dict_ptr (db, hval); + + /* Validate and then check the entry. */ + if (dictp->codem1 >= max_ent) + goto nomatch; + + if (dictp->fcode == fcode) { + ent = dictp->codem1 + 1; + continue; /* found (prefix,suffix) */ + } + + /* continue probing until a match or invalid entry */ + disp = (hval == 0) ? 1 : hval; + + do { + hval += disp; + if (hval >= db->hsize) + hval -= db->hsize; + dictp = dict_ptr (db, hval); + if (dictp->codem1 >= max_ent) + goto nomatch; + } while (dictp->fcode != fcode); + + ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ + continue; + +nomatch: + OUTPUT(ent); /* output the prefix */ + + /* code -> hashtable */ + if (max_ent < db->maxmaxcode) { + struct bsd_dict *dictp2; + struct bsd_dict *dictp3; + int indx; + + /* expand code size if needed */ + if (max_ent >= mxcode) { + db->n_bits = ++n_bits; + mxcode = MAXCODE (n_bits); + } + + /* + * Invalidate old hash table entry using + * this code, and then take it over. + */ + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + dictp3->codem1 = BADCODEM1; + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->fcode = fcode; + db->max_ent = ++max_ent; + + if (db->lens) { + unsigned short *len1 = lens_ptr (db, max_ent); + unsigned short *len2 = lens_ptr (db, ent); + *len1 = *len2 + 1; + } + } + ent = c; + } + + OUTPUT(ent); /* output the last code */ + + if(skb_out) + db->bytes_out += skb_out->len; /* Do not count bytes from here */ + db->uncomp_bytes += isize; + db->in_count += isize; + ++db->uncomp_count; + ++db->seqno; + + if (bitno < 32) + ++db->bytes_out; /* must be set before calling bsd_check */ + + /* + * Generate the clear command if needed + */ + + if (bsd_check(db)) + OUTPUT (CLEAR); + + /* + * Pad dribble bits of last code with ones. + * Do not emit a completely useless byte of ones. + */ + if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) + *(skb_put(skb_out,1)) = (unsigned char) ((accm | (0xff << (bitno-8))) >> 24); + + /* + * Increase code size if we would have without the packet + * boundary because the decompressor will do so. + */ + if (max_ent >= mxcode && max_ent < db->maxmaxcode) + db->n_bits++; + + /* If output length is too large then this is an incompressible frame. */ + if (!skb_out || (skb_out && skb_out->len >= skb_in->len) ) { + ++db->incomp_count; + db->incomp_bytes += isize; + return 0; + } + + /* Count the number of compressed frames */ + ++db->comp_count; + db->comp_bytes += skb_out->len; + return skb_out->len; + +#undef OUTPUT +} + +/* + * Update the "BSD Compress" dictionary on the receiver for + * incompressible data by pretending to compress the incoming data. + */ +static void bsd_incomp (void *state, struct sk_buff *skb_in,int proto) +{ + bsd_compress (state, skb_in, NULL, proto); +} + +/* + * Decompress "BSD Compress". + */ +static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, + struct isdn_ppp_resetparams *rsparm) +{ + struct bsd_db *db; + unsigned int max_ent; + unsigned long accm; + unsigned int bitno; /* 1st valid bit in accm */ + unsigned int n_bits; + unsigned int tgtbitno; /* bitno when we have a code */ + struct bsd_dict *dictp; + int seq; + unsigned int incode; + unsigned int oldcode; + unsigned int finchar; + unsigned char *p,*ibuf; + int ilen; + int codelen; + int extra; + + db = (struct bsd_db *) state; + max_ent = db->max_ent; + accm = 0; + bitno = 32; /* 1st valid bit in accm */ + n_bits = db->n_bits; + tgtbitno = 32 - n_bits; /* bitno when we have a code */ + + printk(KERN_DEBUG "bsd_decompress called\n"); + + if(!skb_in || !skb_out) { + printk(KERN_ERR "bsd_decompress called with NULL parameter\n"); + return DECOMP_ERROR; + } + + /* + * Get the sequence number. + */ + if( (p = skb_pull(skb_in,2)) == NULL) { + return DECOMP_ERROR; + } + p-=2; + seq = (p[0] << 8) + p[1]; + ilen = skb_in->len; + ibuf = skb_in->data; + + /* + * Check the sequence number and give up if it differs from + * the value we're expecting. + */ + if (seq != db->seqno) { + if (db->debug) { + printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n", + db->unit, seq, db->seqno - 1); + } + return DECOMP_ERROR; + } + + ++db->seqno; + db->bytes_out += ilen; + + if(skb_tailroom(skb_out) > 0) + *(skb_put(skb_out,1)) = 0; + else + return DECOMP_ERR_NOMEM; + + oldcode = CLEAR; + + /* + * Keep the checkpoint correctly so that incompressible packets + * clear the dictionary at the proper times. + */ + + for (;;) { + if (ilen-- <= 0) { + db->in_count += (skb_out->len - 1); /* don't count the header */ + break; + } + + /* + * Accumulate bytes until we have a complete code. + * Then get the next code, relying on the 32-bit, + * unsigned accm to mask the result. + */ + + bitno -= 8; + accm |= *ibuf++ << bitno; + if (tgtbitno < bitno) + continue; + + incode = accm >> tgtbitno; + accm <<= n_bits; + bitno += n_bits; + + /* + * The dictionary must only be cleared at the end of a packet. + */ + + if (incode == CLEAR) { + if (ilen > 0) { + if (db->debug) + printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit); + return DECOMP_FATALERROR; /* probably a bug */ + } + bsd_clear(db); + break; + } + + if ((incode > max_ent + 2) || (incode > db->maxmaxcode) + || (incode > max_ent && oldcode == CLEAR)) { + if (db->debug) { + printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ", + db->unit, incode, oldcode); + printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n", + max_ent, skb_out->len, db->seqno); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + + /* Special case for KwKwK string. */ + if (incode > max_ent) { + finchar = oldcode; + extra = 1; + } else { + finchar = incode; + extra = 0; + } + + codelen = *(lens_ptr (db, finchar)); + if( skb_tailroom(skb_out) < codelen + extra) { + if (db->debug) { + printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit); +#ifdef DEBUG + printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n", + ilen, finchar, codelen, skb_out->len); +#endif + } + return DECOMP_FATALERROR; + } + + /* + * Decode this code and install it in the decompressed buffer. + */ + + p = skb_put(skb_out,codelen); + p += codelen; + while (finchar > LAST) { + struct bsd_dict *dictp2 = dict_ptr (db, finchar); + + dictp = dict_ptr (db, dictp2->cptr); + +#ifdef DEBUG + if (--codelen <= 0 || dictp->codem1 != finchar-1) { + if (codelen <= 0) { + printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit); + printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent); + } else { + if (dictp->codem1 != finchar-1) { + printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",db->unit, incode, finchar); + printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1); + } + } + return DECOMP_FATALERROR; + } +#endif + + { + u32 fcode = dictp->fcode; + *--p = (fcode >> 16) & 0xff; + finchar = fcode & 0xffff; + } + } + *--p = finchar; + +#ifdef DEBUG + if (--codelen != 0) + printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent); +#endif + + if (extra) /* the KwKwK case again */ + *(skb_put(skb_out,1)) = finchar; + + /* + * If not first code in a packet, and + * if not out of code space, then allocate a new code. + * + * Keep the hash table correct so it can be used + * with uncompressed packets. + */ + if (oldcode != CLEAR && max_ent < db->maxmaxcode) { + struct bsd_dict *dictp2, *dictp3; + u16 *lens1, *lens2; + unsigned long fcode; + int hval, disp, indx; + + fcode = BSD_KEY(oldcode,finchar); + hval = BSD_HASH(oldcode,finchar,db->hshift); + dictp = dict_ptr (db, hval); + + /* look for a free hash table entry */ + if (dictp->codem1 < max_ent) { + disp = (hval == 0) ? 1 : hval; + do { + hval += disp; + if (hval >= db->hsize) + hval -= db->hsize; + dictp = dict_ptr (db, hval); + } while (dictp->codem1 < max_ent); + } + + /* + * Invalidate previous hash table entry + * assigned this code, and then take it over + */ + + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + dictp3->codem1 = BADCODEM1; + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->fcode = fcode; + db->max_ent = ++max_ent; + + /* Update the length of this string. */ + lens1 = lens_ptr (db, max_ent); + lens2 = lens_ptr (db, oldcode); + *lens1 = *lens2 + 1; + + /* Expand code size if needed. */ + if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { + db->n_bits = ++n_bits; + tgtbitno = 32-n_bits; + } + } + oldcode = incode; + } + + ++db->comp_count; + ++db->uncomp_count; + db->comp_bytes += skb_in->len - BSD_OVHD; + db->uncomp_bytes += skb_out->len; + + if (bsd_check(db)) { + if (db->debug) + printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n", + db->unit, db->seqno - 1); + } + return skb_out->len; +} + +/************************************************************* + * Table of addresses for the BSD compression module + *************************************************************/ + +static struct isdn_ppp_compressor ippp_bsd_compress = { + NULL,NULL, /* prev,next: overwritten by isdn_ppp */ + CI_BSD_COMPRESS, /* compress_proto */ + bsd_alloc, /* alloc */ + bsd_free, /* free */ + bsd_init, /* init */ + bsd_reset, /* reset */ + bsd_compress, /* compress */ + bsd_decompress, /* decompress */ + bsd_incomp, /* incomp */ + bsd_stats /* comp_stat */ +}; + +/************************************************************* + * Module support routines + *************************************************************/ + +int init_module(void) +{ + int answer = isdn_ppp_register_compressor (&ippp_bsd_compress); + if (answer == 0) + printk (KERN_INFO "PPP BSD Compression module registered\n"); + return answer; +} + +void cleanup_module(void) +{ + isdn_ppp_unregister_compressor (&ippp_bsd_compress); +} diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.2.10/linux/drivers/isdn/isdn_cards.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/isdn_cards.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_cards.c,v 1.7 1998/02/20 17:24:28 fritz Exp $ +/* $Id: isdn_cards.c,v 1.9 1999/04/12 12:33:11 fritz Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.c,v $ + * Revision 1.9 1999/04/12 12:33:11 fritz + * Changes from 2.0 tree. + * + * Revision 1.8 1999/03/29 11:13:23 armin + * Added eicon driver init. + * * Revision 1.7 1998/02/20 17:24:28 fritz * Added ACT2000 init. * @@ -56,6 +62,10 @@ extern void pcbit_init(void); #endif +#ifdef CONFIG_ISDN_DRV_EICON +extern void eicon_init(void); +#endif + #ifdef CONFIG_ISDN_DRV_AVMB1 extern void avmb1_init(void); extern void capi_init(void); @@ -87,5 +97,8 @@ #endif #if CONFIG_ISDN_DRV_ACT2000 act2000_init(); +#endif +#if CONFIG_ISDN_DRV_EICON + eicon_init(); #endif } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v2.2.10/linux/drivers/isdn/isdn_cards.h Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/isdn_cards.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $ +/* $Id: isdn_cards.h,v 1.3 1999/04/12 12:33:13 fritz Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * * 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 @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_cards.h,v $ + * Revision 1.3 1999/04/12 12:33:13 fritz + * Changes from 2.0 tree. + * * Revision 1.2 1997/02/03 23:31:55 fritz * Reformatted according CodingStyle * diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.2.10/linux/drivers/isdn/isdn_common.c Tue Jan 19 11:06:52 1999 +++ linux/drivers/isdn/isdn_common.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $ +/* $Id: isdn_common.c,v 1.83 1999/07/13 21:02:05 werner Exp $ * Linux ISDN subsystem, common used functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,111 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_common.c,v $ + * Revision 1.83 1999/07/13 21:02:05 werner + * Added limit possibilty of driver b_channel resources (ISDN_STAT_DISCH) + * + * Revision 1.82 1999/07/12 21:06:50 werner + * Fixed problem when loading more than one driver temporary + * + * Revision 1.81 1999/07/11 17:14:09 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * + * Revision 1.80 1999/07/07 10:14:00 detabc + * remove unused messages + * + * Revision 1.79 1999/07/05 23:51:30 werner + * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl + * hisaxctrl id 10 + * + * Revision 1.78 1999/07/05 20:21:15 werner + * changes to use diversion sources for all kernel versions. + * removed static device, only proc filesystem used + * + * Revision 1.77 1999/07/01 08:29:50 keil + * compatibility to 2.3 kernel + * + * Revision 1.76 1999/06/29 16:16:44 calle + * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again. + * Also right unlocking (ISDN_CMD_UNLOCK) is done now. + * isdnlog should check returncode of read(2) calls. + * + * Revision 1.75 1999/04/18 14:06:47 fritz + * Removed TIMRU stuff. + * + * Revision 1.74 1999/04/12 13:16:45 fritz + * Changes from 2.0 tree. + * + * Revision 1.73 1999/04/12 12:33:15 fritz + * Changes from 2.0 tree. + * + * Revision 1.72 1999/03/02 12:04:44 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.71 1999/01/28 09:10:43 armin + * Fixed bad while-loop in isdn_readbch(). + * + * Revision 1.70 1999/01/15 19:58:54 he + * removed compatibiltity macro + * + * Revision 1.69 1998/09/07 21:59:58 he + * flush method for 2.1.118 and above + * updated IIOCTLNETGPN + * + * Revision 1.68 1998/08/31 21:09:45 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * + * Revision 1.67 1998/06/26 15:12:21 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.66 1998/06/17 19:50:41 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * + * Revision 1.62 1998/04/14 16:28:43 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.61 1998/03/22 18:50:46 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * + * Revision 1.60 1998/03/19 13:18:18 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * Revision 1.59 1998/03/09 17:46:23 he + * merged in 2.1.89 changes + * + * Revision 1.58 1998/03/07 22:35:24 fritz + * Starting generic module support (Nothing usable yet). + * + * Revision 1.57 1998/03/07 18:21:01 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.56 1998/02/25 17:49:38 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.55 1998/02/23 23:35:32 fritz * Eliminated some compiler warnings. * @@ -261,6 +361,9 @@ #ifdef CONFIG_ISDN_AUDIO #include "isdn_audio.h" #endif +#ifdef CONFIG_ISDN_DIVERSION +#include +#endif CONFIG_ISDN_DIVERSION #include "isdn_v110.h" #include "isdn_cards.h" @@ -269,7 +372,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.55 $"; +static char *isdn_revision = "$Revision: 1.83 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -285,18 +388,46 @@ #endif extern char *isdn_v110_revision; +#ifdef CONFIG_ISDN_DIVERSION +isdn_divert_if *divert_if = NULL; /* interface to diversion module */ +#endif CONFIG_ISDN_DIVERSION + + static int isdn_writebuf_stub(int, int, const u_char *, int, int); void isdn_MOD_INC_USE_COUNT(void) { + int i; + MOD_INC_USE_COUNT; + for (i = 0; i < dev->drivers; i++) { + isdn_ctrl cmd; + + cmd.driver = i; + cmd.arg = 0; + cmd.command = ISDN_CMD_LOCK; + isdn_command(&cmd); + dev->drv[i]->locks++; + } } void isdn_MOD_DEC_USE_COUNT(void) { + int i; + MOD_DEC_USE_COUNT; + for (i = 0; i < dev->drivers; i++) + if (dev->drv[i]->locks > 0) { + isdn_ctrl cmd; + + cmd.driver = i; + cmd.arg = 0; + cmd.command = ISDN_CMD_UNLOCK; + isdn_command(&cmd); + dev->drv[i]->locks--; + } } #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) @@ -312,6 +443,82 @@ } #endif +/* + * I picked the pattern-matching-functions from an old GNU-tar version (1.10) + * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) + */ +static int +isdn_star(char *s, char *p) +{ + while (isdn_wildmat(s, p)) { + if (*++s == '\0') + return (2); + } + return (0); +} + +/* + * Shell-type Pattern-matching for incoming caller-Ids + * This function gets a string in s and checks, if it matches the pattern + * given in p. + * + * Return: + * 0 = match. + * 1 = no match. + * 2 = no match. Would eventually match, if s would be longer. + * + * Possible Patterns: + * + * '?' matches one character + * '*' matches zero or more characters + * [xyz] matches the set of characters in brackets. + * [^xyz] matches any single character not in the set of characters + */ + +int +isdn_wildmat(char *s, char *p) +{ + register int last; + register int matched; + register int reverse; + register int nostar = 1; + + for (; *p; s++, p++) + switch (*p) { + case '\\': + /* + * Literal match with following character, + * fall through. + */ + p++; + default: + if (*s != *p) + return (*s == '\0')?2:1; + continue; + case '?': + /* Match anything. */ + if (*s == '\0') + return (2); + continue; + case '*': + nostar = 0; + /* Trailing star matches everything. */ + return (*++p ? isdn_star(s, p) : 0); + case '[': + /* [^....] means inverse character class. */ + if ((reverse = (p[1] == '^'))) + p++; + for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) + matched = 1; + if (matched == reverse) + return (1); + continue; + } + return (*s == '\0')?0:nostar; +} + static void isdn_free_queue(struct sk_buff_head *queue) { @@ -345,7 +552,6 @@ isdn_timer_funct(ulong dummy) { int tf = dev->tflags; - if (tf & ISDN_TIMER_FAST) { if (tf & ISDN_TIMER_MODEMREAD) isdn_tty_readmodem(); @@ -374,13 +580,16 @@ if (tf & ISDN_TIMER_KEEPALIVE) isdn_net_slarp_out(); } + if (tf & ISDN_TIMER_CARRIER) + isdn_tty_carrier_timeout(); #if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP) if (tf & ISDN_TIMER_IPPP) isdn_ppp_timer_timeout(); #endif } } - if (tf) { + if (tf) + { int flags; save_flags(flags); @@ -506,6 +715,29 @@ isdn_command(&cmd); } +/* + * Begin of a CAPI like LL<->HL interface, currently used only for + * supplementary service (CAPI 2.0 part III) + */ +#include "avmb1/capicmd.h" /* this should be moved in a common place */ + +int +isdn_capi_rec_hl_msg(capi_msg *cm) { + + int di; + int ch; + + di = (cm->adr.Controller & 0x7f) -1; + ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f); + switch(cm->Command) { + case CAPI_FACILITY: + /* in the moment only handled in tty */ + return(isdn_tty_capi_facility(cm)); + default: + return(-1); + } +} + static int isdn_status_callback(isdn_ctrl * c) { @@ -540,13 +772,13 @@ wake_up_interruptible(&dev->drv[di]->st_waitq); break; case ISDN_STAT_RUN: - dev->drv[di]->running = 1; + dev->drv[di]->flags |= DRV_FLAG_RUNNING; for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (dev->drvmap[i] == di) isdn_all_eaz(di, dev->chanmap[i]); break; case ISDN_STAT_STOP: - dev->drv[di]->running = 0; + dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; break; case ISDN_STAT_ICALL: if (i < 0) @@ -562,19 +794,23 @@ return 0; } /* Try to find a network-interface which will accept incoming call */ - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); - r = isdn_net_find_icall(di, c->arg, i, c->parm.setup); + r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup)); switch (r) { case 0: /* No network-device replies. - * Try ttyI's + * Try ttyI's. + * These return 0 on no match, 1 on match and + * 3 on eventually match, if CID is longer. */ - if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0) - retval = 1; - else if (dev->drv[di]->reject_bus) { + if (c->command == ISDN_STAT_ICALL) + if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval); +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + if ((retval = divert_if->stat_callback(c))) + return(retval); /* processed */ +#endif CONFIG_ISDN_DIVERSION + if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { + /* No tty responding */ cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_HANGUP; @@ -606,13 +842,14 @@ /* ... then start callback. */ isdn_net_dial(); break; + case 5: + /* Number would eventually match, if longer */ + retval = 3; + break; } - if (retval != 1) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_UNLOCK; - isdn_command(&cmd); - } +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "ICALL: ret=%d\n", retval); +#endif return retval; break; case ISDN_STAT_CINF: @@ -634,6 +871,20 @@ printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n", dev->drvid[di], c->arg, c->parm.num); isdn_tty_stat_callback(i, c); +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + divert_if->stat_callback(c); +#endif CONFIG_ISDN_DIVERSION + break; + case ISDN_STAT_DISPLAY: +#ifdef ISDN_DEBUG_STATCALLB + printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display); +#endif + isdn_tty_stat_callback(i, c); +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + divert_if->stat_callback(c); +#endif CONFIG_ISDN_DIVERSION break; case ISDN_STAT_DCONN: if (i < 0) @@ -664,7 +915,7 @@ #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); + dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); /* Signal hangup to network-devices */ if (isdn_net_stat_callback(i, c)) @@ -672,6 +923,11 @@ isdn_v110_stat_callback(i, c); if (isdn_tty_stat_callback(i, c)) break; +#ifdef CONFIG_ISDN_DIVERSION + if (divert_if) + divert_if->stat_callback(c); +#endif CONFIG_ISDN_DIVERSION + break; break; case ISDN_STAT_BCONN: if (i < 0) @@ -682,7 +938,7 @@ /* Signal B-channel-connect to network-devices */ if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags |= (1 << (c->arg)); + dev->drv[di]->online |= (1 << (c->arg)); isdn_info_update(); if (isdn_net_stat_callback(i, c)) break; @@ -698,7 +954,7 @@ #endif if (dev->global_flags & ISDN_GLOBAL_STOPPED) return 0; - dev->drv[di]->flags &= ~(1 << (c->arg)); + dev->drv[di]->online &= ~(1 << (c->arg)); isdn_info_update(); #ifdef CONFIG_ISDN_X25 /* Signal hangup to network-devices */ @@ -723,8 +979,38 @@ break; break; case ISDN_STAT_ADDCH: + if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) + return -1; + isdn_info_update(); + break; + case ISDN_STAT_DISCH: + save_flags(flags); + cli(); + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + if ((dev->drvmap[i] == di) && + (dev->chanmap[i] == c->arg)) { + if (c->parm.num[0]) + dev->usage[i] &= ~ISDN_USAGE_DISABLED; + else + if (USG_NONE(dev->usage[i])) { + dev->usage[i] |= ISDN_USAGE_DISABLED; + } + else + retval = -1; + break; + } + restore_flags(flags); + isdn_info_update(); break; case ISDN_STAT_UNLOAD: + while (dev->drv[di]->locks > 0) { + isdn_ctrl cmd; + cmd.driver = di; + cmd.arg = 0; + cmd.command = ISDN_CMD_UNLOCK; + isdn_command(&cmd); + dev->drv[di]->locks--; + } save_flags(flags); cli(); isdn_tty_stat_callback(i, c); @@ -732,6 +1018,7 @@ if (dev->drvmap[i] == di) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; + dev->usage[i] &= ~ISDN_USAGE_DISABLED; } dev->drivers--; dev->channels -= dev->drv[di]->channels; @@ -741,7 +1028,9 @@ isdn_free_queue(&dev->drv[di]->rpqueue[i]); kfree(dev->drv[di]->rpqueue); kfree(dev->drv[di]->rcv_waitq); +#ifndef COMPAT_HAS_NEW_WAITQ kfree(dev->drv[di]->snd_waitq); +#endif kfree(dev->drv[di]); dev->drv[di] = NULL; dev->drvid[di][0] = '\0'; @@ -750,6 +1039,19 @@ return 0; case ISDN_STAT_L1ERR: break; + case CAPI_PUT_MESSAGE: + return(isdn_capi_rec_hl_msg(&c->parm.cmsg)); +#ifdef CONFIG_ISDN_AUDIO + case ISDN_STAT_AUDIO: + isdn_tty_stat_callback(i, c); + break; +#endif +#ifdef CONFIG_ISDN_DIVERSION + case ISDN_STAT_PROT: + case ISDN_STAT_REDIR: + if (divert_if) + return(divert_if->stat_callback(c)); +#endif CONFIG_ISDN_DIVERSION default: return -1; } @@ -785,7 +1087,11 @@ * of the mapping (di,ch)<->minor, happen during the sleep? --he */ int +#ifdef COMPAT_HAS_NEW_WAITQ +isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep) +#else isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep) +#endif { int left; int count; @@ -819,7 +1125,8 @@ dflag = 0; count_pull = count_put = 0; - while ((count_pull < skb->len) && (left-- > 0)) { + while ((count_pull < skb->len) && (left > 0)) { + left--; if (dev->drv[di]->DLEflag & DLEmask) { *cp++ = DLE; dev->drv[di]->DLEflag &= ~DLEmask; @@ -894,8 +1201,6 @@ return (dev->chanmap[minor]); } -#define INF_DV 0x01 /* Data version for /dev/isdninfo */ - static char * isdn_statstr(void) { @@ -931,7 +1236,7 @@ p = istatbuf + strlen(istatbuf); for (i = 0; i < ISDN_MAX_DRIVERS; i++) { if (dev->drv[i]) { - sprintf(p, "%ld ", dev->drv[i]->flags); + sprintf(p, "%ld ", dev->drv[i]->online); p = istatbuf + strlen(istatbuf); } else { sprintf(p, "? "); @@ -997,7 +1302,7 @@ drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; chidx = isdn_minor2chan(minor); if( ! (p = kmalloc(count,GFP_KERNEL)) ) return -ENOMEM; @@ -1067,7 +1372,7 @@ drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; chidx = isdn_minor2chan(minor); while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) @@ -1081,7 +1386,7 @@ /* * We want to use the isdnctrl device to load the firmware * - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; */ if (dev->drv[drvidx]->interface->writecmd) @@ -1113,11 +1418,11 @@ return mask; } if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { - poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); if (drvidx < 0) { - printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n"); - return POLLERR; + /* driver deregistered while file open */ + return POLLHUP; } + poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); mask = POLLOUT | POLLWRNORM; if (dev->drv[drvidx]->stavail) { mask |= POLLIN | POLLRDNORM; @@ -1132,143 +1437,6 @@ return POLLERR; } -/* - * This accesses user space with interrupts off, but is not needed by - * any of the isdn4k-util programs anyway. Thus, in contrast to your - * first impression after looking at the code, fixing is trival!*/ -#if 0 -static int -isdn_set_allcfg(char *src) -{ - int ret; - int i; - ulong flags; - isdn_net_ioctl_cfg cfg; - isdn_net_ioctl_phone phone; - - if ((ret = isdn_net_rmall())) - return ret; - if (copy_from_user((char *) &i, src, sizeof(int))) return -EFAULT; - save_flags(flags); - cli(); - src += sizeof(int); - while (i) { - int phone_len; - int out_flag; - - if (copy_from_user((char *) &cfg, src, sizeof(cfg))) { - restore_flags(flags); - return -EFAULT; - } - src += sizeof(cfg); - if (!isdn_net_new(cfg.name, NULL)) { - restore_flags(flags); - return -EIO; - } - if ((ret = isdn_net_setcfg(&cfg))) { - restore_flags(flags); - return ret; - } - phone_len = out_flag = 0; - while (out_flag < 2) { - if ((ret = verify_area(VERIFY_READ, src, 1))) { - restore_flags(flags); - return ret; - } - get_user(phone.phone[phone_len], src++); - if ((phone.phone[phone_len] == ' ') || - (phone.phone[phone_len] == '\0')) { - if (phone_len) { - phone.phone[phone_len] = '\0'; - strcpy(phone.name, cfg.name); - phone.outgoing = out_flag; - if ((ret = isdn_net_addphone(&phone))) { - restore_flags(flags); - return ret; - } - } else - out_flag++; - phone_len = 0; - } - if (++phone_len >= sizeof(phone.phone)) - printk(KERN_WARNING - "%s: IIOCSETSET phone number too long, ignored\n", - cfg.name); - } - i--; - } - restore_flags(flags); - return 0; -} - -static int -isdn_get_allcfg(char *dest) -{ - isdn_net_ioctl_cfg cfg; - isdn_net_ioctl_phone phone; - isdn_net_dev *p; - ulong flags; - int ret; - - /* Walk through netdev-chain */ - save_flags(flags); - cli(); - p = dev->netdev; - while (p) { - isdn_net_local *lp = p->local; - - if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) { - restore_flags(flags); - return ret; - } - strcpy(cfg.eaz, lp->msn); - cfg.exclusive = lp->exclusive; - if (lp->pre_device >= 0) { - sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device], - lp->pre_channel); - } else - cfg.drvid[0] = '\0'; - cfg.onhtime = lp->onhtime; - cfg.charge = lp->charge; - cfg.l2_proto = lp->l2_proto; - cfg.l3_proto = lp->l3_proto; - cfg.p_encap = lp->p_encap; - cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0; - cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0; - cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; - cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0; - cfg.chargeint = lp->chargeint; - if (copy_to_user(dest, lp->name, 10)) { - restore_flags(flags); - return -EFAULT; - } - dest += 10; - if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) { - restore_flags(flags); - return -EFAULT; - } - dest += sizeof(cfg); - strcpy(phone.name, lp->name); - phone.outgoing = 0; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) { - restore_flags(flags); - return ret; - } else - dest += ret; - strcpy(phone.name, lp->name); - phone.outgoing = 1; - if ((ret = isdn_net_getphones(&phone, dest)) < 0) { - restore_flags(flags); - return ret; - } else - dest += ret; - put_user(0, dest); - p = p->next; - } - restore_flags(flags); - return 0; -} -#endif static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) @@ -1316,6 +1484,17 @@ } else return -EINVAL; break; +#ifdef CONFIG_NETDEVICES + case IIOCNETGPN: + /* Get peer phone number of a connected + * isdn network interface */ + if (arg) { + if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + return -EFAULT; + return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); + } else + return -EINVAL; +#endif default: return -EINVAL; } @@ -1327,7 +1506,7 @@ if (drvidx < 0) return -ENODEV; chidx = isdn_minor2chan(minor); - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; return 0; } @@ -1513,26 +1692,11 @@ } if (drvidx == -1) return -ENODEV; - dev->drv[drvidx]->reject_bus = iocts.arg; - return 0; -#if 0 - case IIOCGETSET: - /* Get complete setup (all network-interfaces and profile- - settings of all tty-devices */ - if (arg) - return (isdn_get_allcfg((char *) arg)); - else - return -EINVAL; - break; - case IIOCSETSET: - /* Set complete setup (all network-interfaces and profile- - settings of all tty-devices */ - if (arg) - return (isdn_set_allcfg((char *) arg)); + if (iocts.arg) + dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; else - return -EINVAL; - break; -#endif + dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; + return 0; case IIOCSIGPRF: dev->profd = current; return 0; @@ -1544,7 +1708,7 @@ int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; @@ -1556,8 +1720,11 @@ if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; + if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) + return -EFAULT; + p += ISDN_LMSNLEN; } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS; + return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; @@ -1721,7 +1888,6 @@ uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; - isdn_ctrl c; if (minor == ISDN_MINOR_STATUS) { infostruct *p; @@ -1744,31 +1910,25 @@ if (drvidx < 0) return -ENODEV; chidx = isdn_minor2chan(minor); - if (!dev->drv[drvidx]->running) + if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; - if (!(dev->drv[drvidx]->flags & (1 << chidx))) + if (!(dev->drv[drvidx]->online & (1 << chidx))) return -ENODEV; - c.command = ISDN_CMD_LOCK; - c.driver = drvidx; - isdn_command(&c); - MOD_INC_USE_COUNT; + isdn_MOD_INC_USE_COUNT(); return 0; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) return -ENODEV; - c.command = ISDN_CMD_LOCK; - c.driver = drvidx; - MOD_INC_USE_COUNT; - isdn_command(&c); + isdn_MOD_INC_USE_COUNT(); return 0; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { int ret; if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) - MOD_INC_USE_COUNT; + isdn_MOD_INC_USE_COUNT(); return ret; } #endif @@ -1779,13 +1939,12 @@ isdn_close(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); - int drvidx; - isdn_ctrl c; - MOD_DEC_USE_COUNT; if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; + + MOD_DEC_USE_COUNT; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) @@ -1801,24 +1960,12 @@ printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); return 0; } - if (minor < ISDN_MINOR_CTRL) { - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return 0; - c.command = ISDN_CMD_UNLOCK; - c.driver = drvidx; - isdn_command(&c); + isdn_MOD_DEC_USE_COUNT(); + if (minor < ISDN_MINOR_CTRL) return 0; - } if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - return 0; if (dev->profd == current) dev->profd = NULL; - c.command = ISDN_CMD_UNLOCK; - c.driver = drvidx; - isdn_command(&c); return 0; } #ifdef CONFIG_ISDN_PPP @@ -1872,7 +2019,6 @@ ulong flags; ulong features; ulong vfeatures; - isdn_ctrl cmd; save_flags(flags); cli(); @@ -1890,7 +2036,9 @@ if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) continue; - if ((dev->drv[d]->running)) { + if (dev->usage[i] & ISDN_USAGE_DISABLED) + continue; /* usage not allowed */ + if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { if (((dev->drv[d]->interface->features & features) == features) || (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { @@ -1898,10 +2046,6 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); restore_flags(flags); return i; } else { @@ -1909,10 +2053,6 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = d; - cmd.arg = 0; - cmd.command = ISDN_CMD_LOCK; - isdn_command(&cmd); restore_flags(flags); return i; } @@ -1932,7 +2072,6 @@ { int i; ulong flags; - isdn_ctrl cmd; save_flags(flags); cli(); @@ -1946,12 +2085,6 @@ dev->obytes[i] = 0; isdn_info_update(); isdn_free_queue(&dev->drv[di]->rpqueue[ch]); - cmd.driver = di; - cmd.arg = ch; - cmd.command = ISDN_CMD_UNLOCK; - restore_flags(flags); - isdn_command(&cmd); - return; } restore_flags(flags); } @@ -1996,7 +2129,6 @@ copy_from_user(skb_put(skb, len), buf, len); else memcpy(skb_put(skb, len), buf, len); - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); if (ret <= 0) dev_kfree_skb(skb); @@ -2052,19 +2184,233 @@ return ret; } +int +register_isdn_module(isdn_module *m) { +#if 0 + isdn_module_list **pp = &dev->modules; + isdn_module *new = kmalloc(sizeof(isdn_module_list), GFP_KERNEL); + + if (!new) { + printk(KERN_WARNING "isdn: Out of memory in register_isdn_module\n"); + return -1; + } + while (*pp && (*pp)->orig != m) + pp = &(*pp)->next; + if (*pp != NULL) { + printk(KERN_WARNING "isdn: Module %s already registered\n", m->name); + return -1; + } + while (*pp && ((*pp)->module.priority < m->priority)) + pp = &(*pp)->next; + new->next = *pp; + new->orig = m; + new->module = *m; + + *pp = new; +#endif + return 0; +} + +int +unregister_isdn_module(isdn_module *m) { +#if 0 + isdn_module_list **pp = &dev->modules; + + while (*pp && *pp != m) + pp = &(*pp)->next; + if (*pp == NULL) { + printk(KERN_WARNING "isdn: Module %s not found\n", m->name); + return -1; + } +#endif + return 0; +} + +int +isdn_add_channels(driver *d, int drvidx, int n, int adding) +{ + int j, k, m; + ulong flags; + +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&d->st_waitq); +#endif + if (d->flags & DRV_FLAG_RUNNING) + return -1; + if (n < 1) return 0; + + m = (adding) ? d->channels + n : n; + + if (dev->channels + n > ISDN_MAX_CHANNELS) { + printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", + ISDN_MAX_CHANNELS); + return -1; + } + + if ((adding) && (d->rcverr)) + kfree(d->rcverr); + if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); + return -1; + } + memset((char *) d->rcverr, 0, sizeof(int) * m); + + if ((adding) && (d->rcvcount)) + kfree(d->rcvcount); + if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); + if (!adding) kfree(d->rcverr); + return -1; + } + memset((char *) d->rcvcount, 0, sizeof(int) * m); + + if ((adding) && (d->rpqueue)) { + for (j = 0; j < d->channels; j++) + isdn_free_queue(&d->rpqueue[j]); + kfree(d->rpqueue); + } + if (!(d->rpqueue = + (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); + if (!adding) { + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; + } + for (j = 0; j < m; j++) { + skb_queue_head_init(&d->rpqueue[j]); + } + + if ((adding) && (d->rcv_waitq)) + kfree(d->rcv_waitq); +#ifdef COMPAT_HAS_NEW_WAITQ + d->rcv_waitq = (wait_queue_head_t *) + kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); + if (!d->rcv_waitq) { +#else + if (!(d->rcv_waitq = (struct wait_queue **) + kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { +#endif + printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); + if (!adding) { + kfree(d->rpqueue); + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; + } +#ifdef COMPAT_HAS_NEW_WAITQ + d->snd_waitq = d->rcv_waitq + m; + for (j = 0; j < m; j++) { + init_waitqueue_head(&d->rcv_waitq[m]); + init_waitqueue_head(&d->snd_waitq[m]); + } +#else + memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m); + + if ((adding) && (d->snd_waitq)) + kfree(d->snd_waitq); + if (!(d->snd_waitq = (struct wait_queue **) + kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) { + printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n"); + if (!adding) { + kfree(d->rcv_waitq); + kfree(d->rpqueue); + kfree(d->rcvcount); + kfree(d->rcverr); + } + return -1; + } + memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m); +#endif + + dev->channels += n; + save_flags(flags); + cli(); + for (j = d->channels; j < m; j++) + for (k = 0; k < ISDN_MAX_CHANNELS; k++) + if (dev->chanmap[k] < 0) { + dev->chanmap[k] = j; + dev->drvmap[k] = drvidx; + break; + } + restore_flags(flags); + d->channels = m; + return 0; +} + /* * Low-level-driver registration */ + +#ifdef CONFIG_ISDN_DIVERSION +extern isdn_divert_if *divert_if; + +static char *map_drvname(int di) +{ + if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) + return(NULL); + return(dev->drvid[di]); /* driver name */ +} /* map_drvname */ + +static int map_namedrv(char *id) +{ int i; + + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + { if (!strcmp(dev->drvid[i],id)) + return(i); + } + return(-1); +} /* map_namedrv */ + +int DIVERT_REG_NAME(isdn_divert_if *i_div) +{ + if (i_div->if_magic != DIVERT_IF_MAGIC) + return(DIVERT_VER_ERR); + switch (i_div->cmd) + { + case DIVERT_CMD_REL: + if (divert_if != i_div) + return(DIVERT_REL_ERR); + divert_if = NULL; /* free interface */ + MOD_DEC_USE_COUNT; + return(DIVERT_NO_ERR); + + case DIVERT_CMD_REG: + if (divert_if) + return(DIVERT_REG_ERR); + i_div->ll_cmd = isdn_command; /* set command function */ + i_div->drv_to_name = map_drvname; + i_div->name_to_drv = map_namedrv; + MOD_INC_USE_COUNT; + divert_if = i_div; /* remember interface */ + return(DIVERT_NO_ERR); + + default: + return(DIVERT_CMD_ERR); + } +} /* DIVERT_REG_NAME */ + +EXPORT_SYMBOL(DIVERT_REG_NAME); + +#endif CONFIG_ISDN_DIVERSION + + EXPORT_SYMBOL(register_isdn); +EXPORT_SYMBOL(register_isdn_module); +EXPORT_SYMBOL(unregister_isdn_module); +#ifdef CONFIG_ISDN_PPP +EXPORT_SYMBOL(isdn_ppp_register_compressor); +EXPORT_SYMBOL(isdn_ppp_unregister_compressor); +#endif int register_isdn(isdn_if * i) { driver *d; - int n, - j, - k; + int j; ulong flags; int drvidx; @@ -2073,12 +2419,6 @@ ISDN_MAX_DRIVERS); return 0; } - n = i->channels; - if (dev->channels + n > ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", - ISDN_MAX_CHANNELS); - return 0; - } if (!i->writebuf_skb) { printk(KERN_WARNING "register_isdn: No write routine given.\n"); return 0; @@ -2088,64 +2428,22 @@ return 0; } memset((char *) d, 0, sizeof(driver)); - if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); - kfree(d); - return 0; - } - memset((char *) d->rcverr, 0, sizeof(int) * n); - if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - kfree(d->rcverr); - kfree(d); - return 0; - } - memset((char *) d->rcvcount, 0, sizeof(int) * n); - if (!(d->rpqueue = - (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; - } - for (j = 0; j < n; j++) { - skb_queue_head_init(&d->rpqueue[j]); - } - if (!(d->rcv_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; - } - memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * n); - if (!(d->snd_waitq = (struct wait_queue **) - kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n"); - kfree(d->rcv_waitq); - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - kfree(d); - return 0; - } - memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * n); - d->channels = n; - d->loaded = 1; + d->maxbufsize = i->maxbufsize; d->pktcount = 0; d->stavail = 0; - d->running = 0; - d->flags = 0; + d->flags = DRV_FLAG_LOADED; + d->online = 0; d->interface = i; + d->channels = 0; for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) if (!dev->drv[drvidx]) break; + if (isdn_add_channels(d, drvidx, i->channels, 0)) { + kfree(d); + return 0; + } i->channels = drvidx; - i->rcvcallb_skb = isdn_receive_skb_callback; i->statcallb = isdn_status_callback; if (!strlen(i->id)) @@ -2155,15 +2453,7 @@ for (j = 0; j < drvidx; j++) if (!strcmp(i->id, dev->drvid[j])) sprintf(i->id, "line%d", drvidx); - for (j = 0; j < n; j++) - for (k = 0; k < ISDN_MAX_CHANNELS; k++) - if (dev->chanmap[k] < 0) { - dev->chanmap[k] = j; - dev->drvmap[k] = drvidx; - break; - } dev->drv[drvidx] = d; - dev->channels += n; strcpy(dev->drvid[drvidx], i->id); isdn_info_update(); dev->drivers++; @@ -2215,12 +2505,21 @@ memset((char *) dev, 0, sizeof(isdn_dev)); init_timer(&dev->timer); dev->timer.function = isdn_timer_funct; +#ifdef COMPAT_HAS_NEW_WAITQ + init_MUTEX(&dev->sem); + init_waitqueue_head(&dev->info_waitq); +#else dev->sem = MUTEX; +#endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; dev->m_idx[i] = -1; strcpy(dev->num[i], "???"); +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&dev->mdm.info[i].open_wait); + init_waitqueue_head(&dev->mdm.info[i].close_wait); +#endif } if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { printk(KERN_WARNING "isdn: Could not register control devices\n"); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v2.2.10/linux/drivers/isdn/isdn_common.h Tue Jan 19 11:06:52 1999 +++ linux/drivers/isdn/isdn_common.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_common.h,v 1.9 1998/02/20 17:19:01 fritz Exp $ +/* $Id: isdn_common.h,v 1.16 1999/07/01 08:29:54 keil Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,39 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_common.h,v $ + * Revision 1.16 1999/07/01 08:29:54 keil + * compatibility to 2.3 kernel + * + * Revision 1.15 1999/04/18 14:06:50 fritz + * Removed TIMRU stuff. + * + * Revision 1.14 1999/04/12 12:33:18 fritz + * Changes from 2.0 tree. + * + * Revision 1.13 1999/03/02 12:04:47 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.12 1998/06/26 15:12:27 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.11 1998/04/14 16:28:47 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.10 1998/03/07 18:21:03 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * * Revision 1.9 1998/02/20 17:19:01 fritz * Added common stub for sending commands to lowlevel. * @@ -90,10 +118,16 @@ extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); +#ifdef COMPAT_HAS_NEW_WAITQ +extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); +#else extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**); +#endif extern int isdn_get_free_channel(int, int, int, int, int); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); +extern int isdn_wildmat(char *, char *); +extern int isdn_add_channels(driver *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); #endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c --- v2.2.10/linux/drivers/isdn/isdn_concap.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/isdn_concap.c Mon Aug 9 12:04:39 1999 @@ -1,10 +1,21 @@ -/* $Id: isdn_concap.c,v 1.2 1998/01/31 22:49:21 keil Exp $ +/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. * * $Log: isdn_concap.c,v $ + * Revision 1.5 1998/10/30 18:44:48 he + * pass return value from isdn_net_dial_req for dialmode change + * + * Revision 1.4 1998/10/30 17:55:24 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.3 1998/05/26 22:39:22 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * * Revision 1.2 1998/01/31 22:49:21 keil * correct comments * @@ -20,14 +31,9 @@ #include #include "isdn_concap.h" -/* The declaration of this (or a plublic variant thereof) should really go - in linux/isdn.h. But we really need it here (and isdn_ppp, like us, also - refers to that private function currently owned by isdn_net.c) */ -extern int isdn_net_force_dial_lp(isdn_net_local *); - /* The following set of device service operations are for encapsulation - protocols that require for reliable datalink sematics. That means: + protocols that require for reliable datalink semantics. That means: - before any data is to be submitted the connection must explicitly be set up. @@ -66,9 +72,9 @@ IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name); /* dial ... */ - ret = isdn_net_force_dial_lp( lp ); + ret = isdn_net_dial_req( lp ); if ( ret ) IX25DEBUG("dialing failed\n"); - return 0; + return ret; } int isdn_concap_dl_disconn_req(struct concap_proto *concap) diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.2.10/linux/drivers/isdn/isdn_net.c Tue Jan 19 11:06:52 1999 +++ linux/drivers/isdn/isdn_net.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_net.c,v 1.55 1998/02/23 19:38:22 fritz Exp $ +/* $Id: isdn_net.c,v 1.88 1999/07/07 10:13:31 detabc Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -20,11 +20,105 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_net.c,v $ + * Revision 1.88 1999/07/07 10:13:31 detabc + * remove unused messages + * + * Revision 1.87 1999/07/06 07:53:53 calle + * calls to dev_alloc_skb waste 16 bytes of memory, if we calculate the + * right header space for the lowlevel driver. using alloc_skb instead. + * + * Revision 1.86 1999/06/09 10:12:05 paul + * thinko in previous patch + * + * Revision 1.85 1999/06/07 19:42:39 paul + * isdn_net_getpeer() fixed to return correct `outgoing' flag + * + * Revision 1.84 1999/04/18 14:06:55 fritz + * Removed TIMRU stuff. + * + * Revision 1.83 1999/04/12 12:33:23 fritz + * Changes from 2.0 tree. + * + * Revision 1.82 1999/01/17 00:55:58 he + * added mark_bh in BCONN statcallb and cleaned up some dead code + * + * Revision 1.81 1999/01/15 16:36:52 he + * replaced icmp_send() by dst_link_failure() + * + * Revision 1.80 1998/12/01 13:06:22 paul + * Also huptimeout with dialmode == manual + * + * Revision 1.79 1998/10/30 17:55:27 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.78 1998/10/26 18:20:46 he + * re-inserted p=p->next in isdn_net_find_icall() (fixes kernel lock up + * on incoming call not matching the first interface) + * + * Revision 1.77 1998/10/23 10:18:44 paul + * Implementation of "dialmode" (successor of "status") + * You also need current isdnctrl for this! + * + * Revision 1.76 1998/09/07 22:00:05 he + * flush method for 2.1.118 and above + * updated IIOCTLNETGPN + * + * Revision 1.75 1998/08/31 21:09:50 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * + * Revision 1.74 1998/07/30 11:28:32 paul + * printk message only appeared when status is off and interface is rawIP, + * which is confusing for people who don't know about "isdnctrl status on". + * + * Revision 1.73 1998/06/26 22:01:37 keil + * tx_queue_len = 5 was too small + * + * Revision 1.72 1998/06/26 15:12:31 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.71 1998/06/18 22:43:08 fritz + * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at cleanup. + * + * Revision 1.70 1998/06/17 19:50:49 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.69 1998/06/09 12:27:37 cal + * Changed default of local netdev flags: ISDN_NET_STOPPED is default now, + * so autodial is suppressed for that device until it is switched on using + * 'isdnctrl status dev-name on'. + * + * + * + * Revision 1.66 1998/05/26 22:39:24 he + * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) + * concap typo + * cleared dev.tbusy in isdn_net BCONN status callback + * + * Revision 1.61 1998/04/16 19:19:42 keil + * Fix from vger (tx max qlength) + * + * Revision 1.60 1998/04/14 16:28:49 he + * Fixed user space access with interrupts off and remaining + * copy_{to,from}_user() -> -EFAULT return codes + * + * Revision 1.59 1998/03/07 22:37:33 fritz + * Bugfix: restore_flags missing. + * + * Revision 1.58 1998/03/07 18:21:05 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.57 1998/02/25 18:31:13 fritz + * Added debugging output in adjust_header. + * + * Revision 1.56 1998/02/25 17:49:42 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.55 1998/02/23 19:38:22 fritz * Corrected check for modified feature-flags. * @@ -248,9 +342,7 @@ #include #include #include -#ifndef DEV_NUMBUFFS #include -#endif #include #include "isdn_common.h" #include "isdn_net.h" @@ -265,14 +357,10 @@ /* Prototypes */ int isdn_net_force_dial_lp(isdn_net_local *); -static int isdn_net_wildmat(char *s, char *p); static int isdn_net_start_xmit(struct sk_buff *, struct device *); static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -#ifdef DEV_NUMBUFFS -static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -#endif -char *isdn_net_revision = "$Revision: 1.55 $"; +char *isdn_net_revision = "$Revision: 1.88 $"; /* * Code for raw-networking over ISDN @@ -293,16 +381,21 @@ dst_link_failure(skb); } + else { /* dial not triggered by rawIP packet */ + printk(KERN_DEBUG "isdn_net: %s: %s\n", + dev->name, + (reason != NULL) ? reason : "reason unknown"); + } } static void isdn_net_reset(struct device *dev) { #ifdef CONFIG_ISDN_X25 - struct concap_device_ops * dops = + struct concap_device_ops * dops = ( (isdn_net_local *) dev->priv ) -> dops; - struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; #endif ulong flags; @@ -311,7 +404,7 @@ dev->interrupt = 0; dev->tbusy = 0; #ifdef CONFIG_ISDN_X25 - if( cprot && cprot -> pops && dops ) + if( cprot && cprot -> pops && dops ) cprot -> pops -> restart ( cprot, dev, dops ); #endif restore_flags(flags); @@ -338,7 +431,7 @@ if (ifa != NULL) memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); } - + /* If this interface has slaves, start them also */ if ((p = (((isdn_net_local *) dev->priv)->slave))) { @@ -362,6 +455,7 @@ save_flags(flags); cli(); + lp->flags |= ISDN_NET_CONNECTED; lp->isdn_device = dev->drvmap[idx]; lp->isdn_channel = dev->chanmap[idx]; dev->rx_netdev[idx] = lp->netdev; @@ -387,10 +481,6 @@ dev_kfree_skb(lp->sav_skb); lp->sav_skb = NULL; } -#ifdef DEV_NUMBUFFS - if (!lp->master) /* purge only for master device */ - dev_purge_queues(&lp->netdev->dev); -#else if (!lp->master) { /* reset only master device */ /* Moral equivalent of dev_purge_queues(): BEWARE! This chunk of code cannot be called from hardware @@ -398,7 +488,6 @@ */ qdisc_reset(lp->netdev->dev.qdisc); } -#endif lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; @@ -444,7 +533,13 @@ if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { anymore = 1; l->huptimer++; - if ((l->onhtime) && (l->huptimer > l->onhtime)) { + /* + * if there is some dialmode where timeout-hangup + * should _not_ be done, check for that here + */ + if ((l->onhtime) && + (l->huptimer > l->onhtime)) + { if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) { while (jiffies - l->chargetime > l->chargeint) @@ -469,6 +564,11 @@ } else if (l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); } + + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { + isdn_net_hangup(&p->dev); + break; + } } p = (isdn_net_dev *) p->next; } @@ -487,7 +587,7 @@ { isdn_net_dev *p = dev->st_netdev[idx]; int cmd = c->command; - + if (p) { isdn_net_local *lp = p->local; #ifdef CONFIG_ISDN_X25 @@ -538,23 +638,12 @@ failed. If there are generic encap protocol receiver routines signal the closure of the link*/ - - if( !(lp->flags & ISDN_NET_CONNECTED) + + if( !(lp->flags & ISDN_NET_CONNECTED) && pops && pops -> disconn_ind ) pops -> disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { - lp->flags &= ~ISDN_NET_CONNECTED; - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb); - lp->first_skb = NULL; - } - if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb); - lp->sav_skb = NULL; - } - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif @@ -562,10 +651,7 @@ printk(KERN_INFO "%s: remote hangup\n", lp->name); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); - lp->isdn_device = -1; - lp->isdn_channel = -1; - dev->st_netdev[idx] = NULL; - dev->rx_netdev[idx] = NULL; + isdn_net_unbind_channel(lp); return 1; } break; @@ -607,6 +693,11 @@ lp->chargetime = jiffies; printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", lp->name, lp->chargetime); + + /* reset dial-timeout */ + lp->dialstarted = 0; + lp->dialwait_timer = 0; + /* Immediately send first skb to speed up arp */ #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) @@ -617,13 +708,13 @@ if( pops ) if( pops->connect_ind) pops->connect_ind(cprot); - #endif /* CONFIG_ISDN_X25 */ if (lp->first_skb) { - + if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb))) lp->first_skb = NULL; - } else { + } + else { /* * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb). * With an empty lp->first_skb, we need to do this ourselves @@ -721,6 +812,13 @@ break; } anymore = 1; + + if(lp->dialtimeout > 0) + if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) { + lp->dialstarted = jiffies; + lp->dialwait_timer = 0; + } + lp->dialstate++; /* Fall through */ case 2: @@ -735,12 +833,22 @@ lp->dialretry = 0; anymore = 1; lp->dialstate++; - /* Falls through */ + /* Fall through */ case 3: /* Setup interface, dial current phone-number, switch to next number. * If list of phone-numbers is exhausted, increment * retry-counter. */ + if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { + char *s; + if (dev->global_flags & ISDN_GLOBAL_STOPPED) + s = "dial suppressed: isdn system stopped"; + else + s = "dial suppressed: dialmode `off'"; + isdn_net_unreachable(&p->dev, lp->first_skb, s); + isdn_net_hangup(&p->dev); + break; + } cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_SETL2; cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); @@ -765,6 +873,16 @@ lp->dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", lp->name); } else { + if(lp->dialtimeout > 0) + if(jiffies > (lp->dialstarted + lp->dialtimeout)) { + restore_flags(flags); + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out"); + isdn_net_hangup(&p->dev); + break; + } + sprintf(cmd.parm.setup.phone, "%s", lp->dial->num); /* * Switch to next number or back to start if at end of list. @@ -772,6 +890,17 @@ if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { lp->dial = lp->phone[1]; lp->dialretry++; + + if (lp->dialretry > lp->dialmax) { + restore_flags(flags); + if (lp->dialtimeout == 0) { + lp->dialwait_timer = jiffies + lp->dialwait; + lp->dialstarted = 0; + isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times"); + } + isdn_net_hangup(&p->dev); + break; + } } restore_flags(flags); cmd.driver = lp->isdn_device; @@ -786,7 +915,7 @@ isdn_info_update(); } printk(KERN_INFO "%s: dialing %d %s...\n", lp->name, - lp->dialretry - 1, cmd.parm.setup.phone); + lp->dialretry, cmd.parm.setup.phone); lp->dtimer = 0; #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, @@ -810,15 +939,11 @@ break; case 4: /* Wait for D-Channel-connect. - * If timeout and max retries not - * reached, switch back to state 3. + * If timeout, switch back to state 3. + * Dialmax-handling moved to state 3. */ - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) { - if (lp->dialretry < lp->dialmax) { - lp->dialstate = 3; - } else - isdn_net_hangup(&p->dev); - } + if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) + lp->dialstate = 3; anymore = 1; break; case 5: @@ -895,7 +1020,8 @@ /* Remote does callback. Hangup after cbdelay, then wait for incoming * call (in state 4). */ - if (lp->dtimer++ > lp->cbdelay) { + if (lp->dtimer++ > lp->cbdelay) + { printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name); lp->dtimer = 0; lp->dialstate = 4; @@ -930,7 +1056,6 @@ #endif if (lp->flags & ISDN_NET_CONNECTED) { - lp->flags &= ~ISDN_NET_CONNECTED; printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); @@ -938,7 +1063,7 @@ #ifdef CONFIG_ISDN_X25 /* try if there are generic encap protocol receiver routines and signal the closure of - the link */ + the link */ if( pops && pops -> disconn_ind ) pops -> disconn_ind(cprot); #endif /* CONFIG_ISDN_X25 */ @@ -968,7 +1093,7 @@ char addinfo[100]; addinfo[0] = '\0'; - /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ + /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) { /* fall back to old isdn_net_log_packet method() */ char * buf = skb->data; @@ -1062,20 +1187,17 @@ if (ret == len) { lp->transcount += len; clear_bit(0, (void *) &(ndev->tbusy)); - mark_bh(NET_BH); return 0; } if (ret < 0) { dev_kfree_skb(skb); lp->stats.tx_errors++; clear_bit(0, (void *) &(ndev->tbusy)); - mark_bh(NET_BH); return 0; } return 1; } - /* * Helper function for isdn_net_start_xmit. * When called, the connection is already established. @@ -1150,9 +1272,11 @@ if (!skb) return; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - ulong pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; - if (pullsize) + int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN; + if (pullsize > 0) { + printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); skb_pull(skb, pullsize); + } } } @@ -1166,7 +1290,7 @@ { isdn_net_local *lp = (isdn_net_local *) ndev->priv; #ifdef CONFIG_ISDN_X25 - struct concap_proto * cprot = lp -> netdev -> cprot; + struct concap_proto * cprot = lp -> netdev -> cprot; #endif if (ndev->tbusy) { @@ -1179,7 +1303,7 @@ ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */ #ifdef CONFIG_ISDN_X25 /* At this point hard_start_xmit() passes control to the encapsulation - protocol (if present). + protocol (if present). For X.25 auto-dialing is completly bypassed because: - It does not conform with the semantics of a reliable datalink service as needed by X.25 PLP. @@ -1205,17 +1329,46 @@ #endif if (!(lp->flags & ISDN_NET_CONNECTED)) { int chi; + /* only do autodial if allowed by config */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { + isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); + dev_kfree_skb(skb); + ndev->tbusy = 0; + return 0; + } if (lp->phone[1]) { ulong flags; save_flags(flags); cli(); + + if(lp->dialwait_timer <= 0) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait) + lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; + + if(lp->dialwait_timer > 0) { + if(jiffies < lp->dialwait_timer) { + isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); + dev_kfree_skb(skb); + ndev->tbusy = 0; + restore_flags(flags); + return 0; + } else + lp->dialwait_timer = 0; + } + /* Grab a free ISDN-Channel */ - if ((chi = + if (((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, lp->pre_device, - lp->pre_channel)) < 0) { + lp->pre_channel)) < 0) && + ((chi = + isdn_get_free_channel(ISDN_USAGE_NET, + lp->l2_proto, + lp->l3_proto, + lp->pre_device, + lp->pre_channel^1)) < 0)) { restore_flags(flags); isdn_net_unreachable(ndev, skb, "No channel"); @@ -1227,7 +1380,6 @@ if (dev->net_verbose) isdn_net_log_skb(skb, lp); lp->dialstate = 1; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -1290,8 +1442,8 @@ { struct device *p; #ifdef CONFIG_ISDN_X25 - struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + struct concap_proto * cprot = + ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */ #endif @@ -1304,9 +1456,9 @@ /* If this interface has slaves, stop them also */ while (p) { #ifdef CONFIG_ISDN_X25 - cprot = ( (isdn_net_local *) p->priv ) - -> netdev -> cprot; - if( cprot && cprot -> pops ) + cprot = ( (isdn_net_local *) p->priv ) + -> netdev -> cprot; + if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif isdn_net_hangup(p); @@ -1387,12 +1539,12 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply) { unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - struct sk_buff *skb = dev_alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp)); + struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC); unsigned long t = (jiffies / HZ * 1000000); int len; cisco_hdr *ch; cisco_slarp *s; - + if (!skb) { printk(KERN_WARNING "%s: Could not allocate SLARP reply\n", lp->name); @@ -1406,7 +1558,7 @@ s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp)); if (is_reply) { s->code = htonl(CISCO_SLARP_REPLY); - memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); + memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32)); memset(&s->slarp.reply.netmask, 0, sizeof(__u32)); } else { lp->cisco_myseq++; @@ -1589,7 +1741,7 @@ default: #ifdef CONFIG_ISDN_X25 /* try if there are generic sync_device receiver routines */ - if(cprot) if(cprot -> pops) + if(cprot) if(cprot -> pops) if( cprot -> pops -> data_ind){ cprot -> pops -> data_ind(cprot,skb); return; @@ -1600,6 +1752,7 @@ kfree_skb(skb); return; } + netif_rx(skb); return; } @@ -1788,16 +1941,12 @@ ndev->type = ARPHRD_ETHER; ndev->addr_len = ETH_ALEN; - ndev->tx_queue_len = 10; /* for clients without MPPP 5 is better. */ + /* for clients with MPPP maybe higher values better */ + ndev->tx_queue_len = 30; for (i = 0; i < ETH_ALEN; i++) ndev->broadcast[i] = 0xff; -#ifdef DEV_NUMBUFFS - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&ndev->buffs[i]); -#endif - /* The ISDN-specific entries in the device structure. */ ndev->open = &isdn_net_open; ndev->hard_start_xmit = &isdn_net_start_xmit; @@ -1813,86 +1962,15 @@ max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; - ndev->stop = &isdn_net_close; ndev->get_stats = &isdn_net_get_stats; ndev->rebuild_header = &isdn_net_rebuild_header; - #ifdef CONFIG_ISDN_PPP ndev->do_ioctl = isdn_ppp_dev_ioctl; #endif return 0; } -/* - * I picked the pattern-matching-functions from an old GNU-tar version (1.10) - * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) - */ - -static int -isdn_net_Star(char *s, char *p) -{ - while (isdn_net_wildmat(s, p) == 0) - if (*++s == '\0') - return (0); - return (1); -} - -/* - * Shell-type Pattern-matching for incoming caller-Ids - * This function gets a string in s and checks, if it matches the pattern - * given in p. It returns 1 on success, 0 otherwise. - * - * Possible Patterns: - * - * '?' matches one character - * '*' matches zero or more characters - * [xyz] matches the set of characters in brackets. - * [^xyz] matches any single character not in the set of characters - */ - -static int -isdn_net_wildmat(char *s, char *p) -{ - register int last; - register int matched; - register int reverse; - - for (; *p; s++, p++) - switch (*p) { - case '\\': - /* - * Literal match with following character, - * fall through. - */ - p++; - default: - if (*s != *p) - return (0); - continue; - case '?': - /* Match anything. */ - if (*s == '\0') - return (0); - continue; - case '*': - /* Trailing star matches everything. */ - return (*++p ? isdn_net_Star(s, p) : 1); - case '[': - /* [^....] means inverse character class. */ - if ((reverse = (p[1] == '^'))) - p++; - for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) - /* This next line requires a good C compiler. */ - if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) - matched = 1; - if (matched == reverse) - return (0); - continue; - } - return (*s == '\0'); -} - static void isdn_net_swapbind(int drvidx) { @@ -1945,6 +2023,8 @@ * 2 = Reject call, wait cbdelay, then call back * 3 = Reject call * 4 = Wait cbdelay, then call back + * 5 = No appropriate interface for this call, + * would eventually match if CID was longer. */ int isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) @@ -1953,6 +2033,7 @@ int si1; int si2; int ematch; + int wret; int swapped; int sidx = 0; isdn_net_dev *p; @@ -1987,13 +2068,13 @@ } n = (isdn_net_phone *) 0; p = dev->netdev; - ematch = 0; + ematch = wret = swapped = 0; #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, dev->usage[idx]); #endif - swapped = 0; while (p) { + int matchret; isdn_net_local *lp = p->local; /* If last check has triggered as binding-swap, revert it */ @@ -2006,18 +2087,22 @@ break; } swapped = 0; - if (!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) + if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di)))) ematch = 1; + /* Remember if more numbers eventually can match */ + if (matchret > wret) + wret = matchret; #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", lp->name, lp->msn, lp->flags, lp->dialstate); #endif - if ((!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) && /* EAZ is matching */ - (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ - (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ - ))) { + if ((!matchret) && /* EAZ is matching */ + (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ + (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ + ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ + (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ + ))) + { #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", lp->pre_device, lp->pre_channel); @@ -2085,8 +2170,6 @@ #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: already on 2nd channel\n"); #endif - p = (isdn_net_dev *) p->next; - continue; } } } @@ -2096,7 +2179,7 @@ n = lp->phone[0]; if (lp->flags & ISDN_NET_SECURE) { while (n) { - if (isdn_net_wildmat(nr, n->num)) + if (!isdn_wildmat(nr, n->num)) break; n = (isdn_net_phone *) n->next; } @@ -2105,7 +2188,21 @@ #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match3\n"); #endif - /* Here we got an interface matched, now see if it is up. + /* matching interface found */ + + /* + * Is the state STOPPED? + * If so, no dialin is allowed, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + restore_flags(flags); + printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", + lp->name); + return 3; + } + /* + * Is the interface up? * If not, reject the call actively. */ if (!p->dev.start) { @@ -2140,6 +2237,17 @@ } if (lp->flags & ISDN_NET_CALLBACK) { int chi; + /* + * Is the state MANUAL? + * If so, no callback can be made, + * so reject actively. + * */ + if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { + restore_flags(flags); + printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", + lp->name); + return 3; + } printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", lp->name, nr, eaz); if (lp->phone[1]) { @@ -2155,7 +2263,6 @@ /* Setup dialstate. */ lp->dtimer = 0; lp->dialstate = 11; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -2217,10 +2324,10 @@ p = (isdn_net_dev *) p->next; } /* If none of configured EAZ/MSN matched and not verbose, be silent */ - if (ematch || dev->net_verbose) + if (!ematch || dev->net_verbose) printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); restore_flags(flags); - return 0; + return (wret == 2)?5:0; } /* @@ -2253,6 +2360,7 @@ ulong flags; save_flags(flags); cli(); + /* Grab a free ISDN-Channel */ if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto, @@ -2263,7 +2371,6 @@ return -EAGAIN; } lp->dialstate = 1; - lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); #ifdef CONFIG_ISDN_PPP @@ -2285,6 +2392,20 @@ } /* + * This is called from certain upper protocol layers (multilink ppp + * and x25iface encapsulation module) that want to initiate dialing + * themselves. + */ +int +isdn_net_dial_req(isdn_net_local * lp) +{ + /* is there a better error code? */ + if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; + + return isdn_net_force_dial_lp(lp); +} + +/* * Force a net-interface to dial out. * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). */ @@ -2383,8 +2504,13 @@ netdev->local->onhtime = 10; /* Default hangup-time for saving costs of those who forget configuring this */ netdev->local->dialmax = 1; - netdev->local->flags = ISDN_NET_CBHUP; /* Hangup before Callback */ + netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */ netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */ + netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */ + netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ + netdev->local->dialstarted = 0; /* Jiffies of last dial-start */ + netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ + /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; @@ -2465,7 +2591,7 @@ save_flags(flags); cli(); /* avoid races with incoming events trying to call cprot->pops methods */ - if( cprot && cprot -> pops ) + if( cprot && cprot -> pops ) cprot -> pops -> proto_del ( cprot ); p -> cprot = NULL; lp -> dops = NULL; @@ -2479,7 +2605,7 @@ p -> cprot = isdn_concap_new( cfg -> p_encap ); /* p -> cprot == NULL now if p_encap is not supported by means of the concap_proto mechanism */ - /* the protocol is not configured yet; this will + /* the protocol is not configured yet; this will happen later when isdn_net_reset() is called */ #endif } @@ -2508,7 +2634,7 @@ if( cfg->p_encap >= 0 && cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP ) break; - printk(KERN_WARNING + printk(KERN_WARNING "%s: encapsulation protocol %d not supported\n", p->local->name, cfg->p_encap); return -EINVAL; @@ -2583,6 +2709,8 @@ lp->triggercps = cfg->triggercps; lp->slavedelay = cfg->slavedelay * HZ; lp->pppbind = cfg->pppbind; + lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; + lp->dialwait = cfg->dialwait * HZ; if (cfg->secure) lp->flags |= ISDN_NET_SECURE; else @@ -2604,6 +2732,16 @@ lp->flags &= ~ISDN_NET_CALLBACK; break; } + lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ + if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { + /* old isdnctrl version, where only 0 or 1 is given */ + printk(KERN_WARNING + "Old isdnctrl version detected! Please update.\n"); + lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */ + } + else { + lp->flags |= cfg->dialmode; /* turn on selected bits */ + } if (cfg->chargehup) lp->hupflags |= ISDN_CHARGEHUP; else @@ -2671,6 +2809,7 @@ if (lp->flags & ISDN_NET_CBOUT) cfg->callback = 2; cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; + cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; cfg->chargehup = (lp->hupflags & 4) ? 1 : 0; cfg->ihup = (lp->hupflags & 8) ? 1 : 0; cfg->cbdelay = lp->cbdelay; @@ -2680,6 +2819,8 @@ cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ? (lp->chargeint / HZ) : 0; cfg->pppbind = lp->pppbind; + cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; + cfg->dialwait = lp->dialwait / HZ; if (lp->slave) strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name); else @@ -2749,9 +2890,37 @@ } /* - * Delete a phone-number from an interface. + * Copy a string containing the peer's phone number of a connected interface + * to user space. */ +int +isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer) +{ + isdn_net_dev *p = isdn_net_findif(phone->name); + int ch, dv, idx; + if (!p) return -ENODEV; + /* + * Theoretical race: while this executes, the remote number might + * become invalid (hang up) or change (new connection), resulting + * in (partially) wrong number copied to user. This race + * currently ignored. + */ + ch = p->local->isdn_channel; + dv = p->local->isdn_device; + if(ch<0 && dv<0) return -ENOTCONN; + idx = isdn_dc2minor(dv, ch); + if (idx<0) return -ENODEV; + /* for pre-bound channels, we need this extra check */ + if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN; + strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN); + phone->outgoing=USG_OUTGOING(dev->usage[idx]); + if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT; + return 0; +} +/* + * Delete a phone-number from an interface. + */ int isdn_net_delphone(isdn_net_ioctl_phone * phone) { @@ -2957,21 +3126,3 @@ restore_flags(flags); return 0; } - -#ifdef DEV_NUMBUFFS -/* - * helper function to flush device queues - * the better place would be net/core/dev.c - */ -static void -dev_purge_queues(struct device *dev) -{ - int i; - for (i = 0; i < DEV_NUMBUFFS; i++) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&dev->buffs[i]))) - dev_kfree_skb(skb); - } - -} -#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.2.10/linux/drivers/isdn/isdn_net.h Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/isdn_net.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_net.h,v 1.6 1997/10/09 21:28:54 fritz Exp $ +/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.9 1999/04/12 12:33:27 fritz + * Changes from 2.0 tree. + * + * Revision 1.8 1998/10/30 17:55:33 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.7 1998/08/31 21:09:55 he + * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' + * peer phone number) + * * Revision 1.6 1997/10/09 21:28:54 fritz * New HL<->LL interface: * New BSENT callback with nr. of bytes included. @@ -99,6 +109,7 @@ extern int isdn_net_getcfg(isdn_net_ioctl_cfg *); extern int isdn_net_addphone(isdn_net_ioctl_phone *); extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *); +extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); extern int isdn_net_delphone(isdn_net_ioctl_phone *); extern int isdn_net_find_icall(int, int, int, setup_parm); extern void isdn_net_hangup(struct device *); @@ -111,3 +122,4 @@ struct sk_buff *); extern int isdn_net_rcv_skb(int, struct sk_buff *); extern void isdn_net_slarp_out(void); +extern int isdn_net_dial_req(isdn_net_local *); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.2.10/linux/drivers/isdn/isdn_ppp.c Tue Jan 19 11:06:52 1999 +++ linux/drivers/isdn/isdn_ppp.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $ +/* $Id: isdn_ppp.c,v 1.49 1999/07/06 07:47:11 calle Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -18,11 +18,58 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Note: This file differs from the corresponding revision as present in the - * isdn4linux CVS repository because some later bug fixes have been extracted - * from the repository and merged into this file. -- Henner Eisen - * * $Log: isdn_ppp.c,v $ + * Revision 1.49 1999/07/06 07:47:11 calle + * bugfix: dev_alloc_skb only reserve 16 bytes. We need to look at the + * hdrlen the driver want. So I changed dev_alloc_skb calls + * to alloc_skb and skb_reserve. + * + * Revision 1.48 1999/07/01 08:29:56 keil + * compatibility to 2.3 kernel + * + * Revision 1.47 1999/04/18 14:06:59 fritz + * Removed TIMRU stuff. + * + * Revision 1.46 1999/04/12 12:33:35 fritz + * Changes from 2.0 tree. + * + * Revision 1.45 1998/12/30 17:48:24 paul + * fixed syncPPP callback out + * + * Revision 1.44 1998/10/30 17:55:34 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.43 1998/10/29 17:23:54 hipp + * Minor MPPP fixes, verboser logging. + * + * Revision 1.42 1998/07/20 11:30:07 hipp + * Readded compression check + * + * Revision 1.41 1998/07/08 16:50:57 hipp + * Compression changes + * + * Revision 1.40 1998/04/06 19:07:27 hipp + * added check, whether compression is enabled. + * + * Revision 1.39 1998/03/25 22:46:53 hipp + * Some additional CCP changes. + * + * Revision 1.38 1998/03/24 16:33:06 hipp + * More CCP changes. BSD compression now "works" on a local loopback link. + * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h + * + * Revision 1.37 1998/03/22 18:50:49 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * + * Revision 1.36 1998/03/09 17:46:30 he + * merged in 2.1.89 changes + * + * Revision 1.35 1998/03/07 18:21:11 cal + * Dynamic Timeout-Rule-Handling vs. 971110 included + * + * Revision 1.34 1998/02/25 17:49:48 he + * Changed return codes caused be failing copy_{to,from}_user to -EFAULT + * * Revision 1.33 1998/02/20 17:11:54 fritz * Changes for recent kernels. * @@ -157,13 +204,16 @@ * experimental for dynamic addressing: readdress IP frames */ #undef ISDN_SYNCPPP_READDRESS +#define CONFIG_ISDN_CCP 1 #include #define __NO_VERSION__ #include #include -#include #include +#include +#include + #include "isdn_common.h" #include "isdn_ppp.h" #include "isdn_net.h" @@ -180,13 +230,33 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); -static int isdn_ppp_set_compressor(struct ippp_struct *is,int num); +static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *); static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *,struct ippp_struct *); + struct ippp_struct *,struct ippp_struct *,int proto); static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, - struct sk_buff *skb); + struct sk_buff *skb,int proto); static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, struct ippp_struct *is,struct ippp_struct *master,int type); +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, + struct sk_buff *skb); + +/* New CCP stuff */ +static void isdn_ppp_ccp_kickup(struct ippp_struct *is); +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len); +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_timer_callback(unsigned long closure); +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id); +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp); +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id); + + #ifdef CONFIG_ISDN_MPP static int isdn_ppp_bundle(struct ippp_struct *, int unit); @@ -199,18 +269,16 @@ static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.33 $"; +char *isdn_ppp_revision = "$Revision: 1.49 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; static struct isdn_ppp_compressor *ipc_head = NULL; -extern int isdn_net_force_dial_lp(isdn_net_local *); - /* * frame log (debug) */ static void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen) +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) { int cnt, j, @@ -223,13 +291,14 @@ for (i = 0, cnt = 0; cnt < maxlen; i++) { for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]); - printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf); + printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf); } } /* * unbind isdn_net_local <=> ippp-device * note: it can happen, that we hangup/free the master before the slaves + * in this case we bind another lp to the master device */ int isdn_ppp_free(isdn_net_local * lp) @@ -267,8 +336,7 @@ if ((is->state & IPPP_CONNECT)) isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) - is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGEND' staet */ - + is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ if (is->debug & 0x1) printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); @@ -320,14 +388,16 @@ } } } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN) + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + if (ippp_table[i]->minor == lp->pppbind && + (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) break; + } } if (i >= ISDN_MAX_CHANNELS) { restore_flags(flags); - printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n"); + printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); return -1; } unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */ @@ -336,6 +406,15 @@ return -1; } lp->ppp_slot = i; + + /* reset some values */ + lp->netdev->ib.bundled = 0; + lp->netdev->ib.next_num = 0; + lp->netdev->ib.modify = 0; + lp->netdev->ib.last = NULL; + lp->netdev->ib.min = 0; + lp->netdev->ib.sq = NULL; + is = ippp_table[i]; is->lp = lp; is->unit = unit; @@ -359,7 +438,9 @@ ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; +#ifndef COMPAT_HAS_NEW_WAITQ if (ippp_table[lp->ppp_slot]->wq) +#endif wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); } @@ -377,7 +458,11 @@ return 0; is = ippp_table[slot]; +#ifdef COMPAT_HAS_NEW_WAITQ + if (is->state) +#else if (is->state && is->wq) +#endif wake_up_interruptible(&is->wq); is->state = IPPP_CLOSEWAIT; @@ -418,14 +503,19 @@ } is = file->private_data = ippp_table[slot]; +#if 0 if (is->debug & 0x1) +#endif printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state); /* compression stuff */ - is->compressor = NULL; - is->decomp_stat = is->comp_stat = NULL; - is->link_compressor = NULL; - is->link_decomp_stat = is->link_comp_stat = NULL; + is->link_compressor = is->compressor = NULL; + is->link_decompressor = is->decompressor = NULL; + is->link_comp_stat = is->comp_stat = NULL; + is->link_decomp_stat = is->decomp_stat = NULL; + is->compflags = 0; + + is->reset = isdn_ppp_ccp_reset_alloc(is); is->lp = NULL; is->mp_seqno = 0; /* MP sequence number */ @@ -437,8 +527,11 @@ is->mru = 1524; /* MRU, default 1524 */ is->maxcid = 16; /* VJ: maxcid */ is->tk = current; +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&is->wq); +#else is->wq = NULL; /* read() wait queue */ - is->wq1 = NULL; /* select() wait queue */ +#endif is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; is->minor = min; @@ -491,10 +584,30 @@ is->last = is->rq; #ifdef CONFIG_ISDN_PPP_VJ +/* TODO: if this was the previous master: link the slcomp to the new master */ slhc_free(is->slcomp); is->slcomp = NULL; #endif +/* TODO: if this was the previous master: link the the stuff to the new master */ + if(is->comp_stat) + is->compressor->free(is->comp_stat); + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->compressor = is->link_compressor = NULL; + is->decompressor = is->link_decompressor = NULL; + is->comp_stat = is->link_comp_stat = NULL; + is->decomp_stat = is->link_decomp_stat = NULL; + + if(is->reset) + kfree(is->reset); + is->reset = NULL; + + /* this slot is ready for new connections */ is->state = 0; } @@ -505,7 +618,7 @@ get_arg(void *b, void *val, int len) { if (len <= 0) - len = sizeof(unsigned long); + len = sizeof(void *); if (copy_from_user((void *) val, b, len)) return -EFAULT; return 0; @@ -515,15 +628,12 @@ * set arg .. ioctl helper */ static int -set_arg(void *b, unsigned long val, void *str) +set_arg(void *b, void *val,int len) { - if (!str) { - if (copy_to_user(b, (void *) &val, 4)) - return -EFAULT; - } else { - if (copy_to_user(b, str, val)) - return -EFAULT; - } + if(len <= 0) + len = sizeof(void *); + if (copy_to_user(b, (void *) val, len)) + return -EFAULT; return 0; } @@ -534,9 +644,10 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long val; - int num,r; + int r,i,j; struct ippp_struct *is; isdn_net_local *lp; + struct isdn_ppp_comp_data data; is = (struct ippp_struct *) file->private_data; lp = is->lp; @@ -552,7 +663,7 @@ #ifdef CONFIG_ISDN_MPP if (!(is->state & IPPP_CONNECT)) return -EINVAL; - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", (int) min, (int) is->unit, (int) val); @@ -562,24 +673,30 @@ #endif break; case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg((void *) arg, is->unit, NULL))) + if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) + return r; + break; + case PPPIOCGIFNAME: + if(!lp) + return -EINVAL; + if ((r = set_arg((void *) arg, lp->name,strlen(lp->name)))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, is->mpppcfg, NULL))) + if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, is->pppcfg, NULL))) + if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_arg((void *) arg, &val, 0))) { + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { return r; } if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { @@ -598,12 +715,12 @@ if (lp) { struct ppp_idle pidle; pidle.xmit_idle = pidle.recv_idle = lp->huptimer; - if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle))) + if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) return r; } break; case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->mru = val; break; @@ -612,7 +729,7 @@ case PPPIOCSMPMTU: break; case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; val++; if (is->maxcid != val) { @@ -635,31 +752,33 @@ } break; case PPPIOCGDEBUG: - if ((r = set_arg((void *) arg, is->debug, 0))) + if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) return r; break; case PPPIOCSDEBUG: - if ((r = get_arg((void *) arg, &val, 0))) + if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->debug = val; break; case PPPIOCGCOMPRESSORS: { - unsigned long protos = 0; + unsigned long protos[8] = {0,}; struct isdn_ppp_compressor *ipc = ipc_head; while(ipc) { - protos |= (0x1<num); + j = ipc->num / (sizeof(long)*8); + i = ipc->num % (sizeof(long)*8); + if(j < 8) + protos[j] |= (0x1<next; } - if ((r = set_arg((void *) arg, protos, 0))) + if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) return r; } break; case PPPIOCSCOMPRESSOR: - if ((r = get_arg((void *) arg, &num, sizeof(int)))) + if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) return r; - return isdn_ppp_set_compressor(is, num); - break; + return isdn_ppp_set_compressor(is, &data); case PPPIOCGCALLINFO: { struct pppcallinfo pci; @@ -678,7 +797,7 @@ if(lp->flags & ISDN_NET_CALLBACK) pci.calltype |= CALLTYPE_CALLBACK; } - return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci); + return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); } default: break; @@ -701,9 +820,12 @@ printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev)); + /* just registers wait_queue hook. This doesn't really wait. */ poll_wait(file, &is->wq, wait); if (!(is->state & IPPP_OPEN)) { + if(is->state == IPPP_CLOSEWAIT) + return POLLHUP; printk(KERN_DEBUG "isdn_ppp: device not open\n"); return POLLERR; } @@ -777,7 +899,9 @@ is->last = bl->next; restore_flags(flags); +#ifndef COMPAT_HAS_NEW_WAITQ if (is->wq) +#endif wake_up_interruptible(&is->wq); return len; @@ -864,21 +988,33 @@ if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; - if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && + if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && + lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { + unsigned short hl; int cnt; struct sk_buff *skb; - skb = dev_alloc_skb(count); + /* + * we need to reserve enought space in front of + * sk_buff. old call to dev_alloc_skb only reserved + * 16 bytes, now we are looking what the driver want + */ + hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; + skb = alloc_skb(hl+count, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); return count; } + skb_reserve(skb, hl); if (copy_from_user(skb_put(skb, count), buf, count)) return -EFAULT; if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } + + isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ + if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) { if (lp->sav_skb) { dev_kfree_skb(lp->sav_skb); @@ -962,8 +1098,9 @@ is = ippp_table[lp->ppp_slot]; if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32); + printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", + (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len); + isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } if (net_dev->local->master) { printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n"); @@ -981,13 +1118,18 @@ #ifdef CONFIG_ISDN_MPP if (!(is->mpppcfg & SC_REJ_MP_PROT)) { int sqno_end; - - if(proto == PPP_LINK_COMP) { - printk(KERN_DEBUG "received single link compressed frame\n"); - skb = isdn_ppp_decompress(skb,is,NULL); - if(!skb) - return; - proto = isdn_ppp_strip_proto(skb); + + if(is->compflags & SC_LINK_DECOMP_ON) { + if(proto == PPP_LINK_COMP) { + if(is->debug & 0x10) + printk(KERN_DEBUG "received single link compressed frame\n"); + skb = isdn_ppp_decompress(skb,is,NULL,proto); + if(!skb) + return; + proto = isdn_ppp_strip_proto(skb); + } + else + isdn_ppp_decompress(skb,is,NULL,proto); } if (proto == PPP_MP) { @@ -1054,7 +1196,8 @@ } min_sqno &= mask; for (lpq = net_dev->queue;;) { - ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; + if(ippp_table[lpq->ppp_slot]->last_link_seqno >= 0) + ippp_table[lpq->ppp_slot]->last_link_seqno &= mask; lpq = lpq->next; if (lpq == net_dev->queue) break; @@ -1149,17 +1292,31 @@ if (is->debug & 0x10) { printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 32); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } if(proto == PPP_COMP) { if(!lp->master) - skb = isdn_ppp_decompress(skb,is,is); + skb = isdn_ppp_decompress(skb,is,is,proto); else - skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]); - if(!skb) + skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); + + if(!skb) { + printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); return; + } + proto = isdn_ppp_strip_proto(skb); + if (is->debug & 0x10) { + printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto); + isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot); + } + } + else if(is->compflags & SC_DECOMP_ON) { /* If decomp is ON */ + if(!lp->master) + isdn_ppp_decompress(skb,is,is,proto); + else + isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); } switch (proto) { @@ -1226,7 +1383,13 @@ #endif break; case PPP_CCP: - isdn_ppp_receive_ccp(net_dev,lp,skb); + case PPP_LINK_CCP: + isdn_ppp_receive_ccp(net_dev,lp,skb,proto); + /* Dont pop up ResetReq/Ack stuff to the daemon any + longer - the job is done already */ + if(skb->data[0] == CCP_RESETREQ || + skb->data[0] == CCP_RESETACK) + break; /* fall through */ default: isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ @@ -1234,10 +1397,10 @@ return; } + /* Reset hangup-timer */ + lp->huptimer = 0; netif_rx(skb); /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */ - /* Reset hangup-timer */ - lp->huptimer = 0; return; } @@ -1269,9 +1432,9 @@ */ int -isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) +isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev) { - struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */ + struct device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */ isdn_net_local *lp,*mlp; isdn_net_dev *nd; unsigned int proto = PPP_IP; /* 0x21 */ @@ -1280,8 +1443,8 @@ if (mdev) mlp = (isdn_net_local *) (mdev->priv); else { - mdev = dev; - mlp = (isdn_net_local *) (dev->priv); + mdev = netdev; + mlp = (isdn_net_local *) (netdev->priv); } nd = mlp->netdev; /* get master lp */ ipts = ippp_table[mlp->ppp_slot]; @@ -1294,7 +1457,7 @@ ipts->old_pa_dstaddr = mdev->pa_dstaddr; #endif if (ipts->debug & 0x1) - printk(KERN_INFO "%s: IP frame delayed.\n", dev->name); + printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); return 1; } @@ -1338,7 +1501,6 @@ lp = nlp; } ipt = ippp_table[lp->ppp_slot]; - lp->huptimer = 0; /* @@ -1354,16 +1516,25 @@ if (ipt->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); + if (ipts->debug & 0x40) + isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot); #ifdef CONFIG_ISDN_PPP_VJ if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ struct sk_buff *new_skb; - - new_skb = dev_alloc_skb(skb->len); + unsigned short hl; + /* + * we need to reserve enought space in front of + * sk_buff. old call to dev_alloc_skb only reserved + * 16 bytes, now we are looking what the driver want. + */ + hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; + new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC); if (new_skb) { u_char *buf; int pktlen; + skb_reserve(new_skb, hl); new_skb->dev = skb->dev; skb_put(new_skb, skb->len); buf = skb->data; @@ -1393,10 +1564,11 @@ } #endif - /* - * normal or bundle compression - */ - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + /* + * normal (single link) or bundle compression + */ + if(ipts->compflags & SC_COMP_ON) + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); if (ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); @@ -1430,9 +1602,10 @@ #endif /* - * 'link' compression + * 'link in bundle' compression ... */ - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); + if(ipt->compflags & SC_LINK_COMP_ON) + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { unsigned char *data = isdn_ppp_skb_push(&skb,1); @@ -1459,11 +1632,11 @@ if (ipts->debug & 0x40) { printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot); } - if (isdn_net_send_skb(dev, lp, skb)) { + if (isdn_net_send_skb(netdev, lp, skb)) { if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ - printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name); + printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name); dev_kfree_skb(skb); } else lp->sav_skb = skb; @@ -1473,6 +1646,12 @@ #ifdef CONFIG_ISDN_MPP +/* + * free SQ queue + * ------------- + * Note: We need two queues for MPPP. The SQ queue holds fully (re)assembled frames, + * that can't be delivered, because there is an outstanding earlier frame + */ static void isdn_ppp_free_sqqueue(isdn_net_dev * p) { @@ -1489,6 +1668,12 @@ } +/* + * free MP queue + * ------------- + * Note: The MP queue holds all frame fragments of frames, that can't be + * reassembled, because there is at least one missing fragment. + */ static void isdn_ppp_free_mpqueue(isdn_net_dev * p) { @@ -1550,7 +1735,9 @@ return 0; } - +/* + * Mask sequence numbers in MP queue + */ static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask) { @@ -1561,6 +1748,11 @@ } } +/* + * put a fragment at the right place into the MP queue + * Also checks, whether this fragment completes a frame. In this case + * the fragments are copied together into one SKB + */ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno) { @@ -1761,13 +1953,11 @@ slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp); #endif } +#endif /* * a buffered packet timed-out? */ - -#endif - void isdn_ppp_timer_timeout(void) { @@ -1939,7 +2129,7 @@ if (!sdev) return 2; - isdn_net_force_dial_lp((isdn_net_local *) sdev->priv); + isdn_net_dial_req((isdn_net_local *) sdev->priv); return 0; #else return -1; @@ -1980,47 +2170,440 @@ /* * PPP compression stuff */ -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master) + + +/* Push an empty CCP Data Frame up to the daemon to wake it up and let it + generate a CCP Reset-Request or tear down CCP altogether */ + +static void isdn_ppp_ccp_kickup(struct ippp_struct *is) +{ + isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot); +} + +/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, + but absolutely nontrivial. The most abstruse problem we are facing is + that the generation, reception and all the handling of timeouts and + resends including proper request id management should be entirely left + to the (de)compressor, but indeed is not covered by the current API to + the (de)compressor. The API is a prototype version from PPP where only + some (de)compressors have yet been implemented and all of them are + rather simple in their reset handling. Especially, their is only one + outstanding ResetAck at a time with all of them and ResetReq/-Acks do + not have parameters. For this very special case it was sufficient to + just return an error code from the decompressor and have a single + reset() entry to communicate all the necessary information between + the framework and the (de)compressor. Bad enough, LZS is different + (and any other compressor may be different, too). It has multiple + histories (eventually) and needs to Reset each of them independently + and thus uses multiple outstanding Acks and history numbers as an + additional parameter to Reqs/Acks. + All that makes it harder to port the reset state engine into the + kernel because it is not just the same simple one as in (i)pppd but + it must be able to pass additional parameters and have multiple out- + standing Acks. We are trying to achieve the impossible by handling + reset transactions independent by their id. The id MUST change when + the data portion changes, thus any (de)compressor who uses more than + one resettable state must provide and recognize individual ids for + each individual reset transaction. The framework itself does _only_ + differentiate them by id, because it has no other semantics like the + (de)compressor might. + This looks like a major redesign of the interface would be nice, + but I don't have an idea how to do it better. */ + +/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is + getting that lengthy because there is no simple "send-this-frame-out" + function above but every wrapper does a bit different. Hope I guess + correct in this hack... */ + +static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len) +{ + struct sk_buff *skb; + unsigned char *p; + int count; + int cnt = 0; + isdn_net_local *lp = is->lp; + + /* Alloc large enough skb */ + skb = dev_alloc_skb(len + 16); + if(!skb) { + printk(KERN_WARNING + "ippp: CCP cannot send reset - out of memory\n"); + return; + } + + /* We may need to stuff an address and control field first */ + if(!(is->pppcfg & SC_COMP_AC)) { + p = skb_put(skb, 2); + *p++ = 0xff; + *p++ = 0x03; + } + + /* Stuff proto, code, id and length */ + p = skb_put(skb, 6); + *p++ = (proto >> 8); + *p++ = (proto & 0xff); + *p++ = code; + *p++ = id; + cnt = 4 + len; + *p++ = (cnt >> 8); + *p++ = (cnt & 0xff); + + /* Now stuff remaining bytes */ + if(len) { + p = skb_put(skb, len); + memcpy(p, data, len); + } + + /* skb is now ready for xmit */ + printk(KERN_DEBUG "Sending CCP Frame:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + /* Just ripped from isdn_ppp_write. Dunno whether it makes sense, + especially dunno what the sav_skb stuff is good for. */ + + count = skb->len; + if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, + 1, skb)) != count) { + if (lp->sav_skb) { + dev_kfree_skb(lp->sav_skb); + printk(KERN_INFO + "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", + cnt, count); + } else + printk(KERN_INFO + "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", + cnt, count); + lp->sav_skb = skb; + } +} + +/* Allocate the reset state vector */ +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) +{ + struct ippp_ccp_reset *r; + printk(KERN_DEBUG "ippp_ccp: allocating reset data structure\n"); + r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); + if(!r) + return NULL; + memset(r, 0, sizeof(struct ippp_ccp_reset)); + is->reset = r; + return r; +} + +/* Free a given state and clear everything up for later reallocation */ +static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + + if(is->reset->rs[id]) { + printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); + rs = is->reset->rs[id]; + /* Make sure the kernel will not call back later */ + if(rs->ta) + del_timer(&rs->timer); + is->reset->rs[id] = NULL; + kfree(rs); + } else { + printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); + } +} + +/* The timer callback function which is called when a ResetReq has timed out, + aka has never been answered by a ResetAck */ +static void isdn_ppp_ccp_timer_callback(unsigned long closure) +{ + struct ippp_ccp_reset_state *rs = + (struct ippp_ccp_reset_state *)closure; + + if(!rs) { + printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); + return; + } + if(rs->ta && rs->state == CCPResetSentReq) { + /* We are correct here */ + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); + if(!rs->expra) { + /* Hmm, there is no Ack really expected. We can clean + up the state now, it will be reallocated if the + decompressor insists on another reset */ + rs->ta = 0; + isdn_ppp_ccp_reset_free_state(rs->is, rs->id); + return; + } + /* Push it again */ + isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Restart timer */ + rs->timer.expires = jiffies + HZ*5; + add_timer(&rs->timer); + } else { + printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", + rs->state); + } +} + +/* Allocate a new reset transaction state */ +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + if(is->reset->rs[id]) { + printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", + id); + return NULL; + } else { + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->is = is; + rs->id = id; + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + is->reset->rs[id] = rs; + } + return rs; +} + + +/* A decompressor wants a reset with a set of parameters - do what is + necessary to fulfill it */ +static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, + struct isdn_ppp_resetparams *rp) +{ + struct ippp_ccp_reset_state *rs; + + if(rp->valid) { + /* The decompressor defines parameters by itself */ + if(rp->rsend) { + /* And he wants us to send a request */ + if(!(rp->idval)) { + printk(KERN_ERR "ippp_ccp: decompressor must" + " specify reset id\n"); + return; + } + if(is->reset->rs[rp->id]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[rp->id]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + /* Ok, this is a new transaction */ + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", rp->id); + rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + rs->expra = rp->expra; + if(rp->dtval) { + rs->dlen = rp->dlen; + memcpy(rs->data, rp->data, rp->dlen); + } + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, + CCP_RESETREQ, rs->id, + rs->data, rs->dlen); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } + } else { + printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); + } + } else { + /* The reset params are invalid. The decompressor does not + care about them, so we just send the minimal requests + and increase ids only when an Ack is received for a + given id */ + if(is->reset->rs[is->reset->lastid]) { + /* There is already a transaction in existence + for this id. May be still waiting for a + Ack or may be wrong. */ + rs = is->reset->rs[is->reset->lastid]; + if(rs->state == CCPResetSentReq && rs->ta) { + printk(KERN_DEBUG "ippp_ccp: reset" + " trans still in progress" + " for id %d\n", rp->id); + } else { + printk(KERN_WARNING "ippp_ccp: reset" + " trans in wrong state %d for" + " id %d\n", rs->state, rp->id); + } + } else { + printk(KERN_DEBUG "ippp_ccp: new trans for id" + " %d to be started\n", is->reset->lastid); + rs = isdn_ppp_ccp_reset_alloc_state(is, + is->reset->lastid); + if(!rs) { + printk(KERN_ERR "ippp_ccp: out of mem" + " allocing ccp trans\n"); + return; + } + rs->state = CCPResetSentReq; + /* We always expect an Ack if the decompressor doesnt + know better */ + rs->expra = 1; + rs->dlen = 0; + /* HACK TODO - add link comp here */ + isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, + rs->id, NULL, 0); + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; + } + } +} + +/* An Ack was received for this id. This means we stop the timer and clean + up the state prior to calling the decompressors reset routine. */ +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, + unsigned char id) +{ + struct ippp_ccp_reset_state *rs = is->reset->rs[id]; + + if(rs) { + if(rs->ta && rs->state == CCPResetSentReq) { + /* Great, we are correct */ + if(!rs->expra) + printk(KERN_DEBUG "ippp_ccp: ResetAck received" + " for id %d but not expected\n", id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received out of" + "sync for id %d\n", id); + } + if(rs->ta) { + rs->ta = 0; + del_timer(&rs->timer); + } + isdn_ppp_ccp_reset_free_state(is, id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" + " %d\n", id); + } + /* Make sure the simple reset stuff uses a new id next time */ + is->reset->lastid++; +} + +static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, + int proto) { -#if 1 - printk(KERN_ERR "compression not included!\n"); - dev_kfree_skb(skb); - return NULL; +#ifndef CONFIG_ISDN_CCP + if(proto == PPP_COMP || proto == PPP_LINK_COMP) { + printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n"); + dev_kfree_skb(skb); + return NULL; + } + return skb; #else + void *stat = NULL; + struct isdn_ppp_compressor *ipc = NULL; + struct sk_buff *skb_out; + int len; + struct ippp_struct *ri; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + if(!master) { /* - * single link compression + * single link decompression */ - if(!is->link_compressor) { - printk(KERN_ERR "ippp: no (link) compressor defined!\n"); + if(!is->link_decompressor) { + printk(KERN_ERR "ippp: no link decompressor defined!\n"); dev_kfree_skb(skb); return NULL; } if(!is->link_decomp_stat) { - printk(KERN_DEBUG "ippp: initialize link compressor\n"); + printk(KERN_DEBUG "ippp: no link decompressor data allocated\n"); + dev_kfree_skb(skb); + return NULL; } -/* - -> decompress link -*/ - } + stat = is->link_decomp_stat; + ipc = is->link_decompressor; + ri = is; + } else { /* * 'normal' or bundle-compression */ - if(!master->compressor) { - printk(KERN_ERR "ippp: no (link) compressor defined!\n"); + if(!master->decompressor) { + printk(KERN_ERR "ippp: no decompressor defined!\n"); dev_kfree_skb(skb); return NULL; } if(!master->decomp_stat) { -#if 0 - master->decomp_stat = (master->compressor->decomp_alloc)( .. ); -#endif - printk(KERN_DEBUG "ippp: initialize compressor\n"); + printk(KERN_DEBUG "ippp: no decompressor data allocated\n"); + dev_kfree_skb(skb); + return NULL; } + stat = master->decomp_stat; + ipc = master->decompressor; + ri = master; + } + + /* + printk(KERN_DEBUG "ippp: Decompress valid!\n"); + */ + + if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) { + /* Set up reset params for the decompressor */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + +/* !!!HACK,HACK,HACK!!! 2048 is only assumed */ + skb_out = dev_alloc_skb(2048); + len = ipc->decompress(stat,skb,skb_out, &rsparm); + dev_kfree_skb(skb); + if(len <= 0) { + /* Ok, some error */ + switch(len) { + case DECOMP_ERROR: + ri->pppcfg |= SC_DC_ERROR; + printk(KERN_INFO "ippp: decomp wants reset %s params\n", + rsparm.valid ? "with" : "without"); + + isdn_ppp_ccp_reset_trans(ri, &rsparm); + + break; + case DECOMP_FATALERROR: + ri->pppcfg |= SC_DC_FERROR; + /* Kick ipppd to recognize the error */ + isdn_ppp_ccp_kickup(ri); + break; + } + /* Did I see a leak here ? */ + dev_kfree_skb(skb_out); + return NULL; + } + return skb_out; + } + else { + /* + printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit); + */ + ipc->incomp(stat,skb,proto); + return skb; } - - return skb; #endif } @@ -2034,19 +2617,29 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, struct ippp_struct *is,struct ippp_struct *master,int type) { -#if 1 - return skb_in; -#else int ret; int new_proto; struct isdn_ppp_compressor *compressor; void *stat; struct sk_buff *skb_out; +#ifdef CONFIG_ISDN_CCP + /* we do not compress control protocols */ + if(*proto < 0 || *proto > 0x3fff) { +#else + { +#endif + return skb_in; + } + if(type) { /* type=1 => Link compression */ +#if 0 compressor = is->link_compressor; stat = is->link_comp_stat; new_proto = PPP_LINK_COMP; +#else + return skb_in; +#endif } else { if(!master) { @@ -2061,15 +2654,16 @@ } if(!compressor) { - printk(KERN_ERR "No compressor set!\n"); + printk(KERN_ERR "isdn_ppp: No compressor set!\n"); return skb_in; } if(!stat) { - /* init here ? */ + printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); return skb_in; } - skb_out = dev_alloc_skb(skb_in->len); + /* Allow for at least 150 % expansion (for now) */ + skb_out = dev_alloc_skb(skb_in->len + skb_in->len/2 + 32); if(!skb_out) return skb_in; @@ -2082,24 +2676,225 @@ dev_kfree_skb(skb_in); *proto = new_proto; return skb_out; -#endif - } /* * we received a CCP frame .. - * not a clean solution, but we SHOULD handle a few cased in the kernel + * not a clean solution, but we MUST handle a few cases in the kernel */ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb) + struct sk_buff *skb,int proto) { -#if 0 - printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n", - skb->data[0],skb->data[1],skb->data[2],skb->data[3], - skb->data[4],skb->data[5],skb->data[6],skb->data[7] ); -#endif + struct ippp_struct *is = ippp_table[lp->ppp_slot]; + struct ippp_struct *mis; + int len; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + + printk(KERN_DEBUG "Received CCP frame from peer\n"); + isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + if(lp->master) + mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]; + else + mis = is; + + switch(skb->data[0]) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we RECEIVE an ackowledge we enable the decompressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable decompression here!\n"); + if(proto == PPP_CCP) + mis->compflags |= SC_DECOMP_ON; + else + is->compflags |= SC_LINK_DECOMP_ON; + break; + + case CCP_RESETACK: + printk(KERN_DEBUG "Received ResetAck from peer\n"); + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + + if(proto == PPP_CCP) { + /* If a reset Ack was outstanding for this id, then + clean up the state engine */ + isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); + if(mis->decompressor && mis->decomp_stat) + mis->decompressor-> + reset(mis->decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: This is not easy to decide here */ + mis->compflags &= ~SC_DECOMP_DISCARD; + mis->pppcfg &= ~SC_DC_ERROR; + } + else { + isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); + if(is->link_decompressor && is->link_decomp_stat) + is->link_decompressor-> + reset(is->link_decomp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: neither here */ + is->compflags &= ~SC_LINK_DECOMP_DISCARD; + is->pppcfg &= ~SC_DC_ERROR; + } + break; + + case CCP_RESETREQ: + printk(KERN_DEBUG "Received ResetReq from peer\n"); + /* Receiving a ResetReq means we must reset our compressor */ + /* Set up reset params for the reset entry */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + /* Isolate data length */ + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + if(proto == PPP_CCP) { + if(mis->compressor && mis->comp_stat) + mis->compressor-> + reset(mis->comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor-> + reset(is->link_comp_stat, + skb->data[0], + skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + } + /* Ack the Req as specified by rsparm */ + if(rsparm.valid) { + /* Compressor reset handler decided how to answer */ + if(rsparm.rsend) { + /* We should send a Frame */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + rsparm.idval ? rsparm.id + : skb->data[1], + rsparm.dtval ? + rsparm.data : NULL, + rsparm.dtval ? + rsparm.dlen : 0); + } else { + printk(KERN_DEBUG "ResetAck suppressed\n"); + } + } else { + /* We answer with a straight reflected Ack */ + isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, + skb->data[1], + len ? &skb->data[4] : NULL, + len); + } + break; + } +} + + +/* + * Daemon sends a CCP frame ... + */ + +/* TODO: Clean this up with new Reset semantics */ + +static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) +{ + struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot]; + int proto; + unsigned char *data; + + if(!skb || skb->len < 3) + return; + + /* Daemon may send with or without address and control field comp */ + data = skb->data; + if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { + data += 2; + if(skb->len < 5) + return; + } + + proto = ((int)data[0]<<8)+data[1]; + if(proto != PPP_CCP && proto != PPP_LINK_CCP) + return; + + printk(KERN_DEBUG "Received CCP frame from daemon:\n"); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); + + if(lp->master) + mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]; + else + mis = is; + + if(mis != is) + printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); + + switch(data[2]) { + case CCP_CONFREQ: + case CCP_TERMREQ: + case CCP_TERMACK: + if(is->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + if(proto == PPP_CCP) + is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + else + is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + break; + case CCP_CONFACK: + /* if we SEND an ackowledge we can/must enable the compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Enable compression here!\n"); + if(proto == PPP_CCP) + is->compflags |= SC_COMP_ON; + else + is->compflags |= SC_LINK_COMP_ON; + break; + case CCP_RESETACK: + /* If we send a ACK we should reset our compressor */ + if(is->debug & 0x10) + printk(KERN_DEBUG "Reset decompression state here!\n"); + printk(KERN_DEBUG "ResetAck from daemon passed by\n"); + if(proto == PPP_CCP) { + /* link to master? */ + if(is->compressor && is->comp_stat) + is->compressor->reset(is->comp_stat, 0, 0, + NULL, 0, NULL); + is->compflags &= ~SC_COMP_DISCARD; + } + else { + if(is->link_compressor && is->link_comp_stat) + is->link_compressor->reset(is->link_comp_stat, + 0, 0, NULL, 0, NULL); + is->compflags &= ~SC_LINK_COMP_DISCARD; + } + break; + case CCP_RESETREQ: + /* Just let it pass by */ + printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + break; + } } + int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { ipc->next = ipc_head; @@ -2123,32 +2918,67 @@ return 0; } -static int isdn_ppp_set_compressor(struct ippp_struct *is,int num) +static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) { struct isdn_ppp_compressor *ipc = ipc_head; + int ret; + void *stat; + int num = data->num; + + if(is->debug & 0x10) + printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, + (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); while(ipc) { if(ipc->num == num) { - return 0; - is->compressor = ipc; - is->link_compressor = ipc; + stat = ipc->alloc(data); + if(stat) { + ret = ipc->init(stat,data,is->unit,0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + stat = NULL; + break; + } + } + else { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + break; + } + + if(data->flags & IPPP_COMP_FLAG_XMIT) { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_comp_stat) + is->link_compressor->free(is->link_comp_stat); + is->link_comp_stat = stat; + is->link_compressor = ipc; + } + else { + if(is->comp_stat) + is->compressor->free(is->comp_stat); + is->comp_stat = stat; + is->compressor = ipc; + } + } + else { + if(data->flags & IPPP_COMP_FLAG_LINK) { + if(is->link_decomp_stat) + is->link_decompressor->free(is->link_decomp_stat); + is->link_decomp_stat = stat; + is->link_decompressor = ipc; + } + else { + if(is->decomp_stat) + is->decompressor->free(is->decomp_stat); + is->decomp_stat = stat; + is->decompressor = ipc; + } + } + return 0; } ipc = ipc->next; } return -EINVAL; } - - -#if 0 -static struct symbol_table isdn_ppp_syms = -{ -#include - X(isdn_ppp_register_compressor), - X(isdn_ppp_unregister_compressor), -#include -}; -#endif - - diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v2.2.10/linux/drivers/isdn/isdn_ppp.h Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/isdn_ppp.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.12 1998/01/31 22:07:48 keil Exp $ +/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.13 1998/03/22 18:50:50 hipp + * Added BSD Compression for syncPPP .. UNTESTED at the moment + * * Revision 1.12 1998/01/31 22:07:48 keil * changes for newer kernels * @@ -83,6 +86,9 @@ extern void isdn_ppp_release(int, struct file *); extern int isdn_ppp_dial_slave(char *); extern void isdn_ppp_wakeup_daemon(isdn_net_local *); + +extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); +extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc); #define IPPP_OPEN 0x01 #define IPPP_CONNECT 0x02 diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_syms.c linux/drivers/isdn/isdn_syms.c --- v2.2.10/linux/drivers/isdn/isdn_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/isdn_syms.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,114 @@ +/* $Id: isdn_syms.c,v 1.3.2.1 1999/04/22 21:09:37 werner Exp $ + + * Linux ISDN subsystem, exported symbols (linklevel). + * + * 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, 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. + * + * $Log: isdn_syms.c,v $ + * Revision 1.3.2.1 1999/04/22 21:09:37 werner + * Added support for dss1 diversion services + * + * Revision 1.3 1997/02/16 01:02:47 fritz + * Added GPL-Header, Id and Log + * + */ +#include +#include +#include + +#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */ +#include +#endif +#include "isdn_common.h" +#ifdef CONFIG_ISDN_DIVERSION + #include +extern isdn_divert_if *divert_if; + +static char *map_drvname(int di) +{ + if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) + return(NULL); + return(dev->drvid[di]); /* driver name */ +} /* map_drvname */ + +static int map_namedrv(char *id) +{ int i; + + for (i = 0; i < ISDN_MAX_DRIVERS; i++) + { if (!strcmp(dev->drvid[i],id)) + return(i); + } + return(-1); +} /* map_namedrv */ + +int DIVERT_REG_NAME(isdn_divert_if *i_div) +{ + if (i_div->if_magic != DIVERT_IF_MAGIC) + return(DIVERT_VER_ERR); + switch (i_div->cmd) + { + case DIVERT_CMD_REL: + if (divert_if != i_div) + return(DIVERT_REL_ERR); + divert_if = NULL; /* free interface */ + MOD_DEC_USE_COUNT; + return(DIVERT_NO_ERR); + + case DIVERT_CMD_REG: + if (divert_if) + return(DIVERT_REG_ERR); + i_div->ll_cmd = isdn_command; /* set command function */ + i_div->drv_to_name = map_drvname; + i_div->name_to_drv = map_namedrv; + MOD_INC_USE_COUNT; + divert_if = i_div; /* remember interface */ + return(DIVERT_NO_ERR); + + default: + return(DIVERT_CMD_ERR); + } +} /* DIVERT_REG_NAME */ + +#endif CONFIG_ISDN_DIVERSION + +#if (LINUX_VERSION_CODE < 0x020111) +static int has_exported; + +static struct symbol_table isdn_syms = { +#include + X(register_isdn), +#ifdef CONFIG_ISDN_DIVERSION + X(DIVERT_REG_NAME), +#endif CONFIG_ISDN_DIVERSION +#include +}; + +void +isdn_export_syms(void) +{ + if (has_exported) + return; + register_symtab(&isdn_syms); + has_exported = 1; +} + +#else + +EXPORT_SYMBOL(register_isdn); +#ifdef CONFIG_ISDN_DIVERSION + EXPORT(DIVERT_REG_NAME); +#endif CONFIG_ISDN_DIVERSION + +#endif diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.2.10/linux/drivers/isdn/isdn_tty.c Sat Oct 31 10:37:14 1998 +++ linux/drivers/isdn/isdn_tty.c Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $ +/* $Id: isdn_tty.c,v 1.68 1999/07/11 17:51:51 armin Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,84 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.68 1999/07/11 17:51:51 armin + * Bugfix, "-" was missing for AT&L settings. + * + * Revision 1.67 1999/07/11 17:14:12 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * + * Revision 1.66 1999/07/07 10:13:46 detabc + * remove unused messages + * + * Revision 1.65 1999/07/04 21:01:59 werner + * Added support for keypad and display (ported from 2.0) + * + * Revision 1.64 1999/07/01 08:30:00 keil + * compatibility to 2.3 kernel + * + * Revision 1.63 1999/04/12 12:33:39 fritz + * Changes from 2.0 tree. + * + * Revision 1.62 1999/03/02 12:04:48 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.61 1999/01/27 22:53:11 he + * minor updates (spellings, jiffies wrap around in isdn_tty) + * + * Revision 1.60 1998/11/15 23:57:32 keil + * changes for 2.1.127 + * + * Revision 1.59 1998/08/20 13:50:15 keil + * More support for hybrid modem (not working yet) + * + * Revision 1.58 1998/07/26 18:48:45 armin + * Added silence detection in voice receive mode. + * + * Revision 1.57 1998/06/26 15:12:36 fritz + * Added handling of STAT_ICALL with incomplete CPN. + * Added AT&L for ttyI emulator. + * Added more locking stuff in tty_write. + * + * Revision 1.56 1998/06/18 23:31:51 fritz + * Replaced cli()/restore_flags() in isdn_tty_write() by locking. + * Removed direct-senddown feature in isdn_tty_write because it will + * never succeed with locking and is useless anyway. + * + * Revision 1.55 1998/06/17 19:50:55 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * + * + * Revision 1.52 1998/03/19 13:18:21 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * + * + * Revision 1.49 1998/03/08 00:01:59 fritz + * Bugfix: Lowlevel module usage and channel usage were not + * reset on NO DCHANNEL. + * + * Revision 1.48 1998/03/07 12:28:15 tsbogend + * fixed kernel unaligned traps on Linux/Alpha + * * Revision 1.47 1998/02/22 19:44:14 fritz * Bugfixes and improvements regarding V.110, V.110 now running. * @@ -236,7 +314,6 @@ static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int); static void isdn_tty_modem_reset_regs(modem_info *, int); static void isdn_tty_cmd_ATA(modem_info *); -static void isdn_tty_at_cout(char *, modem_info *); static void isdn_tty_flush_buffer(struct tty_struct *); static void isdn_tty_modem_result(int, modem_info *); #ifdef CONFIG_ISDN_AUDIO @@ -254,62 +331,8 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.47 $"; +char *isdn_tty_revision = "$Revision: 1.68 $"; -#define DLE 0x10 -#define ETX 0x03 -#define DC4 0x14 - -/* - * Definition of some special Registers of AT-Emulator - */ -#define REG_RINGATA 0 -#define REG_RINGCNT 1 -#define REG_ESC 2 -#define REG_CR 3 -#define REG_LF 4 -#define REG_BS 5 - -#define REG_RESP 12 -#define BIT_RESP 1 -#define REG_RESPNUM 12 -#define BIT_RESPNUM 2 -#define REG_ECHO 12 -#define BIT_ECHO 4 -#define REG_DCD 12 -#define BIT_DCD 8 -#define REG_CTS 12 -#define BIT_CTS 16 -#define REG_DTRR 12 -#define BIT_DTRR 32 -#define REG_DSR 12 -#define BIT_DSR 64 -#define REG_CPPP 12 -#define BIT_CPPP 128 - -#define REG_DELXMT 13 -#define BIT_DELXMT 1 -#define REG_T70 13 -#define BIT_T70 2 -#define BIT_T70_EXT 32 -#define REG_DTRHUP 13 -#define BIT_DTRHUP 4 -#define REG_RESPXT 13 -#define BIT_RESPXT 8 -#define REG_CIDONCE 13 -#define BIT_CIDONCE 16 -#define REG_RUNG 13 -#define BIT_RUNG 64 - -#define REG_L2PROT 14 -#define REG_L3PROT 15 -#define REG_PSIZE 16 -#define REG_WSIZE 17 -#define REG_SI1 18 -#define REG_SI2 19 -#define REG_SI1I 20 -#define REG_PLAN 21 -#define REG_SCREEN 22 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() * to stuff incoming data directly into a tty's flip-buffer. This @@ -389,6 +412,8 @@ r = 0; #ifdef CONFIG_ISDN_AUDIO isdn_audio_eval_dtmf(info); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_eval_silence(info); #endif if ((tty = info->tty)) { if (info->mcr & UART_MCR_RTS) { @@ -443,8 +468,10 @@ #ifdef CONFIG_ISDN_AUDIO ifmt = 1; - if (info->vonline) + if ((info->vonline) && (!info->emu.vpar[4])) isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); + if ((info->vonline & 1) && (info->emu.vpar[1])) + isdn_audio_calc_silence(info, skb->data, skb->len, ifmt); #endif if ((info->online < 2) #ifdef CONFIG_ISDN_AUDIO @@ -566,8 +593,8 @@ info->isdn_channel, 1, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; + info->msr &= ~UART_MSR_CTS; + info->lsr &= ~UART_LSR_TEMT; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty); @@ -579,8 +606,6 @@ dev_kfree_skb(skb); return; } - if (slen) - skb_pull(skb, slen); skb_queue_head(&info->xmit_queue, skb); } @@ -702,7 +727,6 @@ int audio_len; #endif struct sk_buff *skb; - unsigned long flags; #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 4) { @@ -717,18 +741,20 @@ } } #endif - save_flags(flags); - cli(); - if (!(buflen = info->xmit_count)) { - restore_flags(flags); + if (!(buflen = info->xmit_count)) return; - } - if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) + if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; + info->lsr &= ~UART_LSR_TEMT; + /* info->xmit_count is modified here and in isdn_tty_write(). + * So we return here if isdn_tty_write() is in the + * critical section. + */ + atomic_inc(&info->xmit_lock); + if (!(atomic_dec_and_test(&info->xmit_lock))) + return; if (info->isdn_driver < 0) { info->xmit_count = 0; - restore_flags(flags); return; } skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; @@ -742,7 +768,6 @@ skb = dev_alloc_skb(skb_res + buflen); #endif if (!skb) { - restore_flags(flags); printk(KERN_WARNING "isdn_tty: Out of memory in ttyI%d senddown\n", info->line); @@ -751,7 +776,6 @@ skb_reserve(skb, skb_res); memcpy(skb_put(skb, buflen), info->xmit_buf, buflen); info->xmit_count = 0; - restore_flags(flags); #ifdef CONFIG_ISDN_AUDIO if (info->vonline & 2) { /* For now, ifmt is fixed to 1 (alaw), since this @@ -859,7 +883,7 @@ break; } #ifdef CONFIG_ISDN_AUDIO - if (si == 1) { + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { l2 = ISDN_PROTO_L2_TRANS; usg = ISDN_USAGE_VOICE; } @@ -907,9 +931,11 @@ cmd.parm.setup.si2 = m->mdmreg[REG_SI2]; cmd.command = ISDN_CMD_DIAL; info->dialing = 1; + info->emu.carrierwait = 0; strcpy(dev->num[i], n); isdn_info_update(); isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } } @@ -938,10 +964,16 @@ } #ifdef CONFIG_ISDN_AUDIO info->vonline = 0; + info->emu.vpar[4] = 0; + info->emu.vpar[5] = 8; if (info->dtmf_state) { kfree(info->dtmf_state); info->dtmf_state = NULL; } + if (info->silence_state) { + kfree(info->silence_state); + info->silence_state = NULL; + } if (info->adpcms) { kfree(info->adpcms); info->adpcms = NULL; @@ -965,8 +997,9 @@ } isdn_all_eaz(info->isdn_driver, info->isdn_channel); info->emu.mdmreg[REG_RINGCNT] = 0; - usage = (info->emu.mdmreg[REG_SI1I] == 1) ? - ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; + usage = ((info->emu.mdmreg[REG_SI1I] != 1) || + (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? + ISDN_USAGE_MODEM : ISDN_USAGE_VOICE; isdn_free_channel(info->isdn_driver, info->isdn_channel, usage); } @@ -978,6 +1011,226 @@ } } +/* + * Begin of a CAPI like interface, currently used only for + * supplementary service (CAPI 2.0 part III) + */ +#include "avmb1/capicmd.h" /* this should be moved in a common place */ + +int +isdn_tty_capi_facility(capi_msg *cm) { + return(-1); /* dummy */ +} + +/* isdn_tty_suspend() tries to suspend the current tty connection + */ +static void +isdn_tty_suspend(char *id, modem_info * info, atemu * m) +{ + isdn_ctrl cmd; + + int l; + + if (!info) + return; + +#ifdef ISDN_DEBUG_MODEM_SERVICES + printk(KERN_DEBUG "Msusp ttyI%d\n", info->line); +#endif + l = strlen(id); + if ((info->isdn_driver >= 0) && l) { + cmd.parm.cmsg.Length = l+17; + cmd.parm.cmsg.Command = CAPI_FACILITY; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ + cmd.parm.cmsg.para[1] = 0; + cmd.parm.cmsg.para[2] = l + 3; + cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */ + cmd.parm.cmsg.para[4] = 0; + cmd.parm.cmsg.para[5] = l; + strncpy(&cmd.parm.cmsg.para[6], id, l); + cmd.command = CAPI_PUT_MESSAGE; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + isdn_command(&cmd); + } +} + +/* isdn_tty_resume() tries to resume a suspended call + * setup of the lower levels before that. unfortunatly here is no + * checking for compatibility of used protocols implemented by Q931 + * It does the same things like isdn_tty_dial, the last command + * is different, may be we can merge it. + */ + +static void +isdn_tty_resume(char *id, modem_info * info, atemu * m) +{ + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[REG_L2PROT]; + isdn_ctrl cmd; + ulong flags; + int i; + int j; + int l; + + l = strlen(id); + if (!l) { + isdn_tty_modem_result(4, info); + return; + } + for (j = 7; j >= 0; j--) + if (m->mdmreg[REG_SI1] & (1 << j)) { + si = bit2si[j]; + break; + } +#ifdef CONFIG_ISDN_AUDIO + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + l2 = ISDN_PROTO_L2_TRANS; + usg = ISDN_USAGE_VOICE; + } +#endif + m->mdmreg[REG_SI1I] = si2bit[si]; + save_flags(flags); + cli(); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + if (i < 0) { + restore_flags(flags); + isdn_tty_modem_result(6, info); + } else { + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; + info->last_dir = 1; +// strcpy(info->last_num, n); + isdn_info_update(); + restore_flags(flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.parm.cmsg.Length = l+17; + cmd.parm.cmsg.Command = CAPI_FACILITY; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ + cmd.parm.cmsg.para[1] = 0; + cmd.parm.cmsg.para[2] = l+3; + cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */ + cmd.parm.cmsg.para[4] = 0; + cmd.parm.cmsg.para[5] = l; + strncpy(&cmd.parm.cmsg.para[6], id, l); + cmd.command =CAPI_PUT_MESSAGE; +/* info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); +*/ + isdn_command(&cmd); + } +} + +/* isdn_tty_send_msg() sends a message to a HL driver + * This is used for hybrid modem cards to send AT commands to it + */ + +static void +isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) +{ + int usg = ISDN_USAGE_MODEM; + int si = 7; + int l2 = m->mdmreg[REG_L2PROT]; + isdn_ctrl cmd; + ulong flags; + int i; + int j; + int l; + + l = strlen(msg); + if (!l) { + isdn_tty_modem_result(4, info); + return; + } + for (j = 7; j >= 0; j--) + if (m->mdmreg[REG_SI1] & (1 << j)) { + si = bit2si[j]; + break; + } +#ifdef CONFIG_ISDN_AUDIO + if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + l2 = ISDN_PROTO_L2_TRANS; + usg = ISDN_USAGE_VOICE; + } +#endif + m->mdmreg[REG_SI1I] = si2bit[si]; + save_flags(flags); + cli(); + i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1); + if (i < 0) { + restore_flags(flags); + isdn_tty_modem_result(6, info); + } else { + info->isdn_driver = dev->drvmap[i]; + info->isdn_channel = dev->chanmap[i]; + info->drv_index = i; + dev->m_idx[i] = info->line; + dev->usage[i] |= ISDN_USAGE_OUTGOING; + info->last_dir = 1; + isdn_info_update(); + restore_flags(flags); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_CLREAZ; + isdn_command(&cmd); + strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETEAZ; + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL2; + info->last_l2 = l2; + cmd.arg = info->isdn_channel + (l2 << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_SETL3; + cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); + isdn_command(&cmd); + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.parm.cmsg.Length = l+14; + cmd.parm.cmsg.Command = CAPI_MANUFACTURER; + cmd.parm.cmsg.Subcommand = CAPI_REQ; + cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; + cmd.parm.cmsg.para[0] = l+1; + strncpy(&cmd.parm.cmsg.para[1], msg, l); + cmd.parm.cmsg.para[l+1] = 0xd; + cmd.command =CAPI_PUT_MESSAGE; +/* info->dialing = 1; + strcpy(dev->num[i], n); + isdn_info_update(); +*/ + isdn_command(&cmd); + } +} + static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine) { @@ -1138,15 +1391,16 @@ { int c; int total = 0; - ulong flags; modem_info *info = (modem_info *) tty->driver_data; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write")) return 0; if (!tty) return 0; - save_flags(flags); - cli(); + if (from_user) + down(&info->write_sem); + /* See isdn_tty_senddown() */ + atomic_inc(&info->xmit_lock); while (1) { c = MIN(count, info->xmit_size - info->xmit_count); if (info->isdn_driver >= 0) @@ -1205,10 +1459,6 @@ } else #endif info->xmit_count += c; - if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) { - isdn_tty_senddown(info); - isdn_tty_tint(info); - } } else { info->msr |= UART_MSR_CTS; info->lsr |= UART_LSR_TEMT; @@ -1228,7 +1478,9 @@ } if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); - restore_flags(flags); + atomic_dec(&info->xmit_lock); + if (from_user) + up(&info->write_sem); return total; } @@ -1359,7 +1611,7 @@ status = info->lsr; restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - put_user(result, (ulong *) value); + put_user(result, (uint *) value); return 0; } @@ -1383,7 +1635,7 @@ | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - put_user(result, (ulong *) value); + put_user(result, (uint *) value); return 0; } @@ -1567,8 +1819,12 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info) { +#ifdef COMPAT_HAS_NEW_WAITQ + DECLARE_WAITQUEUE(wait, NULL); +#else struct wait_queue wait = {current, NULL}; +#endif int do_clocal = 0; unsigned long flags; int retval; @@ -1891,7 +2147,9 @@ m->profile[18] = 4; m->profile[19] = 0; m->profile[20] = 0; + m->profile[23] = 0; m->pmsn[0] = '\0'; + m->plmsn[0] = '\0'; } #ifdef CONFIG_ISDN_AUDIO @@ -1902,6 +2160,8 @@ m->vpar[1] = 0; /* Silence detection level (0 = none ) */ m->vpar[2] = 70; /* Silence interval (7 sec. ) */ m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ + m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */ + m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */ } #endif @@ -1912,6 +2172,7 @@ if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); + memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); info->xmit_size = m->mdmreg[REG_PSIZE] * 16; } #ifdef CONFIG_ISDN_AUDIO @@ -1925,6 +2186,7 @@ { memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); + memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) send_sig(SIGIO, dev->profd, 1); } @@ -1988,6 +2250,11 @@ } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &m->info[i]; +#ifdef COMPAT_HAS_NEW_WAITQ + init_MUTEX(&info->write_sem); +#else + info->write_sem = MUTEX; +#endif sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); info->last_dir = 0; @@ -2004,9 +2271,14 @@ info->blocked_open = 0; info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); +#else info->open_wait = 0; info->close_wait = 0; info->isdn_driver = -1; +#endif info->isdn_channel = -1; info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; @@ -2024,25 +2296,67 @@ return 0; } +static int +isdn_tty_match_icall(char *cid, atemu *emu, int di) +{ +#ifdef ISDN_DEBUG_MODEM_ICALL + printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n", + emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di), + emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]); +#endif + if (strlen(emu->lmsn)) { + char *p = emu->lmsn; + char *q; + int tmp; + int ret = 0; + + while (1) { + if ((q = strchr(p, ';'))) + *q = '\0'; + if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret) + ret = tmp; +#ifdef ISDN_DEBUG_MODEM_ICALL + printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", + p, isdn_map_eaz2msn(emu->msn, di), tmp); +#endif + if (q) { + *q = ';'; + p = q; + p++; + } + if (!tmp) + return 0; + if (!q) + break; + } + return ret; + } else + return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di)); +} + /* * An incoming call-request has arrived. * Search the tty-devices for an appropriate device and bind * it to the ISDN-Channel. - * Return Index to dev->mdm or -1 if none found. + * Return: + * + * 0 = No matching device found. + * 1 = A matching device found. + * 3 = No match found, but eventually would match, if + * CID is longer. */ int isdn_tty_find_icall(int di, int ch, setup_parm setup) { char *eaz; int i; + int wret; int idx; int si1; int si2; char nr[32]; ulong flags; - save_flags(flags); - cli(); if (!setup.phone[0]) { nr[0] = '0'; nr[1] = '\0'; @@ -2059,17 +2373,14 @@ #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif + wret = 0; + save_flags(flags); + cli(); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i, - info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di), - info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]); -#endif - if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di), - eaz)) && /* EAZ is matching */ - (info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ - (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ + + if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ + (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ idx = isdn_dc2minor(di, ch); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: match1\n"); @@ -2081,34 +2392,42 @@ #ifndef FIX_FILE_TRANSFER (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) && #endif - (info->isdn_driver == -1) && - (info->isdn_channel == -1) && - (USG_NONE(dev->usage[idx]))) { - info->isdn_driver = di; - info->isdn_channel = ch; - info->drv_index = idx; - dev->m_idx[idx] = info->line; - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM; - strcpy(dev->num[idx], nr); - info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup.plan; - info->emu.mdmreg[REG_SCREEN] = setup.screen; - isdn_info_update(); - restore_flags(flags); - printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, - info->line); - info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); - return info->line; + (info->isdn_driver == -1) && + (info->isdn_channel == -1) && + (USG_NONE(dev->usage[idx]))) { + int matchret; + + if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret) + wret = matchret; + if (!matchret) { /* EAZ is matching */ + info->isdn_driver = di; + info->isdn_channel = ch; + info->drv_index = idx; + dev->m_idx[idx] = info->line; + dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; + dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? + ISDN_USAGE_MODEM : ISDN_USAGE_VOICE; + strcpy(dev->num[idx], nr); + strcpy(info->emu.cpn, eaz); + info->emu.mdmreg[REG_SI1I] = si2bit[si1]; + info->emu.mdmreg[REG_PLAN] = setup.plan; + info->emu.mdmreg[REG_SCREEN] = setup.screen; + isdn_info_update(); + restore_flags(flags); + printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, + info->line); + info->msr |= UART_MSR_RI; + isdn_tty_modem_result(2, info); + isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); + return 1; + } } } } - printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, - dev->drv[di]->reject_bus ? "rejected" : "ignored"); restore_flags(flags); - return -1; + printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, + ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored"); + return (wret == 2)?3:0; } #define TTY_IS_ACTIVE(info) \ @@ -2129,7 +2448,7 @@ case ISDN_STAT_CINF: printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num); info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10); - if (e == c->parm.num) + if (e == (char *)c->parm.num) info->emu.charge = 0; break; @@ -2154,6 +2473,19 @@ /* Signal cause to tty-device */ strncpy(info->last_cause, c->parm.num, 5); return 1; + case ISDN_STAT_DISPLAY: +#ifdef ISDN_TTY_STAT_DEBUG + printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line); +#endif + /* Signal display to tty-device */ + if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) && + !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) { + isdn_tty_at_cout("\r\n", info); + isdn_tty_at_cout("DISPLAY: ", info); + isdn_tty_at_cout(c->parm.display, info); + isdn_tty_at_cout("\r\n", info); + } + return 1; case ISDN_STAT_DCONN: #ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); @@ -2170,10 +2502,11 @@ printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); #endif if (TTY_IS_ACTIVE(info)) { - if (info->dialing == 1) { - info->dialing = 0; + if (info->dialing == 1) isdn_tty_modem_result(7, info); - } + if (info->dialing > 1) + isdn_tty_modem_result(3, info); + info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); #endif @@ -2192,14 +2525,20 @@ if (TTY_IS_ACTIVE(info)) { info->msr |= UART_MSR_DCD; info->emu.charge = 0; - if (info->dialing) { - info->dialing = 0; + if (info->dialing & 0xf) info->last_dir = 1; - } else + else info->last_dir = 0; + info->dialing = 0; info->rcvsched = 1; - if (USG_MODEM(dev->usage[i])) - isdn_tty_modem_result(5, info); + if (USG_MODEM(dev->usage[i])) { + if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { + strcpy(info->emu.connmsg, c->parm.num); + isdn_tty_modem_result(1, info); + } + else + isdn_tty_modem_result(5, info); + } if (USG_VOICE(dev->usage[i])) isdn_tty_modem_result(11, info); return 1; @@ -2229,11 +2568,7 @@ sprintf(info->last_cause, "0000"); isdn_tty_modem_result(6, info); } - info->msr &= ~UART_MSR_DCD; - if (info->online) { - isdn_tty_modem_result(3, info); - info->online = 0; - } + isdn_tty_modem_hup(info, 0); return 1; } break; @@ -2249,6 +2584,20 @@ } } return 1; +#ifdef CONFIG_ISDN_AUDIO + case ISDN_STAT_AUDIO: + if (TTY_IS_ACTIVE(info)) { + switch(c->parm.num[0]) { + case ISDN_AUDIO_DTMF: + if (info->vonline) { + isdn_audio_put_dle_code(info, + c->parm.num[1]); + } + break; + } + } + break; +#endif } } return 0; @@ -2258,13 +2607,13 @@ Modem-Emulator-Routines *********************************************************************/ -#define cmdchar(c) ((c>' ')&&(c<=0x7f)) +#define cmdchar(c) ((c>=' ')&&(c<=0x7f)) /* * Put a message from the AT-emulator into receive-buffer of tty, * convert CR, LF, and BS to values in modem-registers 3, 4 and 5. */ -static void +void isdn_tty_at_cout(char *msg, modem_info * info) { struct tty_struct *tty; @@ -2394,7 +2743,7 @@ "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; ulong flags; - char s[10]; + char s[ISDN_MSNLEN+10]; switch (code) { case 2: @@ -2474,7 +2823,20 @@ } isdn_tty_at_cout(msg[code], info); switch (code) { + case 1: + switch (m->mdmreg[REG_L2PROT]) { + case ISDN_PROTO_L2_MODEM: + isdn_tty_at_cout(" ", info); + isdn_tty_at_cout(m->connmsg, info); + break; + } + break; case 2: + /* Append CPN, if enabled */ + if ((m->mdmreg[REG_CPN] & BIT_CPN)) { + sprintf(s, "/%s", m->cpn); + isdn_tty_at_cout(s, info); + } /* Print CID only once, _after_ 1.st RING */ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && (m->mdmreg[REG_RINGCNT] == 1)) { @@ -2561,7 +2923,9 @@ static void isdn_tty_get_msnstr(char *n, char **p) { - while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ',')) + while ((*p[0] >= '0' && *p[0] <= '9') || + /* Why a comma ??? */ + (*p[0] == ',')) *n++ = *p[0]++; *n = '\0'; } @@ -2576,8 +2940,9 @@ int limit=39; /* MUST match the size in isdn_tty_parse to avoid buffer overflow */ - while (strchr("0123456789,#.*WPTS-", *p) && *p && --cnt>0) { - if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first)) + while (strchr(" 0123456789,#.*WPTS-", *p) && *p && --cnt>0) { + if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) || + (*p == '*') || (*p == '#')) *q++ = *p; p++; if(!--limit) @@ -2627,6 +2992,12 @@ case ISDN_PROTO_L2_TRANS: isdn_tty_at_cout("transparent", info); break; + case ISDN_PROTO_L2_MODEM: + isdn_tty_at_cout("modem", info); + break; + case ISDN_PROTO_L2_FAX: + isdn_tty_at_cout("fax", info); + break; default: isdn_tty_at_cout("unknown", info); break; @@ -2669,6 +3040,8 @@ int i; char rb[100]; +#define MAXRB (sizeof(rb) - 1) + switch (*p[0]) { case 'B': /* &B - Set Buffersize */ @@ -2720,6 +3093,15 @@ isdn_tty_reset_profile(m); isdn_tty_modem_reset_regs(info, 1); break; + case 'L': + /* &L -Set Numbers to listen on */ + p[0]++; + i = 0; + while ((strchr("0123456789,-*[]?;", *p[0])) && + (i < ISDN_LMSNLEN) && *p[0]) + m->lmsn[i++] = *p[0]++; + m->lmsn[i] = '\0'; + break; case 'R': /* &R - Set V.110 bitrate adaption */ p[0]++; @@ -2775,6 +3157,11 @@ sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n", strlen(m->msn) ? m->msn : "None"); isdn_tty_at_cout(rb, info); + if (strlen(m->lmsn)) { + isdn_tty_at_cout("\r\nListen: ", info); + isdn_tty_at_cout(m->lmsn, info); + isdn_tty_at_cout("\r\n", info); + } break; case 'W': /* &W - Write Profile */ @@ -2867,7 +3254,7 @@ int bval; mreg = isdn_getnum(p); - if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) + if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG) PARSE_ERROR1; switch (*p[0]) { case '=': @@ -2940,9 +3327,10 @@ #ifdef CONFIG_ISDN_AUDIO /* If more than one bit set in reg18, autoselect Layer2 */ if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) { - if (m->mdmreg[REG_SI1I] == 1) - l2 = ISDN_PROTO_L2_TRANS; - else + if (m->mdmreg[REG_SI1I] == 1) { + if (l2 != ISDN_PROTO_L2_MODEM) + l2 = ISDN_PROTO_L2_TRANS; + } else l2 = ISDN_PROTO_L2_X75I; } #endif @@ -2958,7 +3346,10 @@ cmd.driver = info->isdn_driver; cmd.arg = info->isdn_channel; cmd.command = ISDN_CMD_ACCEPTD; + info->dialing = 16; + info->emu.carrierwait = 0; isdn_command(&cmd); + isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else isdn_tty_modem_result(8, info); } @@ -3133,8 +3524,9 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info) { atemu *m = &info->emu; + isdn_ctrl cmd; static char *vcmd[] = - {"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL}; + {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL}; int i; int par1; int par2; @@ -3222,6 +3614,11 @@ printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); PARSE_ERROR1; } + info->silence_state = isdn_audio_silence_init(info->silence_state); + if (!info->silence_state) { + printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n"); + PARSE_ERROR1; + } if (m->vpar[3] < 5) { info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); if (!info->adpcmr) { @@ -3248,31 +3645,27 @@ break; case '=': p[0]++; - switch (*p[0]) { - case '0': - case '1': - case '2': - case '3': - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 31)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[1] = par1; - m->vpar[2] = par2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n<0-31>,<0-255>", - info); - break; - default: + if ((*p[0]>='0') && (*p[0]<='9')) { + par1 = isdn_getnum(p); + if ((par1 < 0) || (par1 > 31)) PARSE_ERROR1; - } + if (*p[0] != ',') + PARSE_ERROR1; + p[0]++; + par2 = isdn_getnum(p); + if ((par2 < 0) || (par2 > 255)) + PARSE_ERROR1; + m->vpar[1] = par1; + m->vpar[2] = par2; + break; + } else + if (*p[0] == '?') { + p[0]++; + isdn_tty_at_cout("\r\n<0-31>,<0-255>", + info); + break; + } else + PARSE_ERROR1; break; default: PARSE_ERROR1; @@ -3309,9 +3702,9 @@ info); isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", info); - isdn_tty_at_cout("5;ALAW;8;0;(8000)", + isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n", info); - isdn_tty_at_cout("6;ULAW;8;0;(8000)", + isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n", info); break; default: @@ -3350,6 +3743,52 @@ isdn_tty_modem_result(1, info); return 0; break; + case 7: + /* AT+VDD - DTMF detection */ + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n<%d>,<%d>", + m->vpar[4], + m->vpar[5]); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if ((*p[0]>='0') && (*p[0]<='9')) { + if (info->online != 1) + PARSE_ERROR1; + par1 = isdn_getnum(p); + if ((par1 < 0) || (par1 > 15)) + PARSE_ERROR1; + if (*p[0] != ',') + PARSE_ERROR1; + p[0]++; + par2 = isdn_getnum(p); + if ((par2 < 0) || (par2 > 255)) + PARSE_ERROR1; + m->vpar[4] = par1; + m->vpar[5] = par2; + cmd.driver = info->isdn_driver; + cmd.command = ISDN_CMD_AUDIO; + cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8); + cmd.parm.num[0] = par1; + cmd.parm.num[1] = par2; + isdn_command(&cmd); + break; + } else + if (*p[0] == '?') { + p[0]++; + isdn_tty_at_cout("\r\n<0-15>,<0-255>", + info); + break; + } else + PARSE_ERROR1; + break; + default: + PARSE_ERROR1; + } + break; default: PARSE_ERROR1; } @@ -3372,6 +3811,9 @@ #endif for (p = &m->mdmcmd[2]; *p;) { switch (*p) { + case ' ': + p++; + break; case 'A': /* A - Accept incoming call */ p++; @@ -3446,7 +3888,7 @@ p++; if (info->msr & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result(5, info); + isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info); else isdn_tty_modem_result(3, info); return; @@ -3487,29 +3929,46 @@ case 'Z': /* Z - Load Registers from Profile */ p++; + if (info->msr & UART_MSR_DCD) { + info->online = 0; + isdn_tty_on_hook(info); + } isdn_tty_modem_reset_regs(info, 1); break; -#ifdef CONFIG_ISDN_AUDIO case '+': p++; switch (*p) { +#ifdef CONFIG_ISDN_AUDIO case 'F': p++; if (isdn_tty_cmd_PLUSF(&p, info)) return; break; case 'V': - if (!(m->mdmreg[REG_SI1] & 1)) + if ((!(m->mdmreg[REG_SI1] & 1)) || + (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) PARSE_ERROR; p++; if (isdn_tty_cmd_PLUSV(&p, info)) return; break; +#endif /* CONFIG_ISDN_AUDIO */ + case 'S': /* SUSPEND */ + p++; + isdn_tty_get_msnstr(ds, &p); + isdn_tty_suspend(ds, info, m); + break; + case 'R': /* RESUME */ + isdn_tty_get_msnstr(ds, &p); + isdn_tty_resume(ds, info, m); + case 'M': /* MESSAGE */ + p++; + isdn_tty_send_msg(info, m, p); + break; default: PARSE_ERROR; } break; -#endif /* CONFIG_ISDN_AUDIO */ case '&': p++; if (isdn_tty_cmd_ATand(&p, info)) @@ -3562,7 +4021,7 @@ eb[1] = 0; isdn_tty_at_cout(eb, info); } - if (m->mdmcmdl >= 2) + if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2)))) isdn_tty_parse_at(info); m->mdmcmdl = 0; continue; @@ -3588,15 +4047,16 @@ switch (m->mdmcmdl) { case 0: if (c == 'A') - m->mdmcmd[m->mdmcmdl++] = c; + m->mdmcmd[m->mdmcmdl] = c; break; case 1: if (c == 'T') - m->mdmcmd[m->mdmcmdl++] = c; + m->mdmcmd[m->mdmcmdl] = c; break; default: - m->mdmcmd[m->mdmcmdl++] = c; + m->mdmcmd[m->mdmcmdl] = c; } + m->mdmcmd[++m->mdmcmdl] = 0; } } } @@ -3673,4 +4133,29 @@ } } isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); +} + +/* + * Check all channels if we have a 'no carrier' timeout. + * Timeout value is set by Register S7. + */ +void +isdn_tty_carrier_timeout(void) +{ + int ton = 0; + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) { + modem_info *info = &dev->mdm.info[i]; + if (info->dialing) { + if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { + info->dialing = 0; + isdn_tty_modem_result(3, info); + isdn_tty_modem_hup(info, 1); + } + else + ton = 1; + } + } + isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.2.10/linux/drivers/isdn/isdn_tty.h Thu May 29 21:53:06 1997 +++ linux/drivers/isdn/isdn_tty.h Mon Aug 9 12:04:39 1999 @@ -1,8 +1,8 @@ -/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $ +/* $Id: isdn_tty.h,v 1.14 1999/07/11 17:14:15 armin Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * - * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,35 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.14 1999/07/11 17:14:15 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * + * Revision 1.13 1999/04/12 12:33:46 fritz + * Changes from 2.0 tree. + * + * Revision 1.12 1999/03/02 12:04:51 armin + * -added ISDN_STAT_ADDCH to increase supported channels after + * register_isdn(). + * -ttyI now goes on-hook on ATZ when B-Ch is connected. + * -added timer-function for register S7 (Wait for Carrier). + * -analog modem (ISDN_PROTO_L2_MODEM) implementations. + * -on L2_MODEM a string will be appended to the CONNECT-Message, + * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. + * -variable "dialing" used for ATA also, for interrupting call + * establishment and register S7. + * + * Revision 1.11 1998/03/19 13:18:27 keil + * Start of a CAPI like interface for supplementary Service + * first service: SUSPEND + * * Revision 1.10 1997/03/02 14:29:26 fritz * More ttyI related cleanup. * @@ -54,8 +83,71 @@ * */ + +#define DLE 0x10 +#define ETX 0x03 +#define DC4 0x14 + + +/* + * Definition of some special Registers of AT-Emulator + */ +#define REG_RINGATA 0 +#define REG_RINGCNT 1 +#define REG_ESC 2 +#define REG_CR 3 +#define REG_LF 4 +#define REG_BS 5 + +#define REG_WAITC 7 + +#define REG_RESP 12 +#define BIT_RESP 1 +#define REG_RESPNUM 12 +#define BIT_RESPNUM 2 +#define REG_ECHO 12 +#define BIT_ECHO 4 +#define REG_DCD 12 +#define BIT_DCD 8 +#define REG_CTS 12 +#define BIT_CTS 16 +#define REG_DTRR 12 +#define BIT_DTRR 32 +#define REG_DSR 12 +#define BIT_DSR 64 +#define REG_CPPP 12 +#define BIT_CPPP 128 + +#define REG_T70 13 +#define BIT_T70 2 +#define BIT_T70_EXT 32 +#define REG_DTRHUP 13 +#define BIT_DTRHUP 4 +#define REG_RESPXT 13 +#define BIT_RESPXT 8 +#define REG_CIDONCE 13 +#define BIT_CIDONCE 16 +#define REG_RUNG 13 +#define BIT_RUNG 64 +#define REG_DISPLAY 13 +#define BIT_DISPLAY 128 + +#define REG_L2PROT 14 +#define REG_L3PROT 15 +#define REG_PSIZE 16 +#define REG_WSIZE 17 +#define REG_SI1 18 +#define REG_SI2 19 +#define REG_SI1I 20 +#define REG_PLAN 21 +#define REG_SCREEN 22 + +#define REG_CPN 23 +#define BIT_CPN 1 + extern void isdn_tty_modem_escape(void); extern void isdn_tty_modem_ring(void); +extern void isdn_tty_carrier_timeout(void); extern void isdn_tty_modem_xmit(void); extern int isdn_tty_modem_init(void); extern void isdn_tty_readmodem(void); @@ -63,3 +155,5 @@ extern void isdn_tty_cleanup_xmit(modem_info *); extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); +extern int isdn_tty_capi_facility(capi_msg *cm); +extern void isdn_tty_at_cout(char *, modem_info *); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdn_x25iface.c linux/drivers/isdn/isdn_x25iface.c --- v2.2.10/linux/drivers/isdn/isdn_x25iface.c Thu Jan 7 08:46:59 1999 +++ linux/drivers/isdn/isdn_x25iface.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isdn_x25iface.c,v 1.3 1998/02/20 17:25:20 fritz Exp $ +/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $ * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -10,6 +10,17 @@ * goes to another -- device related -- concap_proto support source file. * * $Log: isdn_x25iface.c,v $ + * Revision 1.6 1999/01/27 22:53:19 he + * minor updates (spellings, jiffies wrap around in isdn_tty) + * + * Revision 1.5 1998/10/30 17:55:39 he + * dialmode for x25iface and multulink ppp + * + * Revision 1.4 1998/06/17 19:51:00 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * * Revision 1.3 1998/02/20 17:25:20 fritz * Changes for recent kernels. * @@ -302,7 +313,12 @@ case 0x01: /* dl_connect request */ if( *state == WAN_DISCONNECTED ){ *state = WAN_CONNECTING; - cprot -> dops -> connect_req(cprot); + ret = cprot -> dops -> connect_req(cprot); + if(ret){ + /* reset state and notify upper layer about + * immidiatly failed attempts */ + isdn_x25iface_disconn_ind(cprot); + } } else { illegal_state_warn( *state, firstbyte ); } diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.2.10/linux/drivers/isdn/isdnloop/isdnloop.c Sat Oct 31 10:37:14 1998 +++ linux/drivers/isdn/isdnloop/isdnloop.c Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.4 1998/02/24 21:39:05 he Exp $ +/* $Id: isdnloop.c,v 1.8 1998/11/18 18:59:43 armin Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -19,6 +19,20 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnloop.c,v $ + * Revision 1.8 1998/11/18 18:59:43 armin + * changes for 2.1.127 + * + * Revision 1.7 1998/10/30 18:58:03 he + * typecast to suppress a compiler warning + * + * Revision 1.6 1998/06/17 19:51:37 he + * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) + * brute force fix to avoid Ugh's in isdn_tty_write() + * cleaned up some dead code + * + * Revision 1.5 1998/04/14 20:59:32 he + * merged 2.1.94 changes + * * Revision 1.4 1998/02/24 21:39:05 he * L2_PROT_X25DTE / DCE * additional state 17 and new internal signal messages "BCON_I" @@ -42,7 +56,7 @@ #include "isdnloop.h" static char -*revision = "$Revision: 1.4 $"; +*revision = "$Revision: 1.8 $"; static int isdnloop_addcard(char *); @@ -1312,7 +1326,7 @@ c->parm.num[0] ? "N" : "ALL", c->parm.num); } else sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : "0123456789"); + c->parm.num[0] ? c->parm.num : (u_char *) "0123456789"); i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); } break; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h --- v2.2.10/linux/drivers/isdn/isdnloop/isdnloop.h Tue Apr 7 07:52:04 1998 +++ linux/drivers/isdn/isdnloop/isdnloop.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.h,v 1.2 1997/10/01 09:22:07 fritz Exp $ +/* $Id: isdnloop.h,v 1.3 1998/04/14 20:59:35 he Exp $ * Loopback lowlevel module for testing of linklevel. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnloop.h,v $ + * Revision 1.3 1998/04/14 20:59:35 he + * merged 2.1.94 changes + * * Revision 1.2 1997/10/01 09:22:07 fritz * Removed old compatibility stuff for 2.0.X kernels. * From now on, this code is for 2.1.X ONLY! diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v2.2.10/linux/drivers/isdn/pcbit/callbacks.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/pcbit/callbacks.c Mon Aug 9 12:04:39 1999 @@ -11,6 +11,13 @@ * callbacks for the FSM */ +/* + * Fix: 19981230 - Carlos Morgado + * Port of Nelson Escravana's fix to CalledPN + * NULL pointer dereference in cb_in_1 (originally fixed in 2.0) + */ + + #define __NO_VERSION__ #include @@ -164,12 +171,24 @@ * ictl.num >= strlen() + strlen() + 5 */ + if (cbdata->data.setup.CallingPN == NULL) { + printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n"); + strcpy(ictl.parm.setup.phone, "0"); + } + else { strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); + } + if (cbdata->data.setup.CalledPN == NULL) { + printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n"); + strcpy(ictl.parm.setup.eazmsn, "0"); + } + else { strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN); - ictl.parm.setup.si1 = 7; - ictl.parm.setup.si2 = 0; - ictl.parm.setup.plan = 0; - ictl.parm.setup.screen = 0; + } + ictl.parm.setup.si1 = 7; + ictl.parm.setup.si2 = 0; + ictl.parm.setup.plan = 0; + ictl.parm.setup.screen = 0; #ifdef DEBUG printk(KERN_DEBUG "statstr: %s\n", ictl.num); diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.2.10/linux/drivers/isdn/pcbit/drv.c Wed Apr 1 16:21:03 1998 +++ linux/drivers/isdn/pcbit/drv.c Mon Aug 9 12:04:39 1999 @@ -86,6 +86,9 @@ dev_pcbit[board] = dev; memset(dev, 0, sizeof(struct pcbit_dev)); +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&dev->set_running_wq); +#endif if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) dev->sh_mem = (unsigned char*) mem_base; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/pcbit/pcbit.h linux/drivers/isdn/pcbit/pcbit.h --- v2.2.10/linux/drivers/isdn/pcbit/pcbit.h Tue Aug 4 10:31:59 1998 +++ linux/drivers/isdn/pcbit/pcbit.h Mon Aug 9 12:04:39 1999 @@ -68,7 +68,11 @@ struct frame_buf *write_queue; /* Protocol start */ +#ifdef COMPAT_HAS_NEW_WAITQ + wait_queue_head_t set_running_wq; +#else struct wait_queue *set_running_wq; +#endif struct timer_list set_running_timer; struct timer_list error_recover_timer; diff -u --recursive --new-file v2.2.10/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.2.10/linux/drivers/isdn/sc/message.c Thu Nov 5 09:58:44 1998 +++ linux/drivers/isdn/sc/message.c Mon Aug 9 12:04:39 1999 @@ -1,5 +1,5 @@ /* - * $Id: message.c,v 1.3 1998/01/31 22:10:55 keil Exp $ + * $Id: message.c,v 1.4 1999/01/05 18:29:47 he Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * message.c - functions for sending and receiving control messages diff -u --recursive --new-file v2.2.10/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.2.10/linux/drivers/macintosh/mediabay.c Mon Dec 21 08:37:28 1998 +++ linux/drivers/macintosh/mediabay.c Mon Aug 9 12:04:57 1999 @@ -64,8 +64,7 @@ #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ -#define MB_IDE_READY(i) ((in_8((volatile unsigned char *) \ - (media_bays[i].cd_base + 0x70)) & 0x80) == 0) +#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif /* diff -u --recursive --new-file v2.2.10/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.2.10/linux/drivers/macintosh/via-pmu.c Thu Apr 29 12:53:48 1999 +++ linux/drivers/macintosh/via-pmu.c Mon Aug 9 12:04:57 1999 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,9 @@ static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); static void set_volume(int level); +#ifdef CONFIG_PMAC_PBOOK +static void pmu_pass_intr(unsigned char *data, int len); +#endif static struct adb_controller pmu_controller = { ADB_VIAPMU, @@ -729,21 +733,32 @@ } pmu_done(req); } else { - adb_input(data+1, len-1, regs, 1); + /* + * XXX the PMU gives us an up event for keycodes + * 0x74 or 0x75 when the PC card eject buttons + * are released, so we ignore those events. + */ + if (!(len == 4 && data[1] == 0x2c && data[3] == 0xff + && (data[2] & ~1) == 0xf4)) + adb_input(data+1, len-1, regs, 1); } + } else if (data[0] == 0x08 && len == 3) { + /* sound/brightness buttons pressed */ + pmu_set_brightness(data[1] >> 3); + set_volume(data[2]); } else { - if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); - set_volume(data[2]); - } else if (show_pmu_ints - && !(data[0] == PMU_INT_TICK && len == 1)) { +#ifdef CONFIG_PMAC_PBOOK + pmu_pass_intr(data, len); +#else + if (show_pmu_ints + && !(data[0] == PMU_INT_TICK && len == 1)) { int i; printk(KERN_DEBUG "pmu intr"); for (i = 0; i < len; ++i) printk(" %.2x", data[i]); printk("\n"); } +#endif } } @@ -1064,15 +1079,112 @@ /* * Support for /dev/pmu device */ +#define RB_SIZE 10 +struct pmu_private { + struct list_head list; + int rb_get; + int rb_put; + struct rb_entry { + unsigned short len; + unsigned char data[16]; + } rb_buf[RB_SIZE]; + struct wait_queue *wait; + spinlock_t lock; +}; + +static LIST_HEAD(all_pmu_pvt); +static spinlock_t all_pvt_lock = SPIN_LOCK_UNLOCKED; + +static void pmu_pass_intr(unsigned char *data, int len) +{ + struct pmu_private *pp; + struct list_head *list; + int i; + unsigned long flags; + + if (len > sizeof(pp->rb_buf[0].data)) + len = sizeof(pp->rb_buf[0].data); + spin_lock_irqsave(&all_pvt_lock, flags); + for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) { + pp = list_entry(list, struct pmu_private, list); + i = pp->rb_put + 1; + if (i >= RB_SIZE) + i = 0; + if (i != pp->rb_get) { + struct rb_entry *rp = &pp->rb_buf[pp->rb_put]; + rp->len = len; + memcpy(rp->data, data, len); + pp->rb_put = i; + wake_up_interruptible(&pp->wait); + } + } + spin_unlock_irqrestore(&all_pvt_lock, flags); +} + static int __openfirmware pmu_open(struct inode *inode, struct file *file) { + struct pmu_private *pp; + unsigned long flags; + + pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL); + if (pp == 0) + return -ENOMEM; + pp->rb_get = pp->rb_put = 0; + spin_lock_init(&pp->lock); + pp->wait = 0; + spin_lock_irqsave(&all_pvt_lock, flags); + list_add(&pp->list, &all_pmu_pvt); + spin_unlock_irqrestore(&all_pvt_lock, flags); + file->private_data = pp; return 0; } static ssize_t __openfirmware pmu_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - return 0; + struct pmu_private *pp = file->private_data; + struct wait_queue wait = { current, NULL }; + int ret; + + if (count < 1 || pp == 0) + return -EINVAL; + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + add_wait_queue(&pp->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + for (;;) { + ret = -EAGAIN; + spin_lock(&pp->lock); + if (pp->rb_get != pp->rb_put) { + int i = pp->rb_get; + struct rb_entry *rp = &pp->rb_buf[i]; + ret = rp->len; + if (ret > count) + ret = count; + if (ret > 0 && copy_to_user(buf, rp->data, ret)) + ret = -EFAULT; + if (++i >= RB_SIZE) + i = 0; + pp->rb_get = i; + } + spin_unlock(&pp->lock); + if (ret >= 0) + break; + + if (file->f_flags & O_NONBLOCK) + break; + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&pp->wait, &wait); + + return ret; } static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, @@ -1081,6 +1193,36 @@ return 0; } +static unsigned int pmu_fpoll(struct file *filp, poll_table *wait) +{ + struct pmu_private *pp = filp->private_data; + unsigned int mask = 0; + + if (pp == 0) + return 0; + poll_wait(filp, &pp->wait, wait); + spin_lock(&pp->lock); + if (pp->rb_get != pp->rb_put) + mask |= POLLIN; + spin_unlock(&pp->lock); + return mask; +} + +static int pmu_release(struct inode *inode, struct file *file) +{ + struct pmu_private *pp = file->private_data; + unsigned long flags; + + if (pp != 0) { + file->private_data = 0; + spin_lock_irqsave(&all_pvt_lock, flags); + list_del(&pp->list); + spin_unlock_irqrestore(&all_pvt_lock, flags); + kfree(pp); + } + return 0; +} + /* Note: removed __openfirmware here since it causes link errors */ static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) @@ -1089,18 +1231,18 @@ __u32 value; switch (cmd) { - case PMU_IOC_SLEEP: + case PMU_IOC_SLEEP: if (pmu_kind != PMU_OHARE_BASED) return -ENOSYS; return powerbook_sleep(); - case PMU_IOC_GET_BACKLIGHT: + case PMU_IOC_GET_BACKLIGHT: return put_user(backlight_level, (__u32 *)arg); - case PMU_IOC_SET_BACKLIGHT: + case PMU_IOC_SET_BACKLIGHT: error = get_user(value, (__u32 *)arg); if (!error) pmu_set_brightness(value); return error; - case PMU_IOC_GET_MODEL: + case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); } return -EINVAL; @@ -1111,12 +1253,12 @@ pmu_read, pmu_write, NULL, /* no readdir */ - NULL, /* no poll yet */ + pmu_fpoll, pmu_ioctl, NULL, /* no mmap */ pmu_open, NULL, /* flush */ - NULL /* no release */ + pmu_release, }; static struct miscdevice pmu_device = { diff -u --recursive --new-file v2.2.10/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.2.10/linux/drivers/misc/parport_pc.c Tue Jun 1 16:43:43 1999 +++ linux/drivers/misc/parport_pc.c Mon Aug 9 12:05:05 1999 @@ -829,9 +829,9 @@ /* Done probing. Now put the port into a sensible start-up state. */ if (p->modes & PARPORT_MODE_PCECR) /* - * Put the ECP detected port in the more SPP like mode. + * Put the ECP detected port in the more PS2 like mode. */ - parport_pc_write_econtrol(p, 0x0); + parport_pc_write_econtrol(p, 0x34); parport_pc_write_control(p, 0x8); parport_pc_write_data(p, 0); udelay (50); diff -u --recursive --new-file v2.2.10/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.2.10/linux/drivers/net/Config.in Mon Jun 7 14:35:22 1999 +++ linux/drivers/net/Config.in Mon Aug 9 12:05:13 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 @@ -19,9 +24,16 @@ tristate 'Ethertap network tap' CONFIG_ETHERTAP fi fi + +tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 + # # 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 @@ -42,7 +54,7 @@ tristate 'Hydra support' CONFIG_HYDRA fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then - bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC + tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC fi bool '3COM cards' CONFIG_NET_VENDOR_3COM if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then @@ -81,19 +93,17 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC 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 +113,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 +125,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 +156,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 +166,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 +191,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 +212,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 +251,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 +276,19 @@ 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 --recursive --new-file v2.2.10/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.2.10/linux/drivers/net/Makefile Mon Jun 7 14:35:22 1999 +++ linux/drivers/net/Makefile Mon Aug 9 12:05:13 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 @@ -83,6 +91,14 @@ endif endif +ifeq ($(CONFIG_NET_SB1000),y) +L_OBJS += sb1000.o +else + ifeq ($(CONFIG_NET_SB1000),m) + M_OBJS += sb1000.o + endif +endif + ifeq ($(CONFIG_DAYNAPORT), y) L_OBJS += daynaport.o CONFIG_8390_BUILTIN = y @@ -143,14 +159,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 +179,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 +438,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 @@ -558,6 +566,14 @@ endif endif +ifeq ($(CONFIG_SIS900),y) +L_OBJS += sis900.o +else + ifeq ($(CONFIG_SIS900),m) + M_OBJS += sis900.o + endif +endif + ifeq ($(CONFIG_YELLOWFIN),y) L_OBJS += yellowfin.o else @@ -582,6 +598,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 +804,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 @@ -892,10 +929,26 @@ endif ifeq ($(CONFIG_MIPS_JAZZ_SONIC),y) -L_OBJS += sonic.o +L_OBJS += jazzsonic.o else ifeq ($(CONFIG_MIPS_JAZZ_SONIC),m) - M_OBJS += sonic.o + M_OBJS += jazzsonic.o + endif +endif + +ifeq ($(CONFIG_BAGETLANCE),y) +L_OBJS += bagetlance.o +else + ifeq ($(CONFIG_BAGETLANCE),m) + M_OBJS += bagetlance.o + endif +endif + +ifeq ($(CONFIG_DECLANCE),y) +L_OBJS += declance.o +else + ifeq ($(CONFIG_DECLANCE),m) + M_OBJS += declance.o endif endif diff -u --recursive --new-file v2.2.10/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.2.10/linux/drivers/net/Space.c Mon Jun 7 14:35:22 1999 +++ linux/drivers/net/Space.c Mon Aug 9 12:05:13 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 *); @@ -110,7 +111,10 @@ extern int am79c961_probe(struct device *dev); extern int epic100_probe(struct device *dev); extern int rtl8139_probe(struct device *dev); +extern int sis900_probe(struct device *dev); extern int hplance_probe(struct device *dev); +extern int bagetlance_probe(struct device *); +extern int dec_lance_probe(struct device *); extern int via_rhine_probe(struct device *dev); extern int tc515_probe(struct device *dev); extern int lance_probe(struct device *dev); @@ -202,6 +206,9 @@ #ifdef CONFIG_RTL8139 {rtl8139_probe, 0}, #endif +#ifdef CONFIG_SIS900 + {sis900_probe, 0}, +#endif #ifdef CONFIG_YELLOWFIN {yellowfin_probe, 0}, #endif @@ -357,6 +364,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 @@ -443,6 +453,12 @@ #ifdef CONFIG_MIPS_JAZZ_SONIC {sonic_probe, 0}, #endif +#ifdef CONFIG_DECLANCE /* DECstation on-board controller */ + {dec_lance_probe, 0}, /* and maybe TURBOchannel option boards */ +#endif +#ifdef CONFIG_BAGETLANCE /* Lance-based Baget ethernet boards */ + {bagetlance_probe, 0}, +#endif {NULL, 0}, }; @@ -668,6 +684,14 @@ #define NEXT_DEV (&mkiss_bootstrap) #endif /* MKISS */ +#if defined(CONFIG_YAM) +extern int yam_init(struct device *); +static struct device yam_bootstrap = { + "yam", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, yam_init, }; +#undef NEXT_DEV +#define NEXT_DEV (&yam_bootstrap) +#endif /* CONFIG_YAM */ + #if defined(CONFIG_STRIP) extern int strip_init_ctrl_dev(struct device *); static struct device strip_bootstrap = { @@ -711,6 +735,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) @@ -719,6 +744,9 @@ #ifdef CONFIG_IBMTR && ibmtr_probe(dev) #endif +#ifdef CONFIG_IBMOL + && olympic_probe(dev) +#endif #ifdef CONFIG_SKTR && sktr_probe(dev) #endif @@ -792,6 +820,14 @@ "bif", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init }; # undef NEXT_DEV # define NEXT_DEV (&bif_dev) +#endif + +#ifdef CONFIG_NET_SB1000 + extern int sb1000_init(struct device *dev); + static struct device sb1000_dev = { + "cm0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, sb1000_probe }; +# undef NEXT_DEV +# define NEXT_DEV (&sb1000_dev) #endif extern int loopback_init(struct device *dev); diff -u --recursive --new-file v2.2.10/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.2.10/linux/drivers/net/acenic.c Mon Mar 22 08:08:12 1999 +++ linux/drivers/net/acenic.c Mon Aug 9 12:04:57 1999 @@ -2,7 +2,7 @@ * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * - * Copyright 1998 by Jes Sorensen, . + * Copyright 1998, 1999 by Jes Sorensen, . * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -67,6 +67,16 @@ #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a #endif +/* + * They used the DEC vendor ID by mistake + */ +#ifndef PCI_DEVICE_ID_FARALLON_PN9000SX +#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a +#endif +#ifndef PCI_VENDOR_ID_SGI +#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 +#endif /* * This driver currently supports Tigon I and Tigon II based cards @@ -171,7 +181,7 @@ static int max_rx_desc[8] = {0, }; static int tx_ratio[8] = {0, }; -static const char __initdata *version = "acenic.c: v0.32 03/15/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static const char __initdata *version = "acenic.c: v0.33 07/20/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct device *root_dev = NULL; @@ -208,7 +218,15 @@ !((pdev->vendor == PCI_VENDOR_ID_3COM) && (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620))) + (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)) && + /* + * Farallon used the DEC vendor ID on their cards by + * mistake for a while + */ + !((pdev->vendor == PCI_VENDOR_ID_DEC) && + (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) && + !((pdev->vendor == PCI_VENDOR_ID_SGI) && + (pdev->device == PCI_DEVICE_ID_SGI_ACENIC))) continue; dev = init_etherdev(dev, sizeof(struct ace_private)); @@ -282,6 +300,18 @@ sprintf(ap->name, "NetGear GA620 Gigabit Ethernet"); printk(KERN_INFO "%s: NetGear GA620 ", dev->name); break; + case PCI_VENDOR_ID_DEC: + if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX) { + sprintf(ap->name, "Farallon PN9000-SX " + "Gigabit Ethernet"); + printk(KERN_INFO "%s: Farallon PN9000-SX ", + dev->name); + break; + } + case PCI_VENDOR_ID_SGI: + sprintf(ap->name, "SGI AceNIC Gigabit Ethernet"); + printk(KERN_INFO "%s: SGI AceNIC ", dev->name); + break; default: sprintf(ap->name, "Unknown AceNIC based Gigabit Ethernet"); printk(KERN_INFO "%s: Unknown AceNIC ", dev->name); @@ -569,7 +599,7 @@ * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ - if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL | GFP_DMA))){ + if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))){ free_irq(dev->irq, dev); return -EAGAIN; } @@ -1162,6 +1192,12 @@ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); +#if 0 + /* + * This was never actually enabled in the RX descriptors + * anyway - it requires a bit more testing before enabling + * it again. + */ /* * If the checksum is correct and this is not a * fragment, tell the stack that the data is correct. @@ -1172,7 +1208,7 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; - +#endif netif_rx(skb); /* send it up */ ap->stats.rx_packets++; diff -u --recursive --new-file v2.2.10/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.2.10/linux/drivers/net/acenic_firmware.h Mon Mar 22 08:08:12 1999 +++ linux/drivers/net/acenic_firmware.h Mon Aug 9 12:04:57 1999 @@ -1,31 +1,31 @@ /* Generated by genfw.c */ int tigonFwReleaseMajor = 0xc; int tigonFwReleaseMinor = 0x3; -int tigonFwReleaseFix = 0x5; +int tigonFwReleaseFix = 0xa; u32 tigonFwStartAddr = 0x00004000; u32 tigonFwTextAddr = 0x00004000; -int tigonFwTextLen = 0x10910; -u32 tigonFwRodataAddr = 0x00014910; +int tigonFwTextLen = 0x10920; +u32 tigonFwRodataAddr = 0x00014920; int tigonFwRodataLen = 0xaa0; -u32 tigonFwDataAddr = 0x000153d0; +u32 tigonFwDataAddr = 0x000153e0; int tigonFwDataLen = 0x150; -u32 tigonFwSbssAddr = 0x00015520; +u32 tigonFwSbssAddr = 0x00015530; int tigonFwSbssLen = 0x2c; -u32 tigonFwBssAddr = 0x00015550; +u32 tigonFwBssAddr = 0x00015560; int tigonFwBssLen = 0x2080; u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, -0x8fbd5404, 0x3a0f021, 0x3c100000, 0x26104000, +0x8fbd5414, 0x3a0f021, 0x3c100000, 0x26104000, 0xc00100c, 0x0, 0xd, 0x27bdffd8, 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, 0xafbf0024, 0xc00248c, 0xafb00020, 0xc0023ec, -0x0, 0x3c040001, 0x24844970, 0x24050001, -0x2e03021, 0x3821, 0x3c100001, 0x261075d0, +0x0, 0x3c040001, 0x24844984, 0x24050001, +0x2e03021, 0x3821, 0x3c100001, 0x261075e0, 0xafb00010, 0xc002407, 0xafbb0014, 0x3c02000f, 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, -0x24050003, 0x3c040001, 0x2484497c, 0x2003021, +0x24050003, 0x3c040001, 0x24844990, 0x2003021, 0x3603821, 0x3c020010, 0xafa20010, 0xc002407, 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 0x370821, 0xa02083b0, 0x3c010001, 0x370821, @@ -63,7 +63,7 @@ 0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc, 0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, 0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, -0x24844988, 0x3c050001, 0xafa00010, 0xafa00014, +0x2484499c, 0x3c050001, 0xafa00010, 0xafa00014, 0x8ee704fc, 0x34a5f000, 0xc002407, 0x603021, 0x26e40030, 0xc00248c, 0x24050400, 0x27440080, 0xc00248c, 0x24050080, 0x26e4777c, 0xc00248c, @@ -73,7 +73,7 @@ 0x3442ca00, 0x2021, 0x24030002, 0xaee30074, 0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, -0x641821, 0x906353d0, 0x2e41021, 0x24840001, +0x641821, 0x906353e0, 0x2e41021, 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 0x24420030, 0xa062009c, 0x2e41021, 0xa040009c, @@ -119,7 +119,7 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, -0xaee90608, 0x3c040001, 0x24844994, 0xafa00010, +0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x8001223, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, @@ -145,21 +145,21 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14c0001b, 0x0, -0x3c040001, 0x2484499c, 0xafa00010, 0xafa00014, +0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, -0x8001223, 0x8ee201b0, 0x3c040001, 0x248449a8, +0x8001223, 0x8ee201b0, 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, -0x248449b4, 0x3405f001, 0x24420001, 0xaee20160, +0x248449c8, 0x3405f001, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x8001238, 0x0, 0x3c020001, 0x2442f5b8, 0x21100, 0x21182, 0x431025, 0x3c010001, 0xac221278, 0x96e2045a, 0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, 0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, -0x3c040001, 0x248449c0, 0x24020001, 0xa2e204ec, +0x3c040001, 0x248449d4, 0x24020001, 0xa2e204ec, 0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, 0x2442a3a0, 0x451024, 0x21082, 0xaee304c8, 0x3c030800, 0x431025, 0x3c010001, 0xac221220, @@ -202,7 +202,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x800136d, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, @@ -227,17 +227,17 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, -0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, -0x8ee20160, 0x3c040001, 0x248449b4, 0x3405f002, +0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f002, 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, -0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449cc, +0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449e0, 0x24050012, 0xafa00010, 0xc002407, 0xafa00014, 0xc004500, 0x0, 0xc002318, 0x0, 0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, @@ -280,7 +280,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x24844994, 0xafa00010, 0xafa00014, 0x8ee60608, +0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x80014a5, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 0x27663000, @@ -305,11 +305,11 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x2484499c, +0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, -0x3c040001, 0x248449a8, 0xafa00014, 0x8ee60608, +0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, @@ -331,7 +331,7 @@ 0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821, 0xac2083bc, 0x3c010001, 0x370821, 0x3e00008, 0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020, -0x8f820054, 0x3c030001, 0x8c635488, 0x24420067, +0x8f820054, 0x3c030001, 0x8c635498, 0x24420067, 0x1060000d, 0xaf820058, 0x3c020001, 0x571021, 0x904283b8, 0x10400005, 0x3c030200, 0x3c010001, 0x370821, 0x8001503, 0xa02083b8, 0x8ee20000, @@ -349,7 +349,7 @@ 0x0, 0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, 0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, -0x24844a40, 0xafa00014, 0xafa20010, 0x8f8600b0, +0x24844a50, 0xafa00014, 0xafa20010, 0x8f8600b0, 0x3c050005, 0xc002407, 0x34a50900, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, @@ -377,10 +377,10 @@ 0xac820000, 0x24020001, 0xac820004, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4, 0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001, -0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a4c, +0xaee201e4, 0x8ee201e4, 0x3c040001, 0x24844a5c, 0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, -0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a54, +0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a64, 0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, 0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002407, 0x34a50900, 0x80015cc, 0x0, 0x8f820104, @@ -413,7 +413,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, -0x8ee204e4, 0x3c040001, 0x24844a5c, 0xafa00014, +0x8ee204e4, 0x3c040001, 0x24844a6c, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f006, 0x16000003, 0x24020001, 0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, @@ -443,7 +443,7 @@ 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, -0x24844a68, 0xafa00014, 0xafa20010, 0x8ee6724c, +0x24844a78, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, 0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, @@ -554,11 +554,11 @@ 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x14620003, 0x3c050009, 0x800197c, 0x24100001, 0x3c040001, -0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, -0x24844a80, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a90, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x34a5f010, 0xc002407, 0x8021, -0x800197c, 0x0, 0x3c040001, 0x24844a8c, +0x800197c, 0x0, 0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, @@ -589,7 +589,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x5600000c, 0xaee90608, -0x3c040001, 0x24844a98, 0xafa00010, 0xafa00014, +0x3c040001, 0x24844aa8, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x800197c, 0x0, 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 0x50400001, @@ -615,10 +615,10 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600001d, 0x24100001, 0x3c040001, -0x24844aa0, 0xafa00010, 0xafa00014, 0x8ee60608, +0x24844ab0, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, -0x8ee201b0, 0x3c040001, 0x24844aac, 0xafa00014, +0x8ee201b0, 0x3c040001, 0x24844abc, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, 0xc002407, 0x0, 0x8ee201ac, 0x8021, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, @@ -626,7 +626,7 @@ 0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, 0x8ee30158, 0x800198c, 0xaee27278, 0x24020001, 0x3c010001, 0x370821, 0xa02283b0, 0x3c020001, -0x8c425488, 0x10400187, 0x0, 0x8ee27b84, +0x8c425498, 0x10400187, 0x0, 0x8ee27b84, 0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84, 0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84, 0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002, @@ -690,12 +690,12 @@ 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, 0x0, 0x3c040001, -0x24844a74, 0xafa00010, 0xafa00014, 0x8f860120, +0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, -0x8001aad, 0x0, 0x3c040001, 0x24844a80, +0x8001aad, 0x0, 0x3c040001, 0x24844a90, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x8001aad, 0x0, -0x3c040001, 0x24844a8c, 0xafa00014, 0x8ee60608, +0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, @@ -742,18 +742,18 @@ 0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001, 0x10400004, 0x24020001, 0xaf820064, 0x80022f4, 0x0, 0x32c20002, 0x1440000c, 0x3c050003, -0x3c040001, 0x24844b24, 0x34a50001, 0x2c03021, +0x3c040001, 0x24844b34, 0x34a50001, 0x2c03021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 0x21080, 0x5a1021, 0x8c420300, 0xafa20020, 0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, -0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b30, +0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b40, 0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, 0xc002407, 0x34a5f01f, 0x3821, 0x14e00003, 0x0, 0x80022ed, 0xaf960064, 0x93a20020, 0x2443ffff, 0x2c620011, 0x10400658, 0x31080, -0x3c010001, 0x220821, 0x8c224be8, 0x400008, +0x3c010001, 0x220821, 0x8c224bf8, 0x400008, 0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c, 0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118, 0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118, @@ -769,7 +769,7 @@ 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x8001bd0, 0xaee20078, -0x3c040001, 0x24844b3c, 0xafa00014, 0x8fa60020, +0x3c040001, 0x24844b4c, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a50004, 0x8ee20110, 0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, @@ -785,7 +785,7 @@ 0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010, 0x618c0, 0x610c0, 0x571821, 0x8c63737c, 0x571021, 0xafa30010, 0x8c427380, 0x3c040001, -0x24844b48, 0xafa20014, 0x8f470214, 0x3c050003, +0x24844b58, 0xafa20014, 0x8f470214, 0x3c050003, 0xc002407, 0x34a50013, 0x8001c90, 0x3c020800, 0x97440212, 0x771021, 0xa444737e, 0x8f440214, 0x771021, 0x2e31821, 0xac447380, 0x34028000, @@ -803,7 +803,7 @@ 0x24840001, 0x2c820080, 0x1440fff8, 0x410c0, 0x4c10023, 0x618c0, 0x910c0, 0x571821, 0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, -0x3c040001, 0x24844b54, 0xafa20014, 0x8f470214, +0x3c040001, 0x24844b64, 0xafa20014, 0x8f470214, 0x3c050003, 0xc002407, 0x34a5f017, 0x8001c90, 0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, 0x8f430214, 0xb71021, 0xac437780, 0x3c020001, @@ -878,13 +878,13 @@ 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24844b60, +0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x8001da0, -0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x8001da0, 0x0, 0x3c040001, -0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, 0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, @@ -899,7 +899,7 @@ 0x1221004, 0x21027, 0x621824, 0xaf830228, 0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e, 0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, -0x571021, 0x8c42727c, 0x3c040001, 0x24844b84, +0x571021, 0x8c42727c, 0x3c040001, 0x24844b94, 0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, 0xc002407, 0x1203021, 0x8001e83, 0x3c020800, 0xb71021, 0x9443727e, 0x97420212, 0x14620019, @@ -927,7 +927,7 @@ 0x910c0, 0x2e41821, 0x3402c000, 0x15000015, 0xa462737c, 0x910c0, 0x2e21821, 0x34028000, 0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, -0x3c040001, 0x24844b90, 0x3c050003, 0xafa20010, +0x3c040001, 0x24844ba0, 0x3c050003, 0xafa20010, 0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, 0x1203021, 0xc002407, 0xafa20014, 0x8001e83, 0x3c020800, 0x2021, 0x428c0, 0xb71021, @@ -1003,12 +1003,12 @@ 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x10620022, -0x0, 0x3c040001, 0x24844b60, 0xafa00010, +0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x8001f93, 0x0, -0x3c040001, 0x24844b6c, 0xafa00014, 0x8f860120, +0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, -0x8001f93, 0x0, 0x3c040001, 0x24844b78, +0x8001f93, 0x0, 0x3c040001, 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, @@ -1020,7 +1020,7 @@ 0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228, 0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, 0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, -0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844b98, +0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844ba8, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, 0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, @@ -1031,7 +1031,7 @@ 0x370821, 0xa02283b2, 0x8001fea, 0xaee40108, 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, -0x8001fea, 0xaee40108, 0x3c040001, 0x24844ba4, +0x8001fea, 0xaee40108, 0x3c040001, 0x24844bb4, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, @@ -1043,13 +1043,13 @@ 0x571021, 0x904283b2, 0x3c010001, 0x370821, 0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 0x8002018, 0xaf820220, -0x3c040001, 0x24844bb0, 0xafa00014, 0x8fa60020, +0x3c040001, 0x24844bc0, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00b, 0x8ee20114, 0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, 0x27840208, 0x27450200, 0xc00249e, 0x24060008, 0x26e40094, 0x27450200, 0xc00249e, 0x24060008, 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, -0x8ee20134, 0x8f460248, 0x2021, 0xc004fa4, +0x8ee20134, 0x8f460248, 0x2021, 0xc004fa8, 0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, 0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, 0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, @@ -1063,7 +1063,7 @@ 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaee30108, 0x8002061, 0x2021, 0xaee40108, 0x2021, -0x3c030001, 0x641821, 0x906353e0, 0x2e41021, +0x3c030001, 0x641821, 0x906353f0, 0x2e41021, 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 0x24420030, 0xa062009c, 0x2e41021, @@ -1143,13 +1143,13 @@ 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24844b60, +0x10620022, 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x80021c4, -0x0, 0x3c040001, 0x24844b6c, 0xafa00014, +0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x80021c4, 0x0, 0x3c040001, -0x24844b78, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, @@ -1159,7 +1159,7 @@ 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, 0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, -0x24844bbc, 0xafa00010, 0xafa00014, 0x8fa60020, +0x24844bcc, 0xafa00010, 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 0x34a5f00f, 0x93a20020, 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, @@ -1190,7 +1190,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bc4, +0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bd4, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 0x80022e0, 0x0, 0x8f830120, 0x27623800, 0x24660020, @@ -1216,11 +1216,11 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, -0x0, 0x3c040001, 0x24844bcc, 0xafa00010, +0x0, 0x3c040001, 0x24844bdc, 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, -0x24844bd8, 0xafa00014, 0x8ee60608, 0x8f470228, +0x24844be8, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, 0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, @@ -1247,7 +1247,7 @@ 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, -0x8f87011c, 0x3c040001, 0x24844c8c, 0xc002407, +0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002407, 0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, 0x3c020400, 0x1062002b, 0x43102b, 0x14400008, 0x3c022000, 0x3c020100, 0x10620026, 0x3c020200, @@ -1264,7 +1264,7 @@ 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, 0xafa20014, 0x8f8600a0, -0x8f87011c, 0x3c040001, 0x24844c98, 0xc002407, +0x8f87011c, 0x3c040001, 0x24844cac, 0xc002407, 0x34a5f000, 0x8f8300a0, 0x3c027f00, 0x621824, 0x3c020400, 0x10620055, 0x8021, 0x43102b, 0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, @@ -1290,43 +1290,43 @@ 0xaee2019c, 0x80023e7, 0x8ee2019c, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x0, 0x3c020001, -0x8c425408, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26105550, 0x2002021, +0x8c425418, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26105560, 0x2002021, 0xc00248c, 0x24052000, 0x26021fe0, 0x3c010001, -0xac225524, 0x3c010001, 0xac225520, 0xaf420250, +0xac225534, 0x3c010001, 0xac225530, 0xaf420250, 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, -0x3c010001, 0xac225408, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635524, +0x3c010001, 0xac225418, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635534, 0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, -0x3c020001, 0x8c425524, 0x8c830004, 0xac430004, +0x3c020001, 0x8c425534, 0x8c830004, 0xac430004, 0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010, 0xac470014, 0xac480018, 0xac49001c, 0x3c010001, -0xac235524, 0xac44000c, 0x3c020001, 0x24425550, +0xac235534, 0xac44000c, 0x3c020001, 0x24425560, 0x62182b, 0x10600005, 0x0, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, -0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x3c020001, 0x8c425400, 0xac620000, +0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400, 0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0x27bdffd0, +0x8c635534, 0x3c020001, 0x8c425400, 0x27bdffd0, 0xafb40020, 0x8fb40040, 0xafb00010, 0x808021, 0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, 0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, -0xac620000, 0x3c050001, 0x8ca55524, 0x3c020001, -0x8c4253f0, 0xc09021, 0xe09821, 0x10800006, +0xac620000, 0x3c050001, 0x8ca55534, 0x3c020001, +0x8c425400, 0xc09021, 0xe09821, 0x10800006, 0xaca20004, 0x24a50008, 0xc002494, 0x24060018, 0x8002452, 0x0, 0x24a40008, 0xc00248c, -0x24050018, 0x3c020001, 0x8c425524, 0x3c050001, -0x24a55550, 0x2442ffe0, 0x3c010001, 0xac225524, +0x24050018, 0x3c020001, 0x8c425534, 0x3c050001, +0x24a55560, 0x2442ffe0, 0x3c010001, 0xac225534, 0x45102b, 0x10400005, 0x0, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x8e020000, 0xac620000, 0x3c030001, -0x8c635524, 0x8e020004, 0xac620004, 0xac710008, -0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225524, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x8e020000, 0xac620000, 0x3c030001, +0x8c635534, 0x8e020004, 0xac620004, 0xac710008, +0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225534, 0x45102b, 0xac720010, 0xac730014, 0xac740018, 0xac75001c, 0x10400005, 0xac64000c, 0x3c020001, -0x8c425520, 0x3c010001, 0xac225524, 0x3c030001, -0x8c635524, 0x3c020001, 0x8c4253f0, 0xac620000, -0x3c030001, 0x8c635524, 0x3c020001, 0x8c4253f0, +0x8c425530, 0x3c010001, 0xac225534, 0x3c030001, +0x8c635534, 0x3c020001, 0x8c425400, 0xac620000, +0x3c030001, 0x8c635534, 0x3c020001, 0x8c425400, 0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005, @@ -1372,7 +1372,7 @@ 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f114, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, 0x24480010, 0x3641021, @@ -1401,7 +1401,7 @@ 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24844f00, 0x3c050004, 0xafa20014, 0x8ee604e4, +0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f125, 0x34028100, 0xa5020000, 0x9582000e, 0x8002621, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, @@ -1428,7 +1428,7 @@ 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, -0x3c040001, 0x24844f00, 0x3c050004, 0xafa20014, +0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, 0x8ee37264, 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 0x8002685, 0x24e70004, 0x8f840100, 0x27623000, @@ -1454,7 +1454,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x15200009, 0x3c050004, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f004, 0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, 0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, @@ -1474,7 +1474,7 @@ 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, 0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, -0x3c040001, 0x24844f0c, 0xafa20014, 0x8fa60018, +0x3c040001, 0x24844f1c, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050004, 0xc002407, 0x34a5f005, 0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, 0x80028d7, 0xaee0725c, 0x30430003, 0x24020002, @@ -1516,7 +1516,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f014, 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 0x43102b, 0x14400073, 0x0, 0x8ee27264, @@ -1545,7 +1545,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24844f00, 0x3c050004, +0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, 0x34028100, 0xa5020000, 0x9582000e, 0x8002863, 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, @@ -1572,7 +1572,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 0x34028100, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 0x80028c6, 0x24e70004, @@ -1598,7 +1598,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, -0x24844f18, 0xafab0010, 0xafa00014, 0x8ee604e4, +0x24844f28, 0xafab0010, 0xafa00014, 0x8ee604e4, 0x34a5f017, 0xc002407, 0x30e7ffff, 0x80028e5, 0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, 0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, @@ -1664,7 +1664,7 @@ 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000a, 0x24020001, -0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f00, +0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a53, 0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, 0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, @@ -1698,7 +1698,7 @@ 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, -0x24844f18, 0x3c050004, 0xafa90010, 0xafa00014, +0x24844f28, 0x3c050004, 0xafa90010, 0xafa00014, 0x8ee604e4, 0x34a5f237, 0xc002407, 0x30e7ffff, 0x8002a76, 0x0, 0x8ee27264, 0x451021, 0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, @@ -1722,7 +1722,7 @@ 0x8f830108, 0x21140, 0x621821, 0xaf830108, 0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013, 0x104000c1, 0x31080, 0x3c010001, 0x220821, -0x8c224f40, 0x400008, 0x0, 0x8ee204f0, +0x8c224f50, 0x400008, 0x0, 0x8ee204f0, 0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c, 0x43102b, 0x144000be, 0x0, 0x8ee304e4, 0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120, @@ -1749,7 +1749,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f006, 0x16000003, 0x24020001, 0x8002b75, 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, @@ -1770,7 +1770,7 @@ 0x8002b75, 0xaee20000, 0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, 0x8002b75, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, -0x3c040001, 0x24844f30, 0xafa60014, 0xafa20010, +0x3c040001, 0x24844f40, 0xafa60014, 0xafa20010, 0x8cc60018, 0x3c050008, 0xc002407, 0x34a50910, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, @@ -1779,7 +1779,7 @@ 0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001, 0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018, 0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf, -0x31080, 0x3c010001, 0x220821, 0x8c224f90, +0x31080, 0x3c010001, 0x220821, 0x8c224fa0, 0x400008, 0x0, 0x9663000e, 0x8ee2725c, 0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c, 0x96e20458, 0x24840001, 0xaee404f0, 0x24630001, @@ -1808,7 +1808,7 @@ 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24844f24, 0xafa00014, 0xafa20010, +0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, 0x1200030a, 0x240c0001, 0x8002f1d, 0x0, 0x966c001c, @@ -2002,7 +2002,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, -0x8ee204e4, 0x3c040001, 0x24844f24, 0xafa00014, +0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, 0x16000003, 0x240c0001, 0x8002f60, 0xa2ec04f4, @@ -2057,7 +2057,7 @@ 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, -0x3c040001, 0x24845040, 0xafa20014, 0x8f8600e0, +0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, 0x80034d0, 0x0, 0x8fa3001c, 0x8fb20018, 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, @@ -2155,11 +2155,11 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f003, 0x80034d0, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 0x431024, 0x8003474, 0xaee20000, @@ -2211,7 +2211,7 @@ 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, -0x3c050006, 0x8e020018, 0x3c040001, 0x24845060, +0x3c050006, 0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 0xc002407, 0xafa30014, 0x93a20037, 0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, @@ -2244,7 +2244,7 @@ 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 0x8ee6724c, 0x800343f, 0x34a5f00b, 0x3c010001, 0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, 0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, @@ -2276,7 +2276,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, -0x8ee2724c, 0x3c040001, 0x24845078, 0xafa00014, +0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, 0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, @@ -2303,7 +2303,7 @@ 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, -0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, 0x8ee20174, 0x24420001, 0xaee20174, 0x8ee20174, 0x8003472, @@ -2333,7 +2333,7 @@ 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 0xac9e0004, 0x1620001d, 0x0, 0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484506c, 0x3c050006, 0xafa20014, +0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 0x8ee6724c, 0x34a5f00d, 0xc002407, 0x2003821, 0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, @@ -2395,7 +2395,7 @@ 0x10430007, 0x4821, 0x8f8200e4, 0x24090001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24845040, 0xafa20014, +0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, 0x8003854, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, @@ -2493,15 +2493,15 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845048, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f003, 0x8003854, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845054, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 0x431024, 0x80037fc, 0xaee20000, 0x8ee25240, -0xafa20010, 0x8ee25244, 0x3c040001, 0x24845054, +0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x80037fc, 0x8ee201c0, 0x96e20468, @@ -2560,7 +2560,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x15200018, 0x3c050006, -0x8e020018, 0x3c040001, 0x24845060, 0xafa20010, +0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 0xc002407, 0xafa30014, 0x32c200ff, 0x1040002b, 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, @@ -2620,7 +2620,7 @@ 0x10430007, 0x3821, 0x8f8200e4, 0x24070001, 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24845084, 0xafa20014, +0x8f8200c8, 0x3c040001, 0x24845094, 0xafa20014, 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f200, 0x8003c5f, 0x0, 0x8fa3001c, 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, @@ -2718,11 +2718,11 @@ 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845090, +0xafa20010, 0x8f8200e4, 0x3c040001, 0x248450a0, 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 0xc002407, 0x34a5f203, 0x8003c5f, 0x0, 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x2484509c, 0xafa20014, 0x8ee60e10, 0x8ee70e18, +0x248450ac, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 0xc002407, 0x34a5f202, 0x8ee201c0, 0x24420001, 0xaee201c0, 0x8003c06, 0x8ee201c0, 0x96e20468, 0x53102b, 0x54400001, 0x3c168000, @@ -2818,7 +2818,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x14e00019, 0x3c050006, 0x3c040001, 0x24845060, +0x14e00019, 0x3c050006, 0x3c040001, 0x24845070, 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, 0x8e230004, 0x2203021, 0x1603821, 0xc002407, 0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, @@ -2882,7 +2882,7 @@ 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, 0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, -0x248450a4, 0xc002407, 0x34a5f001, 0x8003ce1, +0x248450b4, 0xc002407, 0x34a5f001, 0x8003ce1, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 0x571021, 0xac490508, @@ -2914,7 +2914,7 @@ 0x24020003, 0xac620000, 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, 0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, -0x8ee75240, 0x3c040001, 0x248450b0, 0xc002407, +0x8ee75240, 0x3c040001, 0x248450c0, 0xc002407, 0x34a5f010, 0x8003d63, 0x0, 0x8ee20500, 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, @@ -2934,7 +2934,7 @@ 0x8f830128, 0x21140, 0x621821, 0xaf830128, 0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012, 0x10400008, 0x31080, 0x3c010001, 0x220821, -0x8c2250c0, 0x400008, 0x0, 0x24020001, +0x8c2250d0, 0x400008, 0x0, 0x24020001, 0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128, @@ -2943,7 +2943,7 @@ 0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020, 0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe, 0x2c620012, 0x1040029c, 0x31080, 0x3c010001, -0x220821, 0x8c225118, 0x400008, 0x0, +0x220821, 0x8c225128, 0x400008, 0x0, 0x8f420218, 0x30420100, 0x10400007, 0x0, 0x95830016, 0x95820018, 0x621823, 0x31402, 0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, @@ -3044,7 +3044,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 0xac820004, 0x1600000d, 0x0, -0x8f820120, 0x3c040001, 0x24845108, 0xafa00014, +0x8f820120, 0x3c040001, 0x24845118, 0xafa00014, 0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, 0xc002407, 0x34a50001, 0x800405b, 0x0, 0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, @@ -3079,7 +3079,7 @@ 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, -0x3c040001, 0x24845078, 0xafa00014, 0xafa20010, +0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, 0x24420001, 0xaee20188, 0x8004054, 0x8ee20188, @@ -3105,7 +3105,7 @@ 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 0xac820004, 0x1600000b, -0x0, 0x8ee2724c, 0x3c040001, 0x24845078, +0x0, 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 0x8ee20174, 0x24420001, 0xaee20174, 0x800405b, 0x8ee20174, @@ -3117,16 +3117,16 @@ 0xc00249e, 0xafb00010, 0x2021, 0x24100001, 0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, -0x3c010001, 0xac235474, 0x3c010001, 0xac235478, -0x3c010001, 0xac20552c, 0x3c010001, 0xac225470, -0x3c010001, 0xac235478, 0xc004fa4, 0x24050004, +0x3c010001, 0xac235484, 0x3c010001, 0xac235488, +0x3c010001, 0xac20553c, 0x3c010001, 0xac225480, +0x3c010001, 0xac235488, 0xc004fa8, 0x24050004, 0xc004784, 0x0, 0x8ee20000, 0x3c03feff, 0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, 0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, -0x248451c0, 0xc002407, 0x3821, 0x8ee20280, +0x248451d0, 0xc002407, 0x3821, 0x8ee20280, 0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, @@ -3138,16 +3138,16 @@ 0xaee20218, 0x8ee20218, 0x80040ca, 0x3c03fdff, 0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, -0x8ee20000, 0x3c040001, 0x248451cc, 0x3c050008, +0x8ee20000, 0x3c040001, 0x248451dc, 0x3c050008, 0x2003021, 0x431024, 0xaee20000, 0x8f820220, 0x3821, 0x3c030300, 0x481024, 0x431025, 0xaf820220, 0xafa00010, 0xc002407, 0xafa00014, 0x800429a, 0x0, 0x2111024, 0x1040001f, 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, -0x3c03fdff, 0x3c040001, 0x248451d8, 0x3c050008, +0x3c03fdff, 0x3c040001, 0x248451e8, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, 0xc002407, 0x3821, 0x3c03fdff, 0x8ee20000, -0x3463ffff, 0x2002021, 0x431024, 0xc004cf0, +0x3463ffff, 0x2002021, 0x431024, 0xc004cf4, 0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, 0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x8004299, 0x511025, 0x2021024, @@ -3218,7 +3218,7 @@ 0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, 0x10c4002a, 0x0, 0x8ee2007c, 0x24420001, 0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0, -0x3c020001, 0x8c4275b0, 0x3c030008, 0x8f8600e0, +0x3c020001, 0x8c4275c0, 0x3c030008, 0x8f8600e0, 0x431024, 0x1040001d, 0x0, 0x10c4001b, 0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080, 0x24850008, 0x27622800, 0x50a20001, 0x27651800, @@ -3254,12 +3254,12 @@ 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425488, +0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425498, 0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001, -0x248451e4, 0x3c050008, 0x24020001, 0x3c010001, +0x248451f4, 0x3c050008, 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50498, 0x3c010001, 0xac205488, -0x3c010001, 0xac22547c, 0xc002407, 0x3821, +0x8f860220, 0x34a50498, 0x3c010001, 0xac205498, +0x3c010001, 0xac22548c, 0xc002407, 0x3821, 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, 0x431024, 0x30840002, 0x1080011e, 0xaee204d0, @@ -3325,24 +3325,24 @@ 0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 0x54620003, 0xafa00010, 0x80043da, -0x0, 0x3c040001, 0x248451f0, 0xafa00014, +0x0, 0x3c040001, 0x24845200, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 0x80043da, 0x0, 0x3c040001, -0x248451fc, 0xafa00014, 0x8f860120, 0x8f870124, +0x2484520c, 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 0x80043da, -0x0, 0x3c040001, 0x24845208, 0xafa00014, +0x0, 0x3c040001, 0x24845218, 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, -0x3c020001, 0x8c425488, 0x27bdffe0, 0x1440000d, -0xafbf0018, 0x3c040001, 0x24845214, 0x3c050008, +0x3c020001, 0x8c425498, 0x27bdffe0, 0x1440000d, +0xafbf0018, 0x3c040001, 0x24845224, 0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, -0x24020001, 0x3c010001, 0xac225488, 0xc002407, +0x24020001, 0x3c010001, 0xac225498, 0xc002407, 0x3821, 0x8ee204d0, 0x3c030001, 0x771821, 0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420008, 0xaf820220, 0x2021, 0xc0050af, +0x34420008, 0xaf820220, 0x2021, 0xc0050b3, 0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -3359,7 +3359,7 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c120001, -0x26521200, 0x3c140001, 0x8e945400, 0x3c100001, +0x26521200, 0x3c140001, 0x8e945410, 0x3c100001, 0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, 0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, 0x0, 0xd, 0x0, 0x0, @@ -3420,100 +3420,100 @@ 0x1062000c, 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x8004539, 0x0, 0x10620004, 0x24020800, 0x8004539, -0x0, 0x24020700, 0x3c010001, 0xac22548c, +0x0, 0x24020700, 0x3c010001, 0xac22549c, 0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028, -0x3c010001, 0xc004ccd, 0xac205474, 0x24040001, -0x2821, 0x27a60020, 0x34028000, 0xc0048ea, +0x3c010001, 0xc004cd1, 0xac205484, 0x24040001, +0x2821, 0x27a60020, 0x34028000, 0xc0048ee, 0xa7a20020, 0x8f830054, 0x8f820054, 0x800454b, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004557, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050001, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60020, 0x8f830054, 0x8f820054, 0x8004563, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050002, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050002, 0xc0048ac, 0x27a60018, 0x8f830054, 0x8f820054, 0x800456f, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050003, 0xc0048a8, +0x1440fffc, 0x24040001, 0x24050003, 0xc0048ac, 0x27a6001a, 0x97a20020, 0x10400027, 0x24030001, -0x3c020001, 0x8c425474, 0x97a30018, 0x34420001, -0x3c010001, 0xac225474, 0x24020015, 0x1462000d, +0x3c020001, 0x8c425484, 0x97a30018, 0x34420001, +0x3c010001, 0xac225484, 0x24020015, 0x1462000d, 0x0, 0x97a2001a, 0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, 0x621825, 0x10600005, -0x24020003, 0x3c010001, 0xac225540, 0x80045a7, +0x24020003, 0x3c010001, 0xac225550, 0x80045a7, 0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, 0x24020002, 0x97a3001a, 0x24020001, 0x14620006, -0x24020002, 0x24020004, 0x3c010001, 0xac225540, -0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225540, -0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425474, -0x3c010001, 0xac235540, 0x34420004, 0x3c010001, -0xac225474, 0x3c08fff0, 0x3508bdc0, 0x8f830054, -0x97a60018, 0x3c070001, 0x8ce75540, 0x3c040001, -0x24845280, 0x24020001, 0x3c010001, 0xac22547c, -0xafa60010, 0x3c060001, 0x8cc65474, 0x97a2001a, -0x3c05000d, 0x34a50100, 0x3c010001, 0xac205478, -0x681821, 0x3c010001, 0xac235538, 0xc002407, +0x24020002, 0x24020004, 0x3c010001, 0xac225550, +0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225550, +0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425484, +0x3c010001, 0xac235550, 0x34420004, 0x3c010001, +0xac225484, 0x3c08fff0, 0x3508bdc0, 0x8f830054, +0x97a60018, 0x3c070001, 0x8ce75550, 0x3c040001, +0x24845290, 0x24020001, 0x3c010001, 0xac22548c, +0xafa60010, 0x3c060001, 0x8cc65484, 0x97a2001a, +0x3c05000d, 0x34a50100, 0x3c010001, 0xac205488, +0x681821, 0x3c010001, 0xac235548, 0xc002407, 0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, -0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845478, +0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845488, 0x3021, 0x24020001, 0x1482000a, 0xafbf0010, -0x3c020001, 0x8c4275bc, 0x3c050004, 0x30428000, +0x3c020001, 0x8c4275cc, 0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, 0x80045da, -0x34a54240, 0x3c020001, 0x8c4275bc, 0x3c05000f, +0x34a54240, 0x3c020001, 0x8c4275cc, 0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, -0x34a58480, 0x3c020001, 0x8c425538, 0x8f830054, +0x34a58480, 0x3c020001, 0x8c425548, 0x8f830054, 0x451021, 0x431023, 0x45102b, 0x1440002e, -0x0, 0x3c020001, 0x8c425480, 0x1440002a, +0x0, 0x3c020001, 0x8c425490, 0x1440002a, 0x2cc20001, 0x7182b, 0x431024, 0x1040001d, -0x0, 0x3c090001, 0x8d295474, 0x240b0001, -0x3c054000, 0x3c080001, 0x250875bc, 0x250afffc, +0x0, 0x3c090001, 0x8d295484, 0x240b0001, +0x3c054000, 0x3c080001, 0x250875cc, 0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 0x80045ff, 0x451024, 0x8d420000, 0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, -0x42042, 0x3c010001, 0x10c00024, 0xac245478, -0x8f830054, 0x24020001, 0x3c010001, 0xac22547c, -0x3c010001, 0xac235538, 0x3c020001, 0x8c42547c, -0x10400006, 0x24020001, 0x3c010001, 0xac20547c, +0x42042, 0x3c010001, 0x10c00024, 0xac245488, +0x8f830054, 0x24020001, 0x3c010001, 0xac22548c, +0x3c010001, 0xac235548, 0x3c020001, 0x8c42548c, +0x10400006, 0x24020001, 0x3c010001, 0xac20548c, 0x3c010001, 0x370821, 0xac2283ac, 0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, 0x10620005, 0x24020001, 0xc00462f, 0x0, 0x800462c, -0x0, 0x3c030001, 0x8c635478, 0x10620007, -0x2402000e, 0x3c030001, 0x8c637550, 0x10620003, -0x0, 0xc004cf0, 0x8f840220, 0x8fbf0010, +0x0, 0x3c030001, 0x8c635488, 0x10620007, +0x2402000e, 0x3c030001, 0x8c637560, 0x10620003, +0x0, 0xc004cf4, 0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, -0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55478, -0x3c040001, 0x8c845498, 0x3442ffff, 0x621824, +0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55488, +0x3c040001, 0x8c8454a8, 0x3442ffff, 0x621824, 0x14a40008, 0xaee30000, 0x3c030001, 0x771821, -0x8c6383ac, 0x3c020001, 0x8c42549c, 0x10620008, +0x8c6383ac, 0x3c020001, 0x8c4254ac, 0x10620008, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, -0x3c010001, 0xac255498, 0x3c010001, 0xac22549c, -0x3c030001, 0x8c635478, 0x24020002, 0x10620131, +0x3c010001, 0xac2554a8, 0x3c010001, 0xac2254ac, +0x3c030001, 0x8c635488, 0x24020002, 0x10620131, 0x2c620003, 0x10400005, 0x24020001, 0x10620008, 0x0, 0x800477e, 0x0, 0x24020004, 0x10620079, 0x24020001, 0x800477f, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, 0x10400122, 0x31080, 0x3c010001, -0x220821, 0x8c225298, 0x400008, 0x0, -0xc004784, 0x0, 0x3c020001, 0x8c425484, -0x3c010001, 0xac205410, 0x104000bd, 0x24020002, +0x220821, 0x8c2252a8, 0x400008, 0x0, +0xc004784, 0x0, 0x3c020001, 0x8c425494, +0x3c010001, 0xac205420, 0x104000bd, 0x24020002, 0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, -0x8004781, 0xac205484, 0xc00492b, 0x0, -0x3c030001, 0x8c6354a0, 0x80046f0, 0x24020011, -0x3c050001, 0x8ca55478, 0x3c060001, 0x8cc675bc, -0xc004fa4, 0x2021, 0x24020005, 0x3c010001, -0xac205484, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c040001, 0x2484528c, 0x3c05000f, +0x8004781, 0xac205494, 0xc00492f, 0x0, +0x3c030001, 0x8c6354b0, 0x80046f0, 0x24020011, +0x3c050001, 0x8ca55488, 0x3c060001, 0x8cc675cc, +0xc004fa8, 0x2021, 0x24020005, 0x3c010001, +0xac205494, 0x3c010001, 0x370821, 0x8004781, +0xac2283ac, 0x3c040001, 0x2484529c, 0x3c05000f, 0x34a50100, 0x3021, 0x3821, 0xafa00010, 0xc002407, 0xafa00014, 0x8004781, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0x8004719, 0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 0x14400090, 0x24020007, 0x8f830054, 0x3c020001, -0x8c425530, 0x2463d8f0, 0x431023, 0x2c422710, +0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000df, 0x24020001, 0x800477f, 0x0, -0x3c050001, 0x8ca55478, 0xc0050af, 0x2021, -0xc00517a, 0x2021, 0x3c030001, 0x8c6375b4, +0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, +0xc00517e, 0x2021, 0x3c030001, 0x8c6375c4, 0x46100d1, 0x24020001, 0x3c020008, 0x621024, 0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 0x431024, 0x80046bc, 0x3442251f, 0x8f820214, @@ -3524,69 +3524,69 @@ 0x3c010001, 0x370821, 0xc0043e1, 0xac2283ac, 0x8004781, 0x0, 0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, 0x104000ac, -0x31080, 0x3c010001, 0x220821, 0x8c2252b8, +0x31080, 0x3c010001, 0x220821, 0x8c2252c8, 0x400008, 0x0, 0xc00429f, 0x0, -0x3c010001, 0xac20547c, 0xaf800204, 0x3c010001, -0xc004784, 0xac2075a0, 0x24020001, 0x3c010001, -0xac225490, 0x24020002, 0x3c010001, 0x370821, +0x3c010001, 0xac20548c, 0xaf800204, 0x3c010001, +0xc004784, 0xac2075b0, 0x24020001, 0x3c010001, +0xac2254a0, 0x24020002, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0xc004801, 0x0, -0x3c030001, 0x8c635490, 0x24020009, 0x14620090, +0x3c030001, 0x8c6354a0, 0x24020009, 0x14620090, 0x24020003, 0x3c010001, 0x370821, 0x8004781, -0xac2283ac, 0x3c020001, 0x8c4275b8, 0x30424000, +0xac2283ac, 0x3c020001, 0x8c4275c8, 0x30424000, 0x10400005, 0x0, 0x8f820044, 0x3c03ffff, 0x8004701, 0x34637fff, 0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044, 0x8f830054, 0x800471b, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425530, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400074, 0x24020005, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac2075a0, +0xaf820220, 0xaf800204, 0x3c010001, 0xac2075b0, 0x8f830054, 0x24020006, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0x8004781, 0xac235530, -0x8f830054, 0x3c020001, 0x8c425530, 0x2463fff6, +0xac2283ac, 0x3c010001, 0x8004781, 0xac235540, +0x8f830054, 0x3c020001, 0x8c425540, 0x2463fff6, 0x431023, 0x2c42000a, 0x14400059, 0x0, 0x24020007, 0x3c010001, 0x370821, 0x8004781, 0xac2283ac, 0x8f820220, 0x3c04f700, 0x441025, 0xaf820220, 0x8f820220, 0x3c030300, 0x431024, 0x14400005, 0x1821, 0x8f820220, 0x24030001, 0x441025, 0xaf820220, 0x10600043, 0x24020001, -0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845528, +0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845538, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x3c010001, 0x370821, 0x1080000b, 0xac2283ac, -0x3c020001, 0x8c425504, 0x14400007, 0x24020001, -0x3c010001, 0xac227550, 0xc004cf0, 0x8f840220, +0x3c020001, 0x8c425514, 0x14400007, 0x24020001, +0x3c010001, 0xac227560, 0xc004cf4, 0x8f840220, 0x800476e, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x14400017, 0x2402000e, 0x3c010001, -0xac227550, 0x8ee20000, 0x2021, 0x3c030200, -0x431025, 0xc00517a, 0xaee20000, 0x8f820220, +0xac227560, 0x8ee20000, 0x2021, 0x3c030200, +0x431025, 0xc00517e, 0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xc0043e1, 0xaf820220, 0x3c050001, -0x8ca55478, 0xc0050af, 0x2021, 0x8004781, -0x0, 0x3c020001, 0x8c425504, 0x10400010, -0x0, 0x3c020001, 0x8c425500, 0x2442ffff, -0x3c010001, 0xac225500, 0x14400009, 0x24020002, -0x3c010001, 0xac205504, 0x3c010001, 0x8004781, -0xac225500, 0x24020001, 0x3c010001, 0xac22547c, +0x8ca55488, 0xc0050b3, 0x2021, 0x8004781, +0x0, 0x3c020001, 0x8c425514, 0x10400010, +0x0, 0x3c020001, 0x8c425510, 0x2442ffff, +0x3c010001, 0xac225510, 0x14400009, 0x24020002, +0x3c010001, 0xac205514, 0x3c010001, 0x8004781, +0xac225510, 0x24020001, 0x3c010001, 0xac22548c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c060001, 0x8cc65478, 0x34420004, +0x8f820200, 0x3c060001, 0x8cc65488, 0x34420004, 0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001, 0x10c20008, 0x0, 0x80047ca, 0x0, 0x24020004, 0x10c20013, 0x24020001, 0x80047ca, 0x0, 0x3c030001, -0x8c635468, 0x3c020001, 0x8c425470, 0x3c040001, -0x8c84548c, 0x3c050001, 0x8ca5546c, 0xaf860200, +0x8c635478, 0x3c020001, 0x8c425480, 0x3c040001, +0x8c84549c, 0x3c050001, 0x8ca5547c, 0xaf860200, 0xaf860220, 0x34630022, 0x441025, 0x451025, 0x34420002, 0x80047c9, 0xaf830200, 0x3c030001, -0x8c635528, 0xaf820200, 0x10600009, 0xaf820220, -0x3c020001, 0x8c425504, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c425460, 0x80047bd, 0x346300e0, -0x3c020001, 0x8c425460, 0x3c033f00, 0x346300e2, -0x431025, 0xaf820200, 0x3c030001, 0x8c635464, -0x3c04f700, 0x3c020001, 0x8c425470, 0x3c050001, -0x8ca5548c, 0x641825, 0x431025, 0x451025, +0x8c635538, 0xaf820200, 0x10600009, 0xaf820220, +0x3c020001, 0x8c425514, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c425470, 0x80047bd, 0x346300e0, +0x3c020001, 0x8c425470, 0x3c033f00, 0x346300e2, +0x431025, 0xaf820200, 0x3c030001, 0x8c635474, +0x3c04f700, 0x3c020001, 0x8c425480, 0x3c050001, +0x8ca5549c, 0x641825, 0x431025, 0x451025, 0xaf820220, 0x3e00008, 0x0, 0x8f820220, -0x3c030001, 0x8c635478, 0x34420004, 0xaf820220, +0x3c030001, 0x8c635488, 0x34420004, 0xaf820220, 0x24020001, 0x1062000f, 0x0, 0x8f830054, 0x8f820054, 0x24630002, 0x621023, 0x2c420003, 0x10400011, 0x0, 0x8f820054, 0x621023, @@ -3599,19 +3599,19 @@ 0x2c420033, 0x10400004, 0x0, 0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, 0x431024, 0xaf820220, 0x3e00008, 0x0, -0x3c030001, 0x8c635490, 0x3c020001, 0x8c425494, -0x50620004, 0x2463ffff, 0x3c010001, 0xac235494, -0x2463ffff, 0x2c620009, 0x10400099, 0x31080, -0x3c010001, 0x220821, 0x8c2252d8, 0x400008, +0x3c030001, 0x8c6354a0, 0x3c020001, 0x8c4254a4, +0x50620004, 0x2463ffff, 0x3c010001, 0xac2354a4, +0x2463ffff, 0x2c620009, 0x1040009d, 0x31080, +0x3c010001, 0x220821, 0x8c2252e8, 0x400008, 0x0, 0x8f820044, 0x34428080, 0xaf820044, -0x8f830054, 0x8004896, 0x24020002, 0x8f830054, -0x3c020001, 0x8c425534, 0x2463d8f0, 0x431023, -0x2c422710, 0x14400086, 0x24020003, 0x80048a3, +0x8f830054, 0x800489a, 0x24020002, 0x8f830054, +0x3c020001, 0x8c425544, 0x2463d8f0, 0x431023, +0x2c422710, 0x1440008a, 0x24020003, 0x80048a7, 0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, -0x431024, 0xaf820044, 0x8f830054, 0x8004896, -0x24020004, 0x8f830054, 0x3c020001, 0x8c425534, -0x2463fff6, 0x431023, 0x2c42000a, 0x14400074, -0x24020005, 0x80048a3, 0x0, 0x8f820220, +0x431024, 0xaf820044, 0x8f830054, 0x800489a, +0x24020004, 0x8f830054, 0x3c020001, 0x8c425544, +0x2463fff6, 0x431023, 0x2c42000a, 0x14400078, +0x24020005, 0x80048a7, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, @@ -3629,529 +3629,530 @@ 0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008, 0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, -0x24425420, 0xac820000, 0xac830004, 0xaf8500f0, -0x8f830054, 0x8004896, 0x24020006, 0x8f830054, -0x3c020001, 0x8c425534, 0x2463fff6, 0x431023, -0x2c42000a, 0x1440001e, 0x24020007, 0x80048a3, +0x24425430, 0xac820000, 0xac830004, 0xaf8500f0, +0x8f830054, 0x800489a, 0x24020006, 0x8f830054, +0x3c020001, 0x8c425544, 0x2463fff6, 0x431023, +0x2c42000a, 0x14400022, 0x24020007, 0x80048a7, 0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, +0x8f820220, 0x2403fff7, 0x431024, 0xaf820220, 0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, -0x24020008, 0x3c010001, 0xac225490, 0x3c010001, -0x80048a5, 0xac235534, 0x8f830054, 0x3c020001, -0x8c425534, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020009, 0x3c010001, 0xac225490, +0x24020008, 0x3c010001, 0xac2254a0, 0x3c010001, +0x80048a9, 0xac235544, 0x8f830054, 0x3c020001, +0x8c425544, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020009, 0x3c010001, 0xac2254a0, 0x3e00008, 0x0, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc004ca7, 0x24040001, +0xafbf0020, 0xa6200000, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004ca7, 0x2021, 0xc004ca7, 0x24040001, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x2021, 0xc004cab, 0x24040001, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fffa, +0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fffa, 0x2701024, 0xc004ccd, 0x34108000, -0xc004ccd, 0x0, 0xc004c87, 0x0, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fffa, 0x2701024, 0xc004cd1, 0x34108000, +0xc004cd1, 0x0, 0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004ccd, 0x0, 0x8fbf0020, 0x8fb3001c, +0xc004cd1, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc004ca7, +0xafb00010, 0x8021, 0xafbf0020, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x2501024, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x2501024, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8fbf0020, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354a0, -0x3c020001, 0x8c4254e4, 0x27bdffd8, 0xafbf0020, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c6354b0, +0x3c020001, 0x8c4254f4, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac2354e4, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c225300, -0x400008, 0x0, 0xc004ccd, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc004ca7, +0xac2354f4, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c225310, +0x400008, 0x0, 0xc004cd1, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc004ca7, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc004cab, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8004c80, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc004ca7, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004ca7, -0x2021, 0xc004ca7, 0x24040001, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x24100010, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8004c84, 0x24020002, 0x27b10010, 0xa7a00010, +0x8021, 0xc004cab, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc004cab, +0x2021, 0xc004cab, 0x24040001, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004ca7, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc004ccd, 0x34108000, -0xc004ccd, 0x0, 0xc004c87, 0x0, +0xc004cab, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc004cab, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc004cd1, 0x34108000, +0xc004cd1, 0x0, 0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004ccd, 0x0, 0x97a20010, 0x30428000, -0x144002dc, 0x24020003, 0x8004c80, 0x0, +0xc004cd1, 0x0, 0x97a20010, 0x30428000, +0x144002dc, 0x24020003, 0x8004c84, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc004ca7, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc004ca7, 0x24040001, 0xc004ca7, +0xc004cab, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fff8, 0x0, 0xc004ccd, -0x0, 0x8f830054, 0x8004c72, 0x24020004, -0x8f830054, 0x3c020001, 0x8c42553c, 0x2463ff9c, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fff8, 0x0, 0xc004cd1, +0x0, 0x8f830054, 0x8004c76, 0x24020004, +0x8f830054, 0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c635540, 0x10620297, 0x2c620003, +0x3c030001, 0x8c635550, 0x10620297, 0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, -0x24020004, 0x10620291, 0x2402000f, 0x8004c80, -0x24020011, 0x8004c80, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x24020004, 0x10620291, 0x2402000f, 0x8004c84, +0x24020011, 0x8004c84, 0x24020005, 0x24020014, +0xa7a20010, 0x27b10010, 0x8021, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x32020012, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x32020012, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8f830054, -0x8004c72, 0x24020006, 0x8f830054, 0x3c020001, -0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400250, 0x24020007, 0x8004c80, 0x0, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8f830054, +0x8004c76, 0x24020006, 0x8f830054, 0x3c020001, +0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, +0x14400250, 0x24020007, 0x8004c84, 0x0, 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020013, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020013, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x24020008, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440020f, 0x24020009, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x24020008, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440020f, 0x24020009, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440019b, 0x2402000b, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000a, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x1440019b, 0x2402000b, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020017, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020017, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020017, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400127, 0x24020012, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000c, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x14400127, 0x24020012, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020014, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020014, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020014, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x24020013, 0x8f830054, -0x3c020001, 0x8c42553c, 0x2463ff9c, 0x431023, -0x2c420064, 0x144000b3, 0x2402000d, 0x8004c80, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x24020013, 0x8f830054, +0x3c020001, 0x8c42554c, 0x2463ff9c, 0x431023, +0x2c420064, 0x144000b3, 0x2402000d, 0x8004c84, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x24040001, -0xc004ca7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x24040001, +0xc004cab, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ccd, 0x34108000, 0xc004ccd, 0x0, -0xc004c87, 0x0, 0x50400005, 0x108042, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cd1, 0x34108000, 0xc004cd1, 0x0, +0xc004c8b, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004ccd, 0x8021, +0x1600fff7, 0x0, 0xc004cd1, 0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc004ca7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, -0xc004ca7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, +0xc004cab, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, +0xc004cab, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004ca7, 0x108042, 0x1600fffa, 0x32020018, -0xc004ca7, 0x24040001, 0xc004ca7, 0x2021, +0xc004cab, 0x108042, 0x1600fffa, 0x32020018, +0xc004cab, 0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, -0x1600fff8, 0x0, 0xc004ccd, 0x0, -0x8f830054, 0x8004c72, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc004ca7, +0x2021, 0x24040001, 0xc004cab, 0x108042, +0x1600fff8, 0x0, 0xc004cd1, 0x0, +0x8f830054, 0x8004c76, 0x2402000e, 0x24020840, +0xa7a20010, 0x27b10010, 0x8021, 0xc004cab, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004ca7, 0x2021, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0xc004ca7, +0x0, 0xc004cab, 0x2021, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0xc004cab, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004ca7, 0x108042, +0x2021, 0x24040001, 0xc004cab, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc004ca7, -0x108042, 0x1600fffa, 0x32020013, 0xc004ca7, -0x24040001, 0xc004ca7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc004cab, +0x108042, 0x1600fffa, 0x32020013, 0xc004cab, +0x24040001, 0xc004cab, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004ca7, 0x108042, 0x1600fff8, -0x0, 0xc004ccd, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac2254a0, 0x3c010001, -0x8004c82, 0xac23553c, 0x8f830054, 0x3c020001, -0x8c42553c, 0x2463ff9c, 0x431023, 0x2c420064, +0x24040001, 0xc004cab, 0x108042, 0x1600fff8, +0x0, 0xc004cd1, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac2254b0, 0x3c010001, +0x8004c86, 0xac23554c, 0x8f830054, 0x3c020001, +0x8c42554c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac2254a0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0xac2254b0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, -0x8f840054, 0x8f820054, 0xa32824, 0x8004c93, +0x8f840054, 0x8f820054, 0xa32824, 0x8004c97, 0x24840001, 0x8f820054, 0x821023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004ca1, 0x24630001, 0x8f820054, +0x8f820054, 0x8004ca5, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, 0x3c020002, 0x822025, 0x641825, 0xaf830044, 0x8f820044, 0x3c030001, 0x431025, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004cb9, 0x24630001, 0x8f820054, +0x8f820054, 0x8004cbd, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004cc7, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004ccb, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, 0xaf820044, 0x8f820044, 0x3c030001, 0x431025, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdb, +0xaf820044, 0x8f830054, 0x8f820054, 0x8004cdf, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004ce9, 0x24630001, 0x8f820054, +0x8f820054, 0x8004ced, 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, 0x1462022c, 0x803021, 0x3c020001, -0x8c425528, 0x14400033, 0x0, 0x8f850224, +0x8c425538, 0x14400033, 0x0, 0x8f850224, 0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001, 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 0x38a20400, 0x2c420001, 0x621825, 0x14600007, 0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, 0x621825, 0x10600005, 0x0, 0xc00429f, -0x0, 0x8004d29, 0x2402000e, 0xc0043e1, -0x0, 0x3c050001, 0x8ca55478, 0xc0050af, -0x2021, 0x3c030001, 0x8c635478, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c425474, -0x8004d25, 0x2403fff7, 0x3c020001, 0x8c425474, -0x431024, 0x3c010001, 0xac225474, 0x2402000e, -0x3c010001, 0xc00429f, 0xac227550, 0x8004f23, +0x0, 0x8004d2d, 0x2402000e, 0xc0043e1, +0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, +0x2021, 0x3c030001, 0x8c635488, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484, +0x8004d29, 0x2403fff7, 0x3c020001, 0x8c425484, +0x431024, 0x3c010001, 0xac225484, 0x2402000e, +0x3c010001, 0xc00429f, 0xac227560, 0x8004f27, 0x0, 0x8f820220, 0x3c030400, 0x431024, 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, -0x8c42755c, 0xa32024, 0x431024, 0x1482000c, -0x0, 0x3c020001, 0x8c427560, 0x24420001, -0x3c010001, 0xac227560, 0x2c420002, 0x14400008, -0x24020001, 0x3c010001, 0x8004d49, 0xac227580, -0x3c010001, 0xac207560, 0x3c010001, 0xac207580, -0x3c020001, 0x8c427580, 0x10400006, 0x30a20040, -0x10400004, 0x24020001, 0x3c010001, 0x8004d54, -0xac227584, 0x3c010001, 0xac207584, 0x3c010001, -0xac25755c, 0x3c010001, 0x8004d64, 0xac207590, -0x24020001, 0x3c010001, 0xac227590, 0x3c010001, -0xac207580, 0x3c010001, 0xac207560, 0x3c010001, -0xac207584, 0x3c010001, 0xac20755c, 0x3c030001, -0x8c637550, 0x3c020001, 0x8c427554, 0x10620003, -0x3c020200, 0x3c010001, 0xac237554, 0xc21024, +0x8c42756c, 0xa32024, 0x431024, 0x1482000c, +0x0, 0x3c020001, 0x8c427570, 0x24420001, +0x3c010001, 0xac227570, 0x2c420002, 0x14400008, +0x24020001, 0x3c010001, 0x8004d4d, 0xac227590, +0x3c010001, 0xac207570, 0x3c010001, 0xac207590, +0x3c020001, 0x8c427590, 0x10400006, 0x30a20040, +0x10400004, 0x24020001, 0x3c010001, 0x8004d58, +0xac227594, 0x3c010001, 0xac207594, 0x3c010001, +0xac25756c, 0x3c010001, 0x8004d68, 0xac2075a0, +0x24020001, 0x3c010001, 0xac2275a0, 0x3c010001, +0xac207590, 0x3c010001, 0xac207570, 0x3c010001, +0xac207594, 0x3c010001, 0xac20756c, 0x3c030001, +0x8c637560, 0x3c020001, 0x8c427564, 0x10620003, +0x3c020200, 0x3c010001, 0xac237564, 0xc21024, 0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, -0x3c010001, 0xac23547c, 0x8004f21, 0x3c03f700, +0x3c010001, 0xac23548c, 0x8004f25, 0x3c03f700, 0x2c62000e, 0x104001a8, 0x31080, 0x3c010001, -0x220821, 0x8c225350, 0x400008, 0x0, -0x3c010001, 0xac207580, 0x3c010001, 0xac207560, -0x3c010001, 0xac20755c, 0x3c010001, 0xac207584, -0x3c010001, 0xac207578, 0x3c010001, 0xac207570, +0x220821, 0x8c225360, 0x400008, 0x0, +0x3c010001, 0xac207590, 0x3c010001, 0xac207570, +0x3c010001, 0xac20756c, 0x3c010001, 0xac207594, +0x3c010001, 0xac207588, 0x3c010001, 0xac207580, 0xc0047cc, 0xaf800224, 0x24020002, 0x3c010001, -0xac227550, 0x3c020001, 0x8c427590, 0x14400056, +0xac227560, 0x3c020001, 0x8c4275a0, 0x14400056, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 0xc00429f, 0xaee20000, 0xaf800204, 0x8f820200, 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, -0xac2075a0, 0x8f830054, 0x3c020001, 0x8c427578, -0x24040001, 0x3c010001, 0xac24758c, 0x24420001, -0x3c010001, 0xac227578, 0x2c420004, 0x3c010001, -0xac237574, 0x14400006, 0x24020003, 0x3c010001, -0xac24547c, 0x3c010001, 0x8004f1f, 0xac207578, -0x3c010001, 0x8004f1f, 0xac227550, 0x8f830054, -0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0xac2075b0, 0x8f830054, 0x3c020001, 0x8c427588, +0x24040001, 0x3c010001, 0xac24759c, 0x24420001, +0x3c010001, 0xac227588, 0x2c420004, 0x3c010001, +0xac237584, 0x14400006, 0x24020003, 0x3c010001, +0xac24548c, 0x3c010001, 0x8004f23, 0xac207588, +0x3c010001, 0x8004f23, 0xac227560, 0x8f830054, +0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, 0x24020004, 0x3c010001, -0xac227550, 0x3c020001, 0x8c427590, 0x14400026, +0xac227560, 0x3c020001, 0x8c4275a0, 0x14400026, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, -0x8004f1f, 0xaee20000, 0x3c040001, 0x8c84552c, -0x3c010001, 0xc004f26, 0xac207568, 0x3c020001, -0x8c42759c, 0xaf820204, 0x3c020001, 0x8c427590, +0x8004f23, 0xaee20000, 0x3c040001, 0x8c84553c, +0x3c010001, 0xc004f2a, 0xac207578, 0x3c020001, +0x8c4275ac, 0xaf820204, 0x3c020001, 0x8c4275a0, 0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 0xaee20000, 0x8f820204, 0x30420030, -0x1440013c, 0x24020002, 0x3c030001, 0x8c63759c, -0x24020005, 0x3c010001, 0xac227550, 0x3c010001, -0x8004f1f, 0xac2375a0, 0x3c020001, 0x8c427590, -0x10400010, 0x3c03fdff, 0x3c020001, 0x8c4254fc, -0x24420001, 0x3c010001, 0xac2254fc, 0x2c420002, -0x14400131, 0x24020001, 0x3c010001, 0xac225504, -0x3c010001, 0xac2054fc, 0x3c010001, 0x8004f1f, -0xac22547c, 0x8ee20000, 0x3463ffff, 0x431024, -0xaee20000, 0x3c020001, 0x8c427580, 0x10400122, -0x0, 0x3c020001, 0x8c42755c, 0x1040011e, -0x0, 0x3c010001, 0xac227588, 0x24020003, -0x3c010001, 0xac227560, 0x8004ec0, 0x24020006, -0x3c010001, 0xac207568, 0x8f820204, 0x34420040, -0xaf820204, 0x3c020001, 0x8c4275a0, 0x24030007, -0x3c010001, 0xac237550, 0x34420040, 0x3c010001, -0xac2275a0, 0x3c020001, 0x8c427580, 0x10400005, -0x0, 0x3c020001, 0x8c42755c, 0x104000f9, -0x24020002, 0x3c050001, 0x24a57560, 0x8ca20000, +0x1440013c, 0x24020002, 0x3c030001, 0x8c6375ac, +0x24020005, 0x3c010001, 0xac227560, 0x3c010001, +0x8004f23, 0xac2375b0, 0x3c020001, 0x8c4275a0, +0x10400010, 0x3c03fdff, 0x3c020001, 0x8c42550c, +0x24420001, 0x3c010001, 0xac22550c, 0x2c420002, +0x14400131, 0x24020001, 0x3c010001, 0xac225514, +0x3c010001, 0xac20550c, 0x3c010001, 0x8004f23, +0xac22548c, 0x8ee20000, 0x3463ffff, 0x431024, +0xaee20000, 0x3c020001, 0x8c427590, 0x10400122, +0x0, 0x3c020001, 0x8c42756c, 0x1040011e, +0x0, 0x3c010001, 0xac227598, 0x24020003, +0x3c010001, 0xac227570, 0x8004ec4, 0x24020006, +0x3c010001, 0xac207578, 0x8f820204, 0x34420040, +0xaf820204, 0x3c020001, 0x8c4275b0, 0x24030007, +0x3c010001, 0xac237560, 0x34420040, 0x3c010001, +0xac2275b0, 0x3c020001, 0x8c427590, 0x10400005, +0x0, 0x3c020001, 0x8c42756c, 0x104000f9, +0x24020002, 0x3c050001, 0x24a57570, 0x8ca20000, 0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001, -0x8c427584, 0x104000f8, 0x2404ffbf, 0x3c020001, -0x8c42755c, 0x3c030001, 0x8c637588, 0x441024, +0x8c427594, 0x104000f8, 0x2404ffbf, 0x3c020001, +0x8c42756c, 0x3c030001, 0x8c637598, 0x441024, 0x641824, 0x10430004, 0x24020001, 0x3c010001, -0x8004f1f, 0xac227550, 0x24020003, 0xaca20000, -0x24020008, 0x3c010001, 0xac227550, 0x3c020001, -0x8c42758c, 0x1040000c, 0x24020001, 0x3c040001, -0xc004f33, 0x8c84755c, 0x3c020001, 0x8c4275a8, -0x14400005, 0x24020001, 0x3c020001, 0x8c4275a4, -0x10400006, 0x24020001, 0x3c010001, 0xac22547c, -0x3c010001, 0x8004f1f, 0xac207578, 0x3c020001, -0x8c427570, 0x3c030001, 0x8c63755c, 0x2c420001, -0x210c0, 0x30630008, 0x3c010001, 0xac227570, -0x3c010001, 0xac23756c, 0x8f830054, 0x24020009, -0x3c010001, 0xac227550, 0x3c010001, 0x8004f1f, -0xac237574, 0x8f830054, 0x3c020001, 0x8c427574, +0x8004f23, 0xac227560, 0x24020003, 0xaca20000, +0x24020008, 0x3c010001, 0xac227560, 0x3c020001, +0x8c42759c, 0x1040000c, 0x24020001, 0x3c040001, +0xc004f37, 0x8c84756c, 0x3c020001, 0x8c4275b8, +0x14400005, 0x24020001, 0x3c020001, 0x8c4275b4, +0x10400006, 0x24020001, 0x3c010001, 0xac22548c, +0x3c010001, 0x8004f23, 0xac207588, 0x3c020001, +0x8c427580, 0x3c030001, 0x8c63756c, 0x2c420001, +0x210c0, 0x30630008, 0x3c010001, 0xac227580, +0x3c010001, 0xac23757c, 0x8f830054, 0x24020009, +0x3c010001, 0xac227560, 0x3c010001, 0x8004f23, +0xac237584, 0x8f830054, 0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8, -0x0, 0x3c020001, 0x8c427580, 0x10400005, -0x0, 0x3c020001, 0x8c42755c, 0x104000a9, -0x24020002, 0x3c030001, 0x24637560, 0x8c620000, +0x0, 0x3c020001, 0x8c427590, 0x10400005, +0x0, 0x3c020001, 0x8c42756c, 0x104000a9, +0x24020002, 0x3c030001, 0x24637570, 0x8c620000, 0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001, -0x8c42758c, 0x1040000e, 0x0, 0x3c020001, -0x8c42755c, 0x3c010001, 0xac20758c, 0x30420080, +0x8c42759c, 0x1040000e, 0x0, 0x3c020001, +0x8c42756c, 0x3c010001, 0xac20759c, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, -0x1440000c, 0x24020003, 0x8004ead, 0x2402000c, -0x3c020001, 0x8c42755c, 0x30420080, 0x14400005, +0x1440000c, 0x24020003, 0x8004eb1, 0x2402000c, +0x3c020001, 0x8c42756c, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, 0xac620000, 0x2402000a, 0x3c010001, -0xac227550, 0x3c040001, 0x24847598, 0x8c820000, -0x3c030001, 0x8c637570, 0x431025, 0xaf820204, -0x8c830000, 0x3c040001, 0x8c847570, 0x2402000b, -0x3c010001, 0xac227550, 0x641825, 0x3c010001, -0xac2375a0, 0x3c050001, 0x24a57560, 0x8ca20000, +0xac227560, 0x3c040001, 0x248475a8, 0x8c820000, +0x3c030001, 0x8c637580, 0x431025, 0xaf820204, +0x8c830000, 0x3c040001, 0x8c847580, 0x2402000b, +0x3c010001, 0xac227560, 0x641825, 0x3c010001, +0xac2375b0, 0x3c050001, 0x24a57570, 0x8ca20000, 0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001, -0x8c427590, 0x10400005, 0x0, 0x2402000c, -0x3c010001, 0x8004f1f, 0xac227550, 0x3c020001, -0x8c427580, 0x1040006c, 0x0, 0x3c040001, -0x8c84755c, 0x1080005e, 0x30820008, 0x3c030001, -0x8c63756c, 0x10620064, 0x24020003, 0x3c010001, -0xac247588, 0xaca20000, 0x24020006, 0x3c010001, -0x8004f1f, 0xac227550, 0x8f820200, 0x34420002, +0x8c4275a0, 0x10400005, 0x0, 0x2402000c, +0x3c010001, 0x8004f23, 0xac227560, 0x3c020001, +0x8c427590, 0x1040006c, 0x0, 0x3c040001, +0x8c84756c, 0x1080005e, 0x30820008, 0x3c030001, +0x8c63757c, 0x10620064, 0x24020003, 0x3c010001, +0xac247598, 0xaca20000, 0x24020006, 0x3c010001, +0x8004f23, 0xac227560, 0x8f820200, 0x34420002, 0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, -0xac227550, 0x3c010001, 0xac237574, 0x8f830054, -0x3c020001, 0x8c427574, 0x2463d8f0, 0x431023, +0xac227560, 0x3c010001, 0xac237584, 0x8f830054, +0x3c020001, 0x8c427584, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440003a, 0x0, 0x3c020001, -0x8c427590, 0x10400029, 0x2402000e, 0x3c030001, -0x8c6375a4, 0x3c010001, 0x14600015, 0xac227550, -0xc0043e1, 0x0, 0x3c050001, 0x8ca55478, -0xc0050af, 0x2021, 0x3c030001, 0x8c635478, +0x8c4275a0, 0x10400029, 0x2402000e, 0x3c030001, +0x8c6375b4, 0x3c010001, 0x14600015, 0xac227560, +0xc0043e1, 0x0, 0x3c050001, 0x8ca55488, +0xc0050b3, 0x2021, 0x3c030001, 0x8c635488, 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, -0x8c425474, 0x8004eee, 0x2403fff7, 0x3c020001, -0x8c425474, 0x431024, 0x3c010001, 0xac225474, +0x8c425484, 0x8004ef2, 0x2403fff7, 0x3c020001, +0x8c425484, 0x431024, 0x3c010001, 0xac225484, 0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, -0x8f820224, 0x3c010001, 0xac2275ac, 0x8f820220, +0x8f820224, 0x3c010001, 0xac2275bc, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0x8004f1f, 0xaf820220, 0x3c020001, -0x8c427580, 0x10400005, 0x0, 0x3c020001, -0x8c42755c, 0x1040000f, 0x24020002, 0x3c020001, -0x8c427560, 0x2c424e21, 0x1040000a, 0x24020002, -0x3c020001, 0x8c427580, 0x1040000f, 0x0, -0x3c020001, 0x8c42755c, 0x1440000b, 0x0, -0x24020002, 0x3c010001, 0x8004f1f, 0xac227550, -0x3c020001, 0x8c427580, 0x10400003, 0x0, +0x34420002, 0x8004f23, 0xaf820220, 0x3c020001, +0x8c427590, 0x10400005, 0x0, 0x3c020001, +0x8c42756c, 0x1040000f, 0x24020002, 0x3c020001, +0x8c427570, 0x2c424e21, 0x1040000a, 0x24020002, +0x3c020001, 0x8c427590, 0x1040000f, 0x0, +0x3c020001, 0x8c42756c, 0x1440000b, 0x0, +0x24020002, 0x3c010001, 0x8004f23, 0xac227560, +0x3c020001, 0x8c427590, 0x10400003, 0x0, 0xc00429f, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x3c030001, 0x246375a8, 0x8c620000, -0x10400005, 0x34422000, 0x3c010001, 0xac22759c, -0x8004f31, 0xac600000, 0x3c010001, 0xac24759c, +0x27bd0018, 0x3c030001, 0x246375b8, 0x8c620000, +0x10400005, 0x34422000, 0x3c010001, 0xac2275ac, +0x8004f35, 0xac600000, 0x3c010001, 0xac2475ac, 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, -0xafbf0018, 0x3c010001, 0xac2275a4, 0x14400067, +0xafbf0018, 0x3c010001, 0xac2275b4, 0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 0x21200, 0x3c040001, -0x8c84552c, 0x621825, 0x331c2, 0x3c030001, -0x24635508, 0x30828000, 0x21202, 0x30840001, +0x8c84553c, 0x621825, 0x331c2, 0x3c030001, +0x24635518, 0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, 0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, 0x0, 0x10600007, 0x24020002, 0x10620013, 0x24020003, 0x1062002c, 0x3c05000f, -0x8004f95, 0x0, 0x8f820200, 0x2403feff, +0x8004f99, 0x0, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 0x3c010001, -0xac2075c4, 0x3c010001, 0x8004fa0, 0xac2075cc, +0xac2075d4, 0x3c010001, 0x8004fa4, 0xac2075dc, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x24020100, 0x3c010001, 0xac2275c4, 0x3c010001, -0x8004fa0, 0xac2075cc, 0x8f820200, 0x2403feff, +0x24020100, 0x3c010001, 0xac2275d4, 0x3c010001, +0x8004fa4, 0xac2075dc, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, -0x431025, 0xaf820220, 0x3c010001, 0xac2075c4, -0x3c010001, 0x8004fa0, 0xac2375cc, 0x8f820200, +0x431025, 0xaf820220, 0x3c010001, 0xac2075d4, +0x3c010001, 0x8004fa4, 0xac2375dc, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 0x24020100, 0x3c010001, -0xac2275c4, 0x3c010001, 0x8004fa0, 0xac2375cc, -0x34a5ffff, 0x3c040001, 0x24845388, 0xafa30010, -0xc002407, 0xafa00014, 0x8004fa0, 0x0, -0x24020030, 0x3c010001, 0xac2275a8, 0x8fbf0018, +0xac2275d4, 0x3c010001, 0x8004fa4, 0xac2375dc, +0x34a5ffff, 0x3c040001, 0x24845398, 0xafa30010, +0xc002407, 0xafa00014, 0x8004fa4, 0x0, +0x24020030, 0x3c010001, 0xac2275b8, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x248453a0, -0x3c050009, 0x3c020001, 0x8c425478, 0x34a59001, +0xafb00020, 0xc08021, 0x3c040001, 0x248453b0, +0x3c050009, 0x3c020001, 0x8c425488, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, 0xa7a0001a, 0xafb00014, 0xc002407, 0xafa20010, 0x24020002, 0x126200ed, 0x2e620003, 0x10400005, -0x24020001, 0x1262000a, 0x3c02fffb, 0x80050a8, +0x24020001, 0x1262000a, 0x3c02fffb, 0x80050ac, 0x0, 0x24020004, 0x1262006d, 0x24020008, -0x1262006c, 0x3c02ffec, 0x80050a8, 0x0, +0x1262006c, 0x3c02ffec, 0x80050ac, 0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, -0x320821, 0xac3075bc, 0x3c024000, 0x2021024, +0x320821, 0xac3075cc, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, 0x101382, -0x3042000c, 0x3c030001, 0x246354a4, 0x431021, +0x3042000c, 0x3c030001, 0x246354b4, 0x431021, 0x823821, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010001, 0x320821, 0xac2275c0, -0x8004fe7, 0x3c020080, 0x3c010001, 0x320821, -0xac2075c0, 0x3c020080, 0x2021024, 0x10400006, +0x24020100, 0x3c010001, 0x320821, 0xac2275d0, +0x8004feb, 0x3c020080, 0x3c010001, 0x320821, +0xac2075d0, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x8004ff3, 0xac2275c8, 0x111140, 0x3c010001, -0x220821, 0xac2075c8, 0x94e30000, 0x32024000, +0x8004ff7, 0xac2275d8, 0x111140, 0x3c010001, +0x220821, 0xac2075d8, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, -0x34420001, 0xc0048ea, 0xa4e20002, 0x24040001, -0x2821, 0xc0048ea, 0x27a60018, 0x3c020001, -0x8c425478, 0x24110001, 0x3c010001, 0xac315484, +0x34420001, 0xc0048ee, 0xa4e20002, 0x24040001, +0x2821, 0xc0048ee, 0x27a60018, 0x3c020001, +0x8c425488, 0x24110001, 0x3c010001, 0xac315494, 0x14530004, 0x32028000, 0xc00429f, 0x0, 0x32028000, 0x10400099, 0x0, 0xc00429f, -0x0, 0x24020002, 0x3c010001, 0xac31547c, -0x3c010001, 0x80050a8, 0xac225478, 0x24040001, -0x24050004, 0x27b0001a, 0xc0048ea, 0x2003021, -0x24040001, 0x2821, 0xc0048ea, 0x2003021, -0x3c020001, 0x521021, 0x8c4275b4, 0x3c040001, -0x8c845478, 0x3c03bfff, 0x3463ffff, 0x3c010001, -0xac335484, 0x431024, 0x3c010001, 0x320821, -0x10930078, 0xac2275b4, 0x80050a8, 0x0, +0x0, 0x24020002, 0x3c010001, 0xac31548c, +0x3c010001, 0x80050ac, 0xac225488, 0x24040001, +0x24050004, 0x27b0001a, 0xc0048ee, 0x2003021, +0x24040001, 0x2821, 0xc0048ee, 0x2003021, +0x3c020001, 0x521021, 0x8c4275c4, 0x3c040001, +0x8c845488, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac335494, 0x431024, 0x3c010001, 0x320821, +0x10930078, 0xac2275c4, 0x80050ac, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, -0xac3075b8, 0x3c022000, 0x2021024, 0x10400009, -0x0, 0x3c020001, 0x8c425504, 0x14400005, -0x24020001, 0x3c010001, 0xac225528, 0x8005049, -0x3c024000, 0x3c010001, 0xac205528, 0x3c024000, +0xac3075c8, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c425514, 0x14400005, +0x24020001, 0x3c010001, 0xac225538, 0x800504d, +0x3c024000, 0x3c010001, 0xac205538, 0x3c024000, 0x2021024, 0x1440001c, 0x0, 0x3c020001, -0x8c425528, 0x10400007, 0x24022020, 0x3c010001, -0xac22552c, 0x24020001, 0x3c010001, 0x370821, +0x8c425538, 0x10400007, 0x24022020, 0x3c010001, +0xac22553c, 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 0x3c04bfff, 0x111940, 0x3c020001, -0x431021, 0x8c4275b0, 0x3c050001, 0x8ca55478, +0x431021, 0x8c4275c0, 0x3c050001, 0x8ca55488, 0x3484ffff, 0x441024, 0x3c010001, 0x230821, -0xac2275b0, 0x24020001, 0x10a20044, 0x0, -0x80050a6, 0x0, 0x3c020001, 0x8c425528, -0x1040001c, 0x24022000, 0x3c010001, 0xac22552c, +0xac2275c0, 0x24020001, 0x10a20044, 0x0, +0x80050aa, 0x0, 0x3c020001, 0x8c425538, +0x1040001c, 0x24022000, 0x3c010001, 0xac22553c, 0x3c0300a0, 0x2031024, 0x14430005, 0x111140, -0x3402a000, 0x3c010001, 0x80050a1, 0xac22552c, -0x3c030001, 0x621821, 0x8c6375b8, 0x3c020020, +0x3402a000, 0x3c010001, 0x80050a5, 0xac22553c, +0x3c030001, 0x621821, 0x8c6375c8, 0x3c020020, 0x621024, 0x10400004, 0x24022001, 0x3c010001, -0x80050a1, 0xac22552c, 0x3c020080, 0x621024, -0x1040001f, 0x3402a001, 0x3c010001, 0x80050a1, -0xac22552c, 0x3c020020, 0x2021024, 0x10400007, +0x80050a5, 0xac22553c, 0x3c020080, 0x621024, +0x1040001f, 0x3402a001, 0x3c010001, 0x80050a5, +0xac22553c, 0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, 0x3c010001, 0x230821, -0xac2275c4, 0x8005095, 0x3c020080, 0x111140, -0x3c010001, 0x220821, 0xac2075c4, 0x3c020080, +0xac2275d4, 0x8005099, 0x3c020080, 0x111140, +0x3c010001, 0x220821, 0xac2075d4, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, -0x3c010001, 0x230821, 0x80050a1, 0xac2275cc, -0x111140, 0x3c010001, 0x220821, 0xac2075cc, -0x3c030001, 0x8c635478, 0x24020001, 0x10620003, +0x3c010001, 0x230821, 0x80050a5, 0xac2275dc, +0x111140, 0x3c010001, 0x220821, 0xac2075dc, +0x3c030001, 0x8c635488, 0x24020001, 0x10620003, 0x0, 0xc00429f, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028, @@ -4159,124 +4160,124 @@ 0x9821, 0xafb1001c, 0x8821, 0x24020002, 0xafbf002c, 0xafb00018, 0xa7a00012, 0x10a20068, 0xa7a00010, 0x2ca20003, 0x10400005, 0x24020001, -0x10a2000a, 0x148140, 0x8005172, 0x2201021, +0x10a2000a, 0x148140, 0x8005176, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, -0x142940, 0x8005172, 0x2201021, 0x3c030001, -0x701821, 0x8c6375bc, 0x3c024000, 0x621024, +0x142940, 0x8005176, 0x2201021, 0x3c030001, +0x701821, 0x8c6375cc, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, -0x628824, 0x3c010001, 0x300821, 0xac3175b4, -0x8005172, 0x2201021, 0x24050001, 0xc0048a8, -0x27a60010, 0x24040001, 0x24050001, 0xc0048a8, +0x628824, 0x3c010001, 0x300821, 0xac3175c4, +0x8005176, 0x2201021, 0x24050001, 0xc0048ac, +0x27a60010, 0x24040001, 0x24050001, 0xc0048ac, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, -0x3c114000, 0x3c030001, 0x8c635540, 0x24020003, +0x3c114000, 0x3c030001, 0x8c635550, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, -0x24020004, 0x10620014, 0x24040001, 0x8005115, +0x24020004, 0x10620014, 0x24040001, 0x8005119, 0x3c028000, 0x24040001, 0x24050011, 0x27b00012, -0xc0048a8, 0x2003021, 0x24040001, 0x24050011, -0xc0048a8, 0x2003021, 0x97a30012, 0x30624000, +0xc0048ac, 0x2003021, 0x24040001, 0x24050011, +0xc0048ac, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, -0x8005112, 0x30628000, 0x24050014, 0x27b00012, -0xc0048a8, 0x2003021, 0x24040001, 0x24050014, -0xc0048a8, 0x2003021, 0x97a30012, 0x30621000, +0x8005116, 0x30628000, 0x24050014, 0x27b00012, +0xc0048ac, 0x2003021, 0x24040001, 0x24050014, +0xc0048ac, 0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, -0x2221025, 0x2531825, 0x800511f, 0x438825, -0x3c110001, 0x2308821, 0x8e3175bc, 0x3c027fff, +0x2221025, 0x2531825, 0x8005123, 0x438825, +0x3c110001, 0x2308821, 0x8e3175cc, 0x3c027fff, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, -0x220821, 0xac3175b4, 0x8005172, 0x2201021, -0x142940, 0x3c030001, 0x651821, 0x8c6375b8, +0x220821, 0xac3175c4, 0x8005176, 0x2201021, +0x142940, 0x3c030001, 0x651821, 0x8c6375c8, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, 0x250821, -0xac3175b0, 0x8005172, 0x2201021, 0x3c020001, -0x8c425488, 0x10400033, 0x3c11c00c, 0x3c020001, -0x8c425504, 0x3c04c00c, 0x34842000, 0x3c030001, -0x8c635528, 0x2102b, 0x21023, 0x441024, +0xac3175c0, 0x8005176, 0x2201021, 0x3c020001, +0x8c425498, 0x10400033, 0x3c11c00c, 0x3c020001, +0x8c425514, 0x3c04c00c, 0x34842000, 0x3c030001, +0x8c635538, 0x2102b, 0x21023, 0x441024, 0x10600003, 0x518825, 0x3c022000, 0x2228825, -0x3c020001, 0x451021, 0x8c4275c4, 0x10400003, -0x3c020020, 0x800514f, 0x2228825, 0x3c02ffdf, +0x3c020001, 0x451021, 0x8c4275d4, 0x10400003, +0x3c020020, 0x8005153, 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140, 0x3c010001, -0x220821, 0x8c2275cc, 0x10400003, 0x3c020080, -0x800515a, 0x2228825, 0x3c02ff7f, 0x3442ffff, -0x2228824, 0x3c020001, 0x8c4254f0, 0x10400002, -0x3c020800, 0x2228825, 0x3c020001, 0x8c4254f4, +0x220821, 0x8c2275dc, 0x10400003, 0x3c020080, +0x800515e, 0x2228825, 0x3c02ff7f, 0x3442ffff, +0x2228824, 0x3c020001, 0x8c425500, 0x10400002, +0x3c020800, 0x2228825, 0x3c020001, 0x8c425504, 0x10400002, 0x3c020400, 0x2228825, 0x3c020001, -0x8c4254f8, 0x10400006, 0x3c020100, 0x800516d, +0x8c425508, 0x10400006, 0x3c020100, 0x8005171, 0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, -0x141140, 0x3c010001, 0x220821, 0xac3175b0, +0x141140, 0x3c010001, 0x220821, 0xac3175c0, 0x2201021, 0x8fbf002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffd8, 0xafb40020, 0x80a021, 0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, -0xafb00010, 0x8f900200, 0x3c030001, 0x8c635478, +0xafb00010, 0x8f900200, 0x3c030001, 0x8c635488, 0x8f930220, 0x24020002, 0x106200b4, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x141940, -0x800523c, 0x0, 0x24020004, 0x1062005a, -0x24020008, 0x10620059, 0x149140, 0x800523c, -0x0, 0x3c040001, 0x832021, 0x8c8475bc, -0x3c110001, 0x2238821, 0x8e3175b4, 0x3c024000, +0x8005240, 0x0, 0x24020004, 0x1062005a, +0x24020008, 0x10620059, 0x149140, 0x8005240, +0x0, 0x3c040001, 0x832021, 0x8c8475cc, +0x3c110001, 0x2238821, 0x8e3175c4, 0x3c024000, 0x821024, 0x1040003e, 0x3c020008, 0x2221024, 0x10400020, 0x36100002, 0x3c020001, 0x431021, -0x8c4275c0, 0x10400005, 0x36100020, 0x36100100, -0x3c020020, 0x80051b1, 0x2228825, 0x2402feff, +0x8c4275d0, 0x10400005, 0x36100020, 0x36100100, +0x3c020020, 0x80051b5, 0x2228825, 0x2402feff, 0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x141140, 0x3c010001, 0x220821, 0x8c2275c8, +0x141140, 0x3c010001, 0x220821, 0x8c2275d8, 0x10400005, 0x3c020001, 0x2629825, 0x3c020080, -0x80051d0, 0x2228825, 0x3c02fffe, 0x3442ffff, -0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d0, +0x80051d4, 0x2228825, 0x3c02fffe, 0x3442ffff, +0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80051d4, 0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, -0x2228824, 0x3c010001, 0x230821, 0xac2075c0, -0x3c010001, 0x230821, 0xac2075c8, 0xc0047cc, +0x2228824, 0x3c010001, 0x230821, 0xac2075d0, +0x3c010001, 0x230821, 0xac2075d8, 0xc0047cc, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xaf820220, 0x80051e7, 0x141140, +0x34420002, 0xaf820220, 0x80051eb, 0x141140, 0x8f820200, 0x2403fffd, 0x431024, 0xc0047cc, 0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, 0x2228824, 0x141140, 0x3c010001, 0x220821, -0x800523c, 0xac3175b4, 0x149140, 0x3c040001, -0x922021, 0x8c8475b8, 0x3c110001, 0x2328821, -0x8e3175b0, 0x3c024000, 0x821024, 0x14400011, -0x0, 0x3c020001, 0x8c425528, 0x14400006, +0x8005240, 0xac3175c4, 0x149140, 0x3c040001, +0x922021, 0x8c8475c8, 0x3c110001, 0x2328821, +0x8e3175c0, 0x3c024000, 0x821024, 0x14400011, +0x0, 0x3c020001, 0x8c425538, 0x14400006, 0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cc, 0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, -0x2228824, 0x3c010001, 0x320821, 0x800523c, -0xac3175b0, 0x3c020001, 0x8c425528, 0x10400005, -0x3c020020, 0x3c020001, 0x8c425504, 0x1040002b, +0x2228824, 0x3c010001, 0x320821, 0x8005240, +0xac3175c0, 0x3c020001, 0x8c425538, 0x10400005, +0x3c020020, 0x3c020001, 0x8c425514, 0x1040002b, 0x3c020020, 0x821024, 0x10400007, 0x36100020, -0x24020100, 0x3c010001, 0x320821, 0xac2275c4, -0x800521c, 0x36100100, 0x3c010001, 0x320821, -0xac2075c4, 0x2402feff, 0x2028024, 0x3c020080, +0x24020100, 0x3c010001, 0x320821, 0xac2275d4, +0x8005220, 0x36100100, 0x3c010001, 0x320821, +0xac2075d4, 0x2402feff, 0x2028024, 0x3c020080, 0x821024, 0x10400007, 0x141940, 0x3c020001, -0x3c010001, 0x230821, 0xac2275cc, 0x800522d, +0x3c010001, 0x230821, 0xac2275dc, 0x8005231, 0x2629825, 0x141140, 0x3c010001, 0x220821, -0xac2075cc, 0x3c02fffe, 0x3442ffff, 0x2629824, +0xac2075dc, 0x3c02fffe, 0x3442ffff, 0x2629824, 0xc0047cc, 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 0x141140, -0x3c010001, 0x220821, 0xac3175b0, 0x8fbf0024, +0x3c010001, 0x220821, 0xac3175c0, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f66, -0x776d6169, 0x6e2e632c, 0x7620312e, 0x312e322e, -0x31312031, 0x3939382f, 0x30342f32, 0x37203232, -0x3a31333a, 0x34322073, 0x6875616e, 0x67204578, -0x70202400, 0x7468655f, 0x4441574e, 0x0, -0x53544143, 0x4b5f3120, 0x0, 0x42616453, -0x6e64526e, 0x67000000, 0x3f456e71, 0x45767400, -0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, -0x6746756c, 0x6c000000, 0x496c6c43, 0x6f6e6652, -0x78000000, 0x53656e64, 0x436b5375, 0x6d000000, -0x52656376, 0x566c616e, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e, +0x322e3131, 0x20313939, 0x382f3034, 0x2f323720, +0x32323a31, 0x333a3432, 0x20736875, 0x616e6720, +0x45787020, 0x24000000, 0x7468655f, 0x4441574e, +0x0, 0x53544143, 0x4b5f3120, 0x0, +0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71, +0x45767400, 0x3f6e6f51, 0x64457650, 0x0, +0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43, +0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375, +0x6d000000, 0x52656376, 0x566c616e, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, -0x696d6572, 0x2e632c76, 0x20312e31, 0x2e322e38, -0x20313939, 0x382f3037, 0x2f333120, 0x31373a35, -0x383a3435, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x542d446d, 0x61526431, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32, +0x2e382031, 0x3939382f, 0x30372f33, 0x31203137, +0x3a35383a, 0x34352073, 0x6875616e, 0x67204578, +0x70202400, 0x542d446d, 0x61526431, 0x0, 0x542d446d, 0x61424200, 0x542d446d, 0x61320000, 0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, 0x64527845, 0x0, 0x656e714d, 0x45765046, @@ -4286,11 +4287,11 @@ 0x6576526e, 0x6746756c, 0x6c000000, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, -0x6f6d6d61, 0x6e642e63, 0x2c762031, 0x2e312e32, -0x2e313020, 0x31393938, 0x2f31312f, 0x31382031, -0x373a3131, 0x3a313820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x3f4d626f, 0x78457674, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31, +0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138, +0x2031373a, 0x31313a31, 0x38207368, 0x75616e67, +0x20457870, 0x20240000, 0x3f4d626f, 0x78457674, 0x0, 0x4e4f636f, 0x6d616e64, 0x0, 0x68737465, 0x5f455252, 0x0, 0x412d4572, 0x72427563, 0x0, 0x4552524f, 0x522d4164, @@ -4309,29 +4310,29 @@ 0x7e70, 0x80cc, 0x6e64, 0x81cc, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, -0x6d612e63, 0x2c762031, 0x2e312e32, 0x2e332031, -0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, -0x34312073, 0x6875616e, 0x67204578, 0x70202400, -0x646d6172, 0x6441544e, 0x0, 0x646d6177, -0x7241544e, 0x0, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3431, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x646d6172, 0x6441544e, 0x0, +0x646d6177, 0x7241544e, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f74, -0x72616365, 0x2e632c76, 0x20312e31, 0x2e322e32, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3530, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x24486561, 0x6465723a, 0x202f7072, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32, +0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, +0x3a31333a, 0x35302073, 0x6875616e, 0x67204578, +0x70202400, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f64, -0x6174612e, 0x632c7620, 0x312e312e, 0x322e3220, -0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, -0x3a343020, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x2331204d, 0x6f6e2046, 0x65622031, 0x2031363a, -0x35393a30, 0x31205053, 0x54203139, 0x39390000, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e, +0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, +0x31333a34, 0x30207368, 0x75616e67, 0x20457870, +0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, +0x23312054, 0x75652041, 0x70722032, 0x30203137, +0x3a32313a, 0x30382050, 0x44542031, 0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031363a, 0x35393a30, 0x31000000, 0x46575f43, +0x2031373a, 0x32313a30, 0x38000000, 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, @@ -4342,17 +4343,17 @@ 0x2e320000, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, -0x656d2e63, 0x2c762031, 0x2e312e32, 0x2e322031, -0x3939382f, 0x30342f32, 0x37203232, 0x3a31333a, -0x34342073, 0x6875616e, 0x67204578, 0x70202400, -0x0, 0x24486561, 0x6465723a, 0x202f7072, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32, +0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, +0x333a3434, 0x20736875, 0x616e6720, 0x45787020, +0x24000000, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f73, -0x656e642e, 0x632c7620, 0x312e312e, 0x322e3131, -0x20313939, 0x382f3132, 0x2f323220, 0x31373a31, -0x373a3535, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x736e6464, 0x654e6f51, 0x20000000, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e, +0x31312031, 0x3939382f, 0x31322f32, 0x32203137, +0x3a31373a, 0x35352073, 0x6875616e, 0x67204578, +0x70202400, 0x736e6464, 0x654e6f51, 0x20000000, 0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, 0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, 0x0, 0x756e6b72, 0x64747970, 0x65000000, @@ -4368,11 +4369,11 @@ 0xbd80, 0xbd80, 0xbd80, 0xbd64, 0xb050, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f72, -0x6563762e, 0x632c7620, 0x312e312e, 0x322e3139, -0x20313939, 0x382f3037, 0x2f323420, 0x32313a33, -0x303a3035, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x706b5278, 0x45525200, 0x66726d32, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e, +0x31392031, 0x3939382f, 0x30372f32, 0x34203231, +0x3a33303a, 0x30352073, 0x6875616e, 0x67204578, +0x70202400, 0x706b5278, 0x45525200, 0x66726d32, 0x4c617267, 0x65000000, 0x72784e6f, 0x52784264, 0x0, 0x72785144, 0x6d614446, 0x0, 0x72785144, 0x6d614246, 0x0, 0x3f6e6f51, @@ -4392,11 +4393,11 @@ 0x1016c, 0x1016c, 0x10164, 0x10164, 0x10164, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f6d, -0x61632e63, 0x2c762031, 0x2e312e32, 0x2e313220, -0x31393938, 0x2f30342f, 0x32372032, 0x323a3133, -0x3a343220, 0x73687561, 0x6e672045, 0x78702024, -0x0, 0x6d616374, 0x7841544e, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31, +0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, +0x31333a34, 0x32207368, 0x75616e67, 0x20457870, +0x20240000, 0x6d616374, 0x7841544e, 0x0, 0x4e745379, 0x6e264c6b, 0x0, 0x72656d61, 0x73737274, 0x0, 0x6c696e6b, 0x444f574e, 0x0, 0x656e714d, 0x45765046, 0x61696c00, @@ -4404,27 +4405,27 @@ 0x456e454d, 0x0, 0x6c696e6b, 0x55500000, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f66772f, 0x636f6d6d, 0x6f6e2f63, -0x6b73756d, 0x2e632c76, 0x20312e31, 0x2e322e32, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3339, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x50726f62, 0x65506879, 0x0, +0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, +0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32, +0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, +0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, +0x70202400, 0x50726f62, 0x65506879, 0x0, 0x6c6e6b41, 0x53535254, 0x0, 0x11994, 0x119cc, 0x119e4, 0x11a18, 0x11a44, 0x11a58, 0x11a94, 0x11e04, 0x11b6c, 0x11bac, 0x11bd8, 0x11c18, 0x11c48, 0x11c84, 0x11cb8, 0x11e04, 0x12048, 0x12060, 0x12088, 0x120a8, 0x120d0, -0x12200, 0x12228, 0x1226c, 0x12294, -0x0, 0x124fc, 0x125cc, 0x126a4, -0x12774, 0x127d0, 0x128ac, 0x128d4, -0x129b0, 0x129d8, 0x12b80, 0x12ba8, -0x12d50, 0x12f48, 0x131dc, 0x130f0, -0x131dc, 0x13208, 0x12d78, 0x12f20, -0x0, 0x135f4, 0x13638, 0x136d0, -0x1371c, 0x1378c, 0x13824, 0x13858, -0x138e0, 0x13978, 0x13a48, 0x13a88, -0x13b0c, 0x13b30, 0x13c64, 0x646f4261, +0x12200, 0x12228, 0x1227c, 0x122a4, +0x0, 0x1250c, 0x125dc, 0x126b4, +0x12784, 0x127e0, 0x128bc, 0x128e4, +0x129c0, 0x129e8, 0x12b90, 0x12bb8, +0x12d60, 0x12f58, 0x131ec, 0x13100, +0x131ec, 0x13218, 0x12d88, 0x12f30, +0x0, 0x13604, 0x13648, 0x136e0, +0x1372c, 0x1379c, 0x13834, 0x13868, +0x138f0, 0x13988, 0x13a58, 0x13a98, +0x13b1c, 0x13b40, 0x13c74, 0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, 0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; @@ -4454,24 +4455,24 @@ /* Generated by genfw.c */ int tigon2FwReleaseMajor = 0xc; int tigon2FwReleaseMinor = 0x3; -int tigon2FwReleaseFix = 0x5; +int tigon2FwReleaseFix = 0xa; u32 tigon2FwStartAddr = 0x00004000; u32 tigon2FwTextAddr = 0x00004000; -int tigon2FwTextLen = 0xec80; -u32 tigon2FwRodataAddr = 0x00012c80; -int tigon2FwRodataLen = 0xfb0; -u32 tigon2FwDataAddr = 0x00013c50; +int tigon2FwTextLen = 0xed40; +u32 tigon2FwRodataAddr = 0x00012d40; +int tigon2FwRodataLen = 0xff0; +u32 tigon2FwDataAddr = 0x00013d60; int tigon2FwDataLen = 0x170; -u32 tigon2FwSbssAddr = 0x00013dc0; +u32 tigon2FwSbssAddr = 0x00013ed0; int tigon2FwSbssLen = 0xbc; -u32 tigon2FwBssAddr = 0x00013e80; +u32 tigon2FwBssAddr = 0x00013f90; int tigon2FwBssLen = 0x20c0; u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, -0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, 0x3c100000, +0x3c1d0001, 0x8fbd3db0, 0x3a0f021, 0x3c100000, 0x26104000, 0xc0010c0, 0x0, 0xd, -0x3c1d0001, 0x8fbd3ca4, 0x3a0f021, 0x3c100000, +0x3c1d0001, 0x8fbd3db4, 0x3a0f021, 0x3c100000, 0x26104000, 0xc00178d, 0x0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -4485,19 +4486,19 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000008, 0x0, 0x80016de, 0x3c0a0001, 0x80016de, -0x3c0a0002, 0x80016de, 0x0, 0x8002acd, -0x0, 0x8002a70, 0x0, 0x80016de, -0x3c0a0004, 0x8003095, 0x0, 0x8001a0e, -0x0, 0x800373f, 0x0, 0x80036e6, -0x0, 0x80016de, 0x3c0a0006, 0x80037ad, +0x3c0a0002, 0x80016de, 0x0, 0x8002afd, +0x0, 0x8002aa0, 0x0, 0x80016de, +0x3c0a0004, 0x80030d1, 0x0, 0x8001a0e, +0x0, 0x8003779, 0x0, 0x8003720, +0x0, 0x80016de, 0x3c0a0006, 0x80037e7, 0x3c0a0007, 0x80016de, 0x3c0a0008, 0x80016de, -0x3c0a0009, 0x8003805, 0x0, 0x8002cc0, +0x3c0a0009, 0x800383f, 0x0, 0x8002cf7, 0x0, 0x80016de, 0x3c0a000b, 0x80016de, -0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027ac, +0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027c5, 0x0, 0x800275a, 0x0, 0x80016de, 0x3c0a000e, 0x8001f28, 0x0, 0x8001920, -0x0, 0x80019c0, 0x0, 0x8003a70, -0x0, 0x8003a5e, 0x0, 0x80016de, +0x0, 0x80019c0, 0x0, 0x8003aa8, +0x0, 0x8003a96, 0x0, 0x80016de, 0x0, 0x80018c6, 0x0, 0x80016de, 0x0, 0x80016de, 0x3c0a0013, 0x80016de, 0x3c0a0014, 0x0, 0x0, 0x0, @@ -4517,79 +4518,79 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27bdffe0, 0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, -0x24030003, 0xaf8300ec, 0x34420004, 0xc0029b8, +0x24030003, 0xaf8300ec, 0x34420004, 0xc0029e8, 0xaf820140, 0x3c0100c0, 0xc001712, 0xac203ffc, -0x403021, 0x3c020008, 0x3c010001, 0xac263dd8, +0x403021, 0x3c020008, 0x3c010001, 0xac263ee8, 0x50c2000d, 0x3c020003, 0x3c100010, 0x10d00009, -0x24050100, 0x3c040001, 0x24842d34, 0x3821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x3c010001, -0xac303dd8, 0x3c020003, 0x34422000, 0x3c010001, -0xac223de8, 0x24020008, 0x3c010001, 0xac223df0, -0x2402001f, 0x3c010001, 0xac223e00, 0x24020016, -0x3c010001, 0xac223dd4, 0x3c05fffe, 0x34a56f08, -0x3c020001, 0x8c423dd8, 0x3c030001, 0x24635f40, -0x3c040001, 0x8c843c54, 0x431023, 0x14800002, +0x24050100, 0x3c040001, 0x24842df4, 0x3821, +0xafa00010, 0xc002a03, 0xafa00014, 0x3c010001, +0xac303ee8, 0x3c020003, 0x34422000, 0x3c010001, +0xac223ef8, 0x24020008, 0x3c010001, 0xac223f00, +0x2402001f, 0x3c010001, 0xac223f10, 0x24020016, +0x3c010001, 0xac223ee4, 0x3c05fffe, 0x34a56f08, +0x3c020001, 0x8c423ee8, 0x3c030001, 0x24636050, +0x3c040001, 0x8c843d64, 0x431023, 0x14800002, 0x458021, 0x2610fa48, 0x2402f000, 0x2028024, 0xc001734, 0x2002021, 0x2022823, 0x3c040020, 0x821823, 0x651823, 0x247bb000, 0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, -0x3c070001, 0x8ce73c50, 0x3c0300bf, 0x3463e000, -0x852023, 0x3c010001, 0xac243de4, 0x822023, -0x3c010001, 0xac223dc0, 0x27620ffc, 0x3c010001, -0xac223ca0, 0x27621ffc, 0xdb3023, 0x7b1823, -0x3c010001, 0xac253dcc, 0x3c010001, 0xac243dc4, -0x3c010001, 0xac223ca4, 0xaf860150, 0x10e00011, -0xaf830250, 0x3c1d0001, 0x8fbd3c5c, 0x3a0f021, -0xc0016f8, 0x0, 0x3c020001, 0x8c423c60, -0x3c030001, 0x8c633c64, 0x2442fe00, 0x24630200, -0x3c010001, 0xac223c60, 0x3c010001, 0x10000004, -0xac233c64, 0x3c1d0001, 0x8fbd3ca0, 0x3a0f021, -0x3c020001, 0x8c423c54, 0x1040000d, 0x26fafa48, -0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, -0x3c1a0001, 0x8f5a3c64, 0x2442fa48, 0x246305b8, -0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, -0x3c020001, 0x8c423c58, 0x14400003, 0x0, -0x3c010001, 0xac203c60, 0xc00114d, 0x0, +0x3c070001, 0x8ce73d60, 0x3c0300bf, 0x3463e000, +0x852023, 0x3c010001, 0xac243ef4, 0x822023, +0x3c010001, 0xac223ed0, 0x27620ffc, 0x3c010001, +0xac223db0, 0x27621ffc, 0xdb3023, 0x7b1823, +0x3c010001, 0xac253edc, 0x3c010001, 0xac243ed4, +0x3c010001, 0xac223db4, 0xaf860150, 0x10e00011, +0xaf830250, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, +0xc0016f8, 0x0, 0x3c020001, 0x8c423d70, +0x3c030001, 0x8c633d74, 0x2442fe00, 0x24630200, +0x3c010001, 0xac223d70, 0x3c010001, 0x10000004, +0xac233d74, 0x3c1d0001, 0x8fbd3db0, 0x3a0f021, +0x3c020001, 0x8c423d64, 0x1040000d, 0x26fafa48, +0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, +0x3c1a0001, 0x8f5a3d74, 0x2442fa48, 0x246305b8, +0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, +0x3c020001, 0x8c423d68, 0x14400003, 0x0, +0x3c010001, 0xac203d70, 0xc00114d, 0x0, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x3c020001, 0x8c423c60, 0x3c030001, 0x8c633c64, -0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1036f4, -0x3c040001, 0x24842d40, 0xafbf0058, 0xafbe0054, +0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, +0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1037d8, +0x3c040001, 0x24842e00, 0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050200, 0xc0029d3, 0x2003821, +0x8f860040, 0x24050200, 0xc002a03, 0x2003821, 0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, 0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, -0x24842d48, 0xa3ae003f, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050300, 0xc0029d3, 0x2003821, +0x24842e08, 0xa3ae003f, 0xafa00010, 0xafa00014, +0x8f860040, 0x24050300, 0xc002a03, 0x2003821, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 0xaf800048, 0x8f820048, 0x14400005, 0x0, 0xaf800048, 0x8f820048, 0x10400004, 0x0, 0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, -0x2e02021, 0x3c050001, 0xc002a40, 0x34a540f8, -0x3402021, 0xc002a40, 0x240505b8, 0x3c020001, -0x8c423de4, 0x3c0d0001, 0x8dad3dc4, 0x3c030001, -0x8c633dc0, 0x3c080001, 0x8d083dcc, 0x3c090001, -0x8d293de8, 0x3c0a0001, 0x8d4a3df0, 0x3c0b0001, -0x8d6b3e00, 0x3c0c0001, 0x8d8c3dd4, 0x3c040001, -0x24842d54, 0x24050400, 0xaf420130, 0x8f420130, +0x2e02021, 0x3c050001, 0xc002a70, 0x34a540f8, +0x3402021, 0xc002a70, 0x240505b8, 0x3c020001, +0x8c423ef4, 0x3c0d0001, 0x8dad3ed4, 0x3c030001, +0x8c633ed0, 0x3c080001, 0x8d083edc, 0x3c090001, +0x8d293ef8, 0x3c0a0001, 0x8d4a3f00, 0x3c0b0001, +0x8d6b3f10, 0x3c0c0001, 0x8d8c3ee4, 0x3c040001, +0x24842e14, 0x24050400, 0xaf420130, 0x8f420130, 0x24060001, 0x24070001, 0xaf400000, 0xaf4d012c, 0xaf430138, 0xaf48013c, 0xaf490140, 0xaf4a0144, 0xaf4b0148, 0xaf4c014c, 0x2442ff80, 0xaf420134, -0x24020001, 0xafa20010, 0xc0029d3, 0xafa00014, +0x24020001, 0xafa20010, 0xc002a03, 0xafa00014, 0x8f42012c, 0xafa20010, 0x8f420130, 0xafa20014, -0x8f460138, 0x8f47013c, 0x3c040001, 0x24842d60, -0xc0029d3, 0x24050500, 0xafb70010, 0xafba0014, -0x8f460140, 0x8f470144, 0x3c040001, 0x24842d6c, -0xc0029d3, 0x24050600, 0x3c020001, 0x8c423dd8, -0x3603821, 0x3c060001, 0x24c65f40, 0x2448ffff, +0x8f460138, 0x8f47013c, 0x3c040001, 0x24842e20, +0xc002a03, 0x24050500, 0xafb70010, 0xafba0014, +0x8f460140, 0x8f470144, 0x3c040001, 0x24842e2c, +0xc002a03, 0x24050600, 0x3c020001, 0x8c423ee8, +0x3603821, 0x3c060001, 0x24c66050, 0x2448ffff, 0x1061824, 0xe81024, 0x43102b, 0x10400006, -0x24050900, 0x3c040001, 0x24842d78, 0xafa80010, -0xc0029d3, 0xafa00014, 0x8f82000c, 0xafa20010, +0x24050900, 0x3c040001, 0x24842e38, 0xafa80010, +0xc002a03, 0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, -0x3c040001, 0x24842d84, 0xc0029d3, 0x24051000, +0x3c040001, 0x24842e44, 0xc002a03, 0x24051000, 0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, -0x3c040001, 0x24842d8c, 0x24051100, 0xafa20010, -0xc0029d3, 0xafa30014, 0xaf800054, 0xaf80011c, +0x3c040001, 0x24842e4c, 0x24051100, 0xafa20010, +0xc002a03, 0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218, 0x30420002, 0x10400009, 0x0, 0x8c020220, 0x3c030002, 0x34630004, 0x431025, 0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, @@ -4611,7 +4612,7 @@ 0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, 0x24051200, 0x96e20472, 0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001, -0x24842d94, 0xc0029d3, 0xafa20014, 0x96f00452, +0x24842e54, 0xc002a03, 0xafa20014, 0x96f00452, 0x32020001, 0x10400002, 0xb021, 0x24160001, 0x32020002, 0x54400001, 0x36d60002, 0x32020008, 0x54400001, 0x36d60004, 0x32020010, 0x54400001, @@ -4624,8 +4625,8 @@ 0x14400004, 0x3207009b, 0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000, 0x1440000d, 0x32020001, 0x3062009b, 0x10e20009, 0x240e0001, 0x3c040001, -0x24842da0, 0x24051300, 0x2003821, 0xa3ae003f, -0xafa30010, 0xc0029d3, 0xafa00014, 0x32020001, +0x24842e60, 0x24051300, 0x2003821, 0xa3ae003f, +0xafa30010, 0xc002a03, 0xafa00014, 0x32020001, 0x54400001, 0x36d60080, 0x32020002, 0x54400001, 0x36d60100, 0x32020008, 0x54400001, 0x36d60200, 0x32020010, 0x54400001, 0x36d60400, 0x32020080, @@ -4649,191 +4650,191 @@ 0xaf420180, 0xaf430184, 0x8ee20478, 0x8ee3047c, 0xaf420188, 0xaf43018c, 0x8ee20488, 0x8ee3048c, 0xaf420190, 0xaf430194, 0x8ee204b0, 0x8ee304b4, -0x24040080, 0xaf420198, 0xaf43019c, 0xc002a40, +0x24040080, 0xaf420198, 0xaf43019c, 0xc002a70, 0x24050080, 0x8c02025c, 0x27440214, 0xaf4201e0, -0x8c020260, 0x24050200, 0x24060008, 0xc002a57, +0x8c020260, 0x24050200, 0x24060008, 0xc002a87, 0xaf4201e8, 0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006, 0x24030002, 0xaf4201e4, 0x240203e8, 0xaf4301f4, 0xaf4301f0, 0xaf4401ec, 0xaf420284, 0x24020001, 0xaf430280, 0xaf42028c, 0x3c030001, -0x671821, 0x90633c68, 0x3471021, 0x24e70001, +0x671821, 0x90633d78, 0x3471021, 0x24e70001, 0xa043021c, 0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040, -0x3c040001, 0x24842dac, 0x24051400, 0x21702, +0x3c040001, 0x24842e6c, 0x24051400, 0x21702, 0x24420030, 0xa062021c, 0x3471021, 0xa040021c, 0x8c070218, 0x2c03021, 0x240205b8, 0xafa20010, -0xc0029d3, 0xafa80014, 0x3c040001, 0x24842db8, +0xc002a03, 0xafa80014, 0x3c040001, 0x24842e78, 0x3c050000, 0x24a55b3c, 0x24060010, 0x27b10030, 0x2203821, 0x27b30034, 0xc001750, 0xafb30010, -0x3c030001, 0x8c633c58, 0x1060000a, 0x408021, +0x3c030001, 0x8c633d68, 0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, 0x831823, 0x431023, 0xafa20034, -0xafa40030, 0xafb30010, 0x3c040001, 0x24842dc4, +0xafa40030, 0xafb30010, 0x3c040001, 0x24842e84, 0x3c050000, 0x24a54100, 0x24060108, 0xc001750, 0x2203821, 0x409021, 0x32c20003, 0x50400045, 0x2203821, 0x8f820050, 0x3c030010, 0x431024, 0x10400016, 0x0, 0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, -0x240e0001, 0x3c040001, 0x24842dd0, 0xa3ae003f, +0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, -0xc0029d3, 0x2c03021, 0x10000004, 0x0, +0xc002a03, 0x2c03021, 0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, -0x24842ddc, 0x3c050001, 0x24a59ce8, 0x3c060001, +0x24842e9c, 0x3c050001, 0x24a59ce8, 0x3c060001, 0x24c69d60, 0xc53023, 0x8f420010, 0x27b30030, 0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, -0xc001750, 0xafb10010, 0x3c040001, 0x24842df0, -0x3c050001, 0x24a5af7c, 0x3c060001, 0x24c6b2f8, +0xc001750, 0xafb10010, 0x3c040001, 0x24842eb0, +0x3c050001, 0x24a5b058, 0x3c060001, 0x24c6b3d4, 0xc53023, 0x2603821, 0xaf420108, 0xc001750, -0xafb10010, 0x3c040001, 0x24842e0c, 0x3c050001, -0x24a5b714, 0x3c060001, 0x24c6c1d4, 0xc53023, -0x2603821, 0x3c010001, 0xac223e30, 0xc001750, -0xafb10010, 0x3c040001, 0x24842e24, 0x10000024, -0x24051600, 0x3c040001, 0x24842e2c, 0x3c050001, +0xafb10010, 0x3c040001, 0x24842ecc, 0x3c050001, +0x24a5b7e4, 0x3c060001, 0x24c6c2c8, 0xc53023, +0x2603821, 0x3c010001, 0xac223f40, 0xc001750, +0xafb10010, 0x3c040001, 0x24842ee4, 0x10000024, +0x24051600, 0x3c040001, 0x24842eec, 0x3c050001, 0x24a59bb4, 0x3c060001, 0x24c69ce0, 0xc53023, -0xc001750, 0xafb30010, 0x3c040001, 0x24842e3c, -0x3c050001, 0x24a5ab34, 0x3c060001, 0x24c6af74, +0xc001750, 0xafb30010, 0x3c040001, 0x24842efc, +0x3c050001, 0x24a5abf4, 0x3c060001, 0x24c6b050, 0xc53023, 0x2203821, 0xaf420108, 0xc001750, -0xafb30010, 0x3c040001, 0x24842e50, 0x3c050001, -0x24a5b300, 0x3c060001, 0x24c6b70c, 0xc53023, -0x2203821, 0x3c010001, 0xac223e30, 0xc001750, -0xafb30010, 0x3c040001, 0x24842e64, 0x24051650, -0x2c03021, 0x3821, 0x3c010001, 0xac223e34, -0xafa00010, 0xc0029d3, 0xafa00014, 0x32c20020, -0x10400021, 0x27a70030, 0x3c040001, 0x24842e70, -0x3c050001, 0x24a5a9c0, 0x3c060001, 0x24c6ab2c, +0xafb30010, 0x3c040001, 0x24842f10, 0x3c050001, +0x24a5b3dc, 0x3c060001, 0x24c6b7dc, 0xc53023, +0x2203821, 0x3c010001, 0xac223f40, 0xc001750, +0xafb30010, 0x3c040001, 0x24842f24, 0x24051650, +0x2c03021, 0x3821, 0x3c010001, 0xac223f44, +0xafa00010, 0xc002a03, 0xafa00014, 0x32c20020, +0x10400021, 0x27a70030, 0x3c040001, 0x24842f30, +0x3c050001, 0x24a5aa80, 0x3c060001, 0x24c6abec, 0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, 0xc001750, 0xafa20010, 0x21900, 0x31982, 0x3c040800, 0x641825, 0xae430028, 0x24030010, 0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, -0x3c040001, 0x24842e84, 0xafa00014, 0xafa30010, -0x8f47001c, 0x24051660, 0x3c010001, 0xac223e2c, +0x3c040001, 0x24842f44, 0xafa00014, 0xafa30010, +0x8f47001c, 0x24051660, 0x3c010001, 0xac223f3c, 0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, -0x1440000a, 0x240e0001, 0x3c040001, 0x24842e90, +0x1440000a, 0x240e0001, 0x3c040001, 0x24842f50, 0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, -0x24051700, 0xc0029d3, 0x3821, 0x3c020000, +0x24051700, 0xc002a03, 0x3821, 0x3c020000, 0x24425b78, 0x21100, 0x21182, 0x3c030800, 0x431025, 0xae420028, 0x24020008, 0xaf42003c, 0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, -0x24842e9c, 0xafa00014, 0xafa20010, 0x8f47001c, -0x24051800, 0x32c60020, 0xc0029d3, 0x0, -0x3c030001, 0x8c633e30, 0x3c050fff, 0x34a5ffff, -0x3c020001, 0x8c423e34, 0x3c040800, 0x651824, +0x24842f5c, 0xafa00014, 0xafa20010, 0x8f47001c, +0x24051800, 0x32c60020, 0xc002a03, 0x0, +0x3c030001, 0x8c633f40, 0x3c050fff, 0x34a5ffff, +0x3c020001, 0x8c423f44, 0x3c040800, 0x651824, 0x31882, 0x641825, 0x451024, 0x21082, 0x441025, 0xae420080, 0x32c20180, 0x10400056, 0xae430020, 0x8f82005c, 0x3c030080, 0x431024, 0x1040000d, 0x0, 0x8f820050, 0xafa20010, -0x8f82005c, 0x240e0001, 0x3c040001, 0x24842ea8, +0x8f82005c, 0x240e0001, 0x3c040001, 0x24842f68, 0xa3ae003f, 0xafa20014, 0x8f870040, 0x24051900, -0xc0029d3, 0x2c03021, 0x8f820050, 0x3c030010, +0xc002a03, 0x2c03021, 0x8f820050, 0x3c030010, 0x431024, 0x10400016, 0x0, 0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 0x8f820050, -0x8c030218, 0x240e0001, 0x3c040001, 0x24842dd0, +0x8c030218, 0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, -0x24052000, 0xc0029d3, 0x2c03021, 0x10000004, +0x24052000, 0xc002a03, 0x2c03021, 0x10000004, 0x0, 0x3c010001, 0x370821, 0xa02240f4, -0x3c040001, 0x24842eb4, 0x3c050001, 0x24a59b2c, +0x3c040001, 0x24842f74, 0x3c050001, 0x24a59b2c, 0x3c060001, 0x24c69bac, 0xc53023, 0x8f420008, 0x27b30030, 0x2603821, 0x27b10034, 0x34420e00, 0xaf420008, 0xc001750, 0xafb10010, 0x3c040001, -0x24842ecc, 0x3c050001, 0x24a5d090, 0x3c060001, -0x24c6db90, 0xc53023, 0x2603821, 0xaf42010c, -0xc001750, 0xafb10010, 0x3c040001, 0x24842ee4, -0x3c050001, 0x24a5e174, 0x3c060001, 0x24c6e860, -0xc53023, 0x2603821, 0x3c010001, 0xac223e40, -0xc001750, 0xafb10010, 0x3c040001, 0x24842efc, -0x10000027, 0x24052100, 0x3c040001, 0x24842f04, +0x24842f8c, 0x3c050001, 0x24a5d180, 0x3c060001, +0x24c6dc78, 0xc53023, 0x2603821, 0xaf42010c, +0xc001750, 0xafb10010, 0x3c040001, 0x24842fa4, +0x3c050001, 0x24a5e25c, 0x3c060001, 0x24c6e948, +0xc53023, 0x2603821, 0x3c010001, 0xac223f50, +0xc001750, 0xafb10010, 0x3c040001, 0x24842fbc, +0x10000027, 0x24052100, 0x3c040001, 0x24842fc4, 0x3c050001, 0x24a599e8, 0x3c060001, 0x24c69b24, 0xc53023, 0x27b10030, 0x2203821, 0x27b30034, -0xc001750, 0xafb30010, 0x3c040001, 0x24842f14, -0x3c050001, 0x24a5c300, 0x3c060001, 0x24c6d088, +0xc001750, 0xafb30010, 0x3c040001, 0x24842fd4, +0x3c050001, 0x24a5c3f0, 0x3c060001, 0x24c6d178, 0xc53023, 0x2203821, 0xaf42010c, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f24, 0x3c050001, -0x24a5e014, 0x3c060001, 0x24c6e16c, 0xc53023, -0x2203821, 0x3c010001, 0xac223e40, 0xc001750, -0xafb30010, 0x3c040001, 0x24842f38, 0x24052150, -0x2c03021, 0x3821, 0x3c010001, 0xac223e4c, -0xafa00010, 0xc0029d3, 0xafa00014, 0x3c030001, -0x8c633e40, 0x3c110fff, 0x3631ffff, 0x3c020001, -0x8c423e4c, 0x3c1e0800, 0x711824, 0x31882, +0xafb30010, 0x3c040001, 0x24842fe4, 0x3c050001, +0x24a5e0fc, 0x3c060001, 0x24c6e254, 0xc53023, +0x2203821, 0x3c010001, 0xac223f50, 0xc001750, +0xafb30010, 0x3c040001, 0x24842ff8, 0x24052150, +0x2c03021, 0x3821, 0x3c010001, 0xac223f5c, +0xafa00010, 0xc002a03, 0xafa00014, 0x3c030001, +0x8c633f50, 0x3c110fff, 0x3631ffff, 0x3c020001, +0x8c423f5c, 0x3c1e0800, 0x711824, 0x31882, 0x7e1825, 0x511024, 0x21082, 0x5e1025, 0xae430038, 0xae420078, 0x8c020218, 0x30420040, 0x14400004, 0x24020001, 0x3c010001, 0x370821, -0xa02240f4, 0x3c040001, 0x24842f44, 0x3c050001, -0x24a5db98, 0x3c060001, 0x24c6dcf4, 0xc53023, +0xa02240f4, 0x3c040001, 0x24843004, 0x3c050001, +0x24a5dc80, 0x3c060001, 0x24c6dddc, 0xc53023, 0x27b50030, 0x2a03821, 0x27b30034, 0xc001750, -0xafb30010, 0x3c010001, 0xac223e38, 0x511024, +0xafb30010, 0x3c010001, 0xac223f48, 0x511024, 0x21082, 0x5e1025, 0xae420050, 0x32c22000, 0x10400005, 0x2a03821, 0x3c020000, 0x24425b78, -0x1000000d, 0x511024, 0x3c040001, 0x24842f58, -0x3c050001, 0x24a5dcfc, 0x3c060001, 0x24c6deac, +0x1000000d, 0x511024, 0x3c040001, 0x24843018, +0x3c050001, 0x24a5dde4, 0x3c060001, 0x24c6df94, 0xc53023, 0xc001750, 0xafb30010, 0x3c010001, -0xac223e50, 0x511024, 0x21082, 0x5e1025, +0xac223f60, 0x511024, 0x21082, 0x5e1025, 0xae420048, 0x32c24000, 0x10400005, 0x27a70030, 0x3c020000, 0x24425b78, 0x1000000e, 0x21100, -0x3c040001, 0x24842f70, 0x3c050001, 0x24a5deb4, -0x3c060001, 0x24c6e00c, 0xc53023, 0x27a20034, -0xc001750, 0xafa20010, 0x3c010001, 0xac223e44, +0x3c040001, 0x24843030, 0x3c050001, 0x24a5df9c, +0x3c060001, 0x24c6e0f4, 0xc53023, 0x27a20034, +0xc001750, 0xafa20010, 0x3c010001, 0xac223f54, 0x21100, 0x21182, 0x3c030800, 0x431025, -0xae420060, 0x3c040001, 0x24842f88, 0x3c050000, +0xae420060, 0x3c040001, 0x24843048, 0x3c050000, 0x24a57ca0, 0x3c060001, 0x24c680c4, 0xc53023, 0x27b10030, 0x2203821, 0x27b30034, 0xc001750, 0xafb30010, 0x3c1e0fff, 0x37deffff, 0x3c040001, -0x24842f94, 0x3c050000, 0x24a56318, 0x3c060000, +0x24843054, 0x3c050000, 0x24a56318, 0x3c060000, 0x24c66478, 0xc53023, 0x2203821, 0x3c010001, -0xac223e18, 0x5e1024, 0x21082, 0x3c150800, +0xac223f28, 0x5e1024, 0x21082, 0x3c150800, 0x551025, 0xae4200b8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fa0, 0x3c050000, 0x24a56480, +0x3c040001, 0x24843060, 0x3c050000, 0x24a56480, 0x3c060000, 0x24c666f8, 0xc53023, 0x2203821, -0x3c010001, 0xac223e0c, 0x5e1024, 0x21082, +0x3c010001, 0xac223f1c, 0x5e1024, 0x21082, 0x551025, 0xae4200e8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fb8, 0x3c050000, 0x24a56700, +0x3c040001, 0x24843078, 0x3c050000, 0x24a56700, 0x3c060000, 0x24c66830, 0xc53023, 0x2203821, -0x3c010001, 0xac223e04, 0x5e1024, 0x21082, +0x3c010001, 0xac223f14, 0x5e1024, 0x21082, 0x551025, 0xae4200c0, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fd0, 0x3c050001, 0x24a5f240, -0x3c060001, 0x24c6f318, 0xc53023, 0x2203821, -0x3c010001, 0xac223e10, 0x5e1024, 0x21082, +0x3c040001, 0x24843090, 0x3c050001, 0x24a5f300, +0x3c060001, 0x24c6f3d8, 0xc53023, 0x2203821, +0x3c010001, 0xac223f20, 0x5e1024, 0x21082, 0x551025, 0xae4200c8, 0xc001750, 0xafb30010, -0x3c040001, 0x24842fdc, 0x3c050001, 0x24a5c1e0, -0x3c060001, 0x24c6c21c, 0xc53023, 0x2203821, +0x3c040001, 0x2484309c, 0x3c050001, 0x24a5c2d0, +0x3c060001, 0x24c6c30c, 0xc53023, 0x2203821, 0xaf420110, 0xc001750, 0xafb30010, 0x3c040001, -0x24842fec, 0x3c050001, 0x24a5c224, 0x3c060001, -0x24c6c24c, 0xc53023, 0x2203821, 0xaf420114, -0xc001750, 0xafb30010, 0x3c040001, 0x24842ff8, -0x3c050001, 0x24a5e9c0, 0x3c060001, 0x24c6eeac, +0x248430ac, 0x3c050001, 0x24a5c314, 0x3c060001, +0x24c6c33c, 0xc53023, 0x2203821, 0xaf420114, +0xc001750, 0xafb30010, 0x3c040001, 0x248430b8, +0x3c050001, 0x24a5eaa0, 0x3c060001, 0x24c6ef78, 0xc53023, 0x2203821, 0xaf420118, 0xc001750, -0xafb30010, 0x3c010001, 0xac223e54, 0x5e1024, -0x21082, 0x551025, 0xc003d9f, 0xae4200d0, -0xc003a1c, 0x0, 0xc002630, 0x0, +0xafb30010, 0x3c010001, 0xac223f64, 0x5e1024, +0x21082, 0x551025, 0xc003dcf, 0xae4200d0, +0xc003a54, 0x0, 0xc002630, 0x0, 0xac000228, 0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038, 0x96e20460, 0xaf420080, 0x32c24000, 0x14400003, 0x0, 0x96e20480, 0xaf420084, 0x96e70490, 0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088, 0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000, 0x10400003, 0x24020400, 0x10e2000b, -0x0, 0x240e0001, 0x3c040001, 0x24843008, +0x0, 0x240e0001, 0x3c040001, 0x248430c8, 0xa3ae003f, 0x96e60490, 0x24052170, 0x2c03821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8f43012c, +0xafa00010, 0xc002a03, 0xafa00014, 0x8f43012c, 0x8f44012c, 0x24020001, 0xa34205b3, 0xaf430094, 0xaf440098, 0xafa00010, 0xafa00014, 0x8f460080, -0x8f470084, 0x3c040001, 0x24843014, 0xc0029d3, +0x8f470084, 0x3c040001, 0x248430d4, 0xc002a03, 0x24052200, 0xc00232c, 0x3c110800, 0x3c1433d8, 0x3694cb58, 0x3c020800, 0x34420080, 0x3c040001, -0x24843020, 0x3c050000, 0x24a55bbc, 0x3c060000, +0x248430e0, 0x3c050000, 0x24a55bbc, 0x3c060000, 0x24c65bd8, 0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, 0xaf820064, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223df4, 0x21100, +0xafa20010, 0x3c010001, 0xac223f04, 0x21100, 0x21182, 0x511025, 0xc0018a8, 0xae420000, 0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 0x3c020000, 0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, 0x511024, 0x14400005, 0x3c030800, 0x8f820060, 0x431024, 0x1040fffd, 0x0, -0xc003a29, 0x8821, 0x3c020100, 0xafa20020, +0xc003a61, 0x8821, 0x3c020100, 0xafa20020, 0x8f530018, 0x240200ff, 0x56620001, 0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24842ce4, 0x3c050009, 0xafa00014, +0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, @@ -4842,21 +4843,21 @@ 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842cec, 0x3c050009, 0xafa20014, +0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24842cf4, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc0029d3, 0x2603821, +0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc002a03, 0x2603821, 0x8f4202d4, 0x24420001, 0xaf4202d4, 0x8f4202d4, 0x93a2003f, 0x10400069, 0x3c020700, 0x34423000, 0xafa20028, 0x8f530018, 0x240200ff, 0x12620002, 0x8821, 0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x24842ce4, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, 0xac4304c0, 0xac4404c4, 0xc01821, @@ -4865,19 +4866,19 @@ 0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842cec, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, -0xafa20010, 0x8f820124, 0x3c040001, 0x24842cf4, +0xafa20010, 0x8f820124, 0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, 0x8fa60028, 0x34a50300, -0xc0029d3, 0x2603821, 0x8f4202e0, 0x24420001, -0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x24843030, +0xc002a03, 0x2603821, 0x8f4202e0, 0x24420001, +0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x248430f0, 0xafa00010, 0xafa00014, 0x8fa60028, 0x24052300, -0xc0029d3, 0x3821, 0x10000004, 0x0, +0xc002a03, 0x3821, 0x10000004, 0x0, 0x8c020264, 0x10400005, 0x0, 0x8f8200a0, 0x30420004, 0x1440fffa, 0x0, 0x8f820044, 0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, @@ -4887,29 +4888,29 @@ 0x8f430138, 0x431021, 0xaf420090, 0x24020001, 0xaf42008c, 0x32c20008, 0x10400006, 0x0, 0x8f820214, 0x3c038100, 0x3042ffff, 0x431025, -0xaf820214, 0x3c020001, 0x8c423d14, 0x30420001, -0x10400009, 0x0, 0x3c040001, 0x2484303c, +0xaf820214, 0x3c020001, 0x8c423e24, 0x30420001, +0x10400009, 0x0, 0x3c040001, 0x248430fc, 0x3c050000, 0x24a56c40, 0x3c060000, 0x24c670e8, -0x10000008, 0xc53023, 0x3c040001, 0x2484304c, +0x10000008, 0xc53023, 0x3c040001, 0x2484310c, 0x3c050000, 0x24a56838, 0x3c060000, 0x24c66c38, 0xc53023, 0x27a70030, 0x27a20034, 0xc001750, -0xafa20010, 0x3c010001, 0xac223e08, 0x3c020001, -0x8c423e08, 0x3c030800, 0x21100, 0x21182, +0xafa20010, 0x3c010001, 0xac223f18, 0x3c020001, +0x8c423f18, 0x3c030800, 0x21100, 0x21182, 0x431025, 0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c, 0x8f87011c, -0x3c040001, 0x2484305c, 0x3c010001, 0xac363de0, -0x3c010001, 0xac203dd0, 0x3c010001, 0xac3c3dc8, -0x3c010001, 0xac3b3df8, 0x3c010001, 0xac373dfc, -0x3c010001, 0xac3a3ddc, 0xc0029d3, 0x24052400, +0x3c040001, 0x2484311c, 0x3c010001, 0xac363ef0, +0x3c010001, 0xac203ee0, 0x3c010001, 0xac3c3ed8, +0x3c010001, 0xac3b3f08, 0x3c010001, 0xac373f0c, +0x3c010001, 0xac3a3eec, 0xc002a03, 0x24052400, 0x8f820200, 0xafa20010, 0x8f820220, 0xafa20014, -0x8f860044, 0x8f870050, 0x3c040001, 0x24843068, -0xc0029d3, 0x24052500, 0x8f830060, 0x74100b, +0x8f860044, 0x8f870050, 0x3c040001, 0x24843128, +0xc002a03, 0x24052500, 0x8f830060, 0x74100b, 0x242000a, 0x200f821, 0x0, 0xd, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, -0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843074, +0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843134, 0x24052600, 0x3021, 0x3821, 0xafbf0018, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8fbf0018, +0xafa00010, 0xc002a03, 0xafa00014, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008, 0x0, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e00008, @@ -4918,16 +4919,16 @@ 0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018, 0xa22823, 0xa32824, 0x8ca20000, 0x1044000a, 0x0, 0xafa50010, 0x8ca20000, 0xafa20014, -0x8f860150, 0x8f870250, 0x3c040001, 0x2484307c, -0xc0029d3, 0x24052700, 0x8fbf0218, 0x3e00008, +0x8f860150, 0x8f870250, 0x3c040001, 0x2484313c, +0xc002a03, 0x24052700, 0x8fbf0218, 0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f, 0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000, 0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000, 0xaca30000, 0x10460005, 0xae040000, 0xa08021, 0xf0102b, -0x1040fff5, 0x102840, 0x3c040001, 0x24843088, +0x1040fff5, 0x102840, 0x3c040001, 0x24843148, 0x24052800, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x2001021, 0x8fbf001c, +0xc002a03, 0xafa00014, 0x2001021, 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 0x8c020224, 0x3047003f, 0x10e00010, 0x803021, 0x2821, 0x24030020, 0xe31024, 0x10400002, 0x63042, @@ -4941,84 +4942,84 @@ 0xafb00018, 0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b, 0x1440001b, 0xe08821, 0x8e330000, 0xafb00010, 0x8ea20000, 0xafa20014, 0x8e270000, -0x24053000, 0xc0029d3, 0x2403021, 0x8e230000, +0x24053000, 0xc002a03, 0x2403021, 0x8e230000, 0x702021, 0x64102b, 0x10400007, 0x2402821, 0x8ca20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24a50004, 0x8ea20000, 0x501023, 0xaea20000, 0x8e220000, 0x501021, 0x1000000b, 0xae220000, 0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000, 0x2409821, 0xafa20014, 0x8e270000, -0x24053100, 0xc0029d3, 0x2603021, 0x2601021, +0x24053100, 0xc002a03, 0x2603021, 0x2601021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 0x3c030001, -0x8c633dc0, 0x3c040001, 0x8c843dcc, 0x34a5bf08, -0x24021ffc, 0x3c010001, 0xac223c60, 0x3c0200c0, -0x3c010001, 0xac223c64, 0x3c020020, 0xafbf0010, +0x8c633ed0, 0x3c040001, 0x8c843edc, 0x34a5bf08, +0x24021ffc, 0x3c010001, 0xac223d70, 0x3c0200c0, +0x3c010001, 0xac223d74, 0x3c020020, 0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, -0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3c5c, +0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, 0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0, 0x346307b8, 0x24021dfc, 0x3c010001, -0xac223c60, 0x24021844, 0x3c010001, 0xac243c64, -0x3c010001, 0xac223c60, 0x3c010001, 0xac233c64, +0xac223d70, 0x24021844, 0x3c010001, 0xac243d74, +0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, 0xc0017ba, 0x375a0200, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843094, -0x24053200, 0x3c020001, 0x8c423c60, 0x3c030001, -0x8c633c64, 0x3021, 0x3603821, 0xafbf0030, +0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843154, +0x24053200, 0x3c020001, 0x8c423d70, 0x3c030001, +0x8c633d74, 0x3021, 0x3603821, 0xafbf0030, 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, -0xafa2001c, 0xafa30018, 0xafb70010, 0xc0029d3, +0xafa2001c, 0xafa30018, 0xafb70010, 0xc002a03, 0xafba0014, 0xc0018c2, 0x0, 0x8f820240, 0x34420004, 0xaf820240, 0x24020001, 0xaf420000, 0x3c020001, 0x571021, 0x904240f4, 0x10400092, -0x2403fffc, 0x3c100001, 0x2610a6d3, 0x3c120001, -0x2652a2ac, 0x2121023, 0x438024, 0x8fa3001c, -0x3c040001, 0x248430a0, 0x70102b, 0x1440001a, +0x2403fffc, 0x3c100001, 0x2610a79b, 0x3c120001, +0x2652a374, 0x2121023, 0x438024, 0x8fa3001c, +0x3c040001, 0x24843160, 0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, -0xafb00010, 0xafa30014, 0xc0029d3, 0x2203821, +0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, 0xae620000, 0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, -0x8fa3001c, 0x3c040001, 0x248430bc, 0x24120020, -0x3c010001, 0xac313dec, 0x2c620020, 0x1440001d, +0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, +0x8fa3001c, 0x3c040001, 0x2484317c, 0x24120020, +0x3c010001, 0xac313efc, 0x2c620020, 0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63e80, 0xafa70010, 0xafa30014, 0xc0029d3, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843e80, +0x24c63f90, 0xafa70010, 0xafa30014, 0xc002a03, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843f90, 0x24650020, 0x65102b, 0x10400007, 0x0, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103e80, 0x24053100, +0xae220000, 0x3c100001, 0x26103f90, 0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x24070020, -0x3c040001, 0x248430d0, 0x8fa3001c, 0x24120020, -0x3c010001, 0xac303e20, 0x2c620020, 0x1440001d, +0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, +0x3c040001, 0x24843190, 0x8fa3001c, 0x24120020, +0x3c010001, 0xac303f30, 0x2c620020, 0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, -0x24c63ea0, 0xafa70010, 0xafa30014, 0xc0029d3, -0x2003821, 0x8fa30018, 0x3c040001, 0x24843ea0, +0x24c63fb0, 0xafa70010, 0xafa30014, 0xc002a03, +0x2003821, 0x8fa30018, 0x3c040001, 0x24843fb0, 0x24650020, 0x65102b, 0x10400007, 0x0, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, -0xae220000, 0x3c100001, 0x26103ea0, 0x24053100, +0xae220000, 0x3c100001, 0x26103fb0, 0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, -0x2402002d, 0xc0029d3, 0xa0820000, 0x3c010001, -0x10000031, 0xac303e1c, 0x3c100000, 0x26107c8f, +0x2402002d, 0xc002a03, 0xa0820000, 0x3c010001, +0x10000031, 0xac303f2c, 0x3c100000, 0x26107c8f, 0x3c120000, 0x26527b0c, 0x2121023, 0x438024, -0x8fa3001c, 0x3c040001, 0x248430e4, 0x70102b, +0x8fa3001c, 0x3c040001, 0x248431a4, 0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, -0x2403021, 0xafb00010, 0xafa30014, 0xc0029d3, +0x2403021, 0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, 0xae620000, 0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, -0x2203021, 0x2402002d, 0xc0029d3, 0xa0820000, -0x3c010001, 0xac313dec, 0x3c030001, 0x8c633dec, +0x2203021, 0x2402002d, 0xc002a03, 0xa0820000, +0x3c010001, 0xac313efc, 0x3c030001, 0x8c633efc, 0x24020400, 0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x0, 0x8f820040, @@ -5032,17 +5033,17 @@ 0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, 0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, -0x36940040, 0x3c020001, 0x8c423d28, 0x10400027, -0x0, 0x3c020001, 0x8c423d14, 0x30420001, -0x14400010, 0x0, 0x3c020001, 0x8c423e58, -0x1040000c, 0x0, 0x3c020001, 0x8c423da4, +0x36940040, 0x3c020001, 0x8c423e38, 0x10400027, +0x0, 0x3c020001, 0x8c423e24, 0x30420001, +0x14400010, 0x0, 0x3c020001, 0x8c423f68, +0x1040000c, 0x0, 0x3c020001, 0x8c423eb4, 0x14400008, 0x0, 0x8f830224, 0x3c020001, -0x8c425f1c, 0x10620003, 0x0, 0xc003bad, +0x8c42602c, 0x10620003, 0x0, 0xc003be0, 0x0, 0x934205b1, 0x10400012, 0x24020001, 0x934305b1, 0x14620004, 0x3c0208ff, 0x24020002, 0x1000000c, 0xa34205b1, 0x3442fffb, 0xa34005b1, 0x8f830220, 0x3c040200, 0x284a025, 0x621824, -0xaf830220, 0x10000004, 0x3c020200, 0xc003f27, +0xaf830220, 0x10000004, 0x3c020200, 0xc003f57, 0x0, 0x3c020200, 0x2c21024, 0x10400003, 0x0, 0xc001de7, 0x0, 0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, @@ -5059,8 +5060,8 @@ 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24843184, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x8f820128, 0x3c040001, 0x24843248, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 0x1000005c, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0x10000027, 0xaf420038, 0x8f440160, @@ -5069,8 +5070,8 @@ 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x24843190, 0xafa20014, 0x8f46002c, 0x8f870120, -0x3c050009, 0xc0029d3, 0x34a51100, 0x10000036, +0x24843254, 0xafa20014, 0x8f46002c, 0x8f870120, +0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, @@ -5098,8 +5099,8 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x24843198, 0xafa20014, 0x8f460044, -0x8f870120, 0x3c050009, 0xc0029d3, 0x34a51300, +0x3c040001, 0x2484325c, 0xafa20014, 0x8f460044, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, 0x1000000f, 0x0, 0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 0x10000004, @@ -5111,20 +5112,20 @@ 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x3c020001, 0x8c423d28, 0x27bdffa8, +0x0, 0x3c020001, 0x8c423e38, 0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, 0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, -0x8c633d18, 0x34420002, 0xaf420004, 0x24020001, +0x8c633e28, 0x34420002, 0xaf420004, 0x24020001, 0x14620003, 0x3c020600, 0x10000002, 0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, 0x11420002, 0x1821, 0x25430001, 0x8c020228, 0x609821, 0x1662000e, 0x3c050009, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x8fa70034, 0x3c040001, 0x24843168, 0xafa00014, +0x8fa70034, 0x3c040001, 0x2484322c, 0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, @@ -5139,7 +5140,7 @@ 0x32a200ff, 0x54400018, 0xaf530018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843174, 0xafa20014, 0x8d460000, +0x3c040001, 0x24843238, 0xafa20014, 0x8d460000, 0x3c050009, 0x10000035, 0x34a50600, 0x8f4202f8, 0x24150001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, @@ -5152,8 +5153,8 @@ 0x1440ffee, 0x0, 0x32a200ff, 0x14400011, 0x3c050009, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, -0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, +0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 0x0, 0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 0x50400029, 0x36100040, 0x3c020400, 0x2c21024, 0x10400013, @@ -5176,10 +5177,10 @@ 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008, 0x0, 0x3c020001, -0x8c423d28, 0x27bdffb0, 0xafbf0048, 0xafbe0044, +0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, -0x8c843d18, 0x24430001, 0x2842000b, 0xaf4400e8, +0x8c843e28, 0x24430001, 0x2842000b, 0xaf4400e8, 0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, 0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, 0xaf420004, 0x24020001, 0x14820003, 0x3c020600, @@ -5188,7 +5189,7 @@ 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24843168, 0x3c050009, 0xafa00014, +0x3c040001, 0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, @@ -5202,7 +5203,7 @@ 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843174, 0x3c050009, +0x8f820124, 0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, 0x8f830054, @@ -5215,9 +5216,9 @@ 0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc0029d3, 0x3c03821, 0x8f4202dc, 0x24420001, +0xc002a03, 0x3c03821, 0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 0x10400033, 0x3c020400, 0x2c21024, 0x10400017, 0x0, 0x934205b0, 0x8f440240, 0x8f450244, @@ -5247,7 +5248,7 @@ 0x8f4300e8, 0x3042007f, 0xa34205b0, 0x24020001, 0x14620005, 0x0, 0x934405b0, 0x42102, 0x10000003, 0x348400f0, 0x934405b0, 0x3484000f, -0xc004b04, 0x0, 0x2402ff7f, 0x282a024, +0xc004b34, 0x0, 0x2402ff7f, 0x282a024, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, @@ -5300,7 +5301,7 @@ 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x24843168, 0x3c050009, 0xafa00014, 0xafa20010, +0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, @@ -5314,7 +5315,7 @@ 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843174, 0x3c050009, 0xafa20014, +0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, @@ -5327,13 +5328,13 @@ 0x326200ff, 0x54400012, 0x24020001, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x2484317c, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc0029d3, 0x3c03821, 0x1021, +0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, +0x34a50700, 0xc002a03, 0x3c03821, 0x1021, 0x1440005b, 0x24020001, 0x10000065, 0x0, 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x24843150, 0x3c050009, +0x8c020228, 0x3c040001, 0x24843214, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, @@ -5342,15 +5343,15 @@ 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843158, 0x3c050009, +0x8f820124, 0x3c040001, 0x2484321c, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x54400011, 0x24020001, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24843160, 0x3c050009, -0xafa20014, 0x8fa60020, 0x34a50300, 0xc0029d3, +0x8f820124, 0x3c040001, 0x24843224, 0x3c050009, +0xafa20014, 0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, 0x1021, 0x1040000d, 0x24020001, 0x8f4202d8, 0xa34005b7, 0xaf4001a0, 0x24420001, 0xaf4202d8, 0x8f4202d8, 0x8ee20150, 0x24420001, @@ -5370,11 +5371,11 @@ 0x14620005, 0x0, 0x8f430124, 0x8f8200b4, 0x10620010, 0x0, 0x8f820104, 0xaf42011c, 0x8f8200b4, 0x8f43011c, 0xaf420124, 0xafa30010, -0x8f420124, 0x3c040001, 0x248431a0, 0xafa20014, +0x8f420124, 0x3c040001, 0x24843264, 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, 0x34a50900, 0x8f42011c, 0xafa20010, 0x8f420124, -0x3c040001, 0x248431ac, 0xafa20014, 0x8f86011c, -0x8f8700b0, 0x3c050005, 0xc0029d3, 0x34a51000, +0x3c040001, 0x24843270, 0xafa20014, 0x8f86011c, +0x8f8700b0, 0x3c050005, 0xc002a03, 0x34a51000, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, 0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, @@ -5382,9 +5383,9 @@ 0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42011c, -0xafa20010, 0x8f420124, 0x3c040001, 0x248431b8, +0xafa20010, 0x8f420124, 0x3c040001, 0x2484327c, 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, -0x34a51100, 0xc0029d3, 0x0, 0x8f8200a0, +0x34a51100, 0xc002a03, 0x0, 0x8f8200a0, 0x30420004, 0x10400069, 0x0, 0x8f430120, 0x8f820124, 0x14620005, 0x0, 0x8f430128, 0x8f8200a4, 0x10620006, 0x0, 0x8f820124, @@ -5397,21 +5398,21 @@ 0x0, 0x8f430128, 0x8f8200a4, 0x10620010, 0x0, 0x8f820124, 0xaf420120, 0x8f8200a4, 0x8f430120, 0xaf420128, 0xafa30010, 0x8f420128, -0x3c040001, 0x248431c4, 0xafa20014, 0x8f86011c, +0x3c040001, 0x24843288, 0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, 0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001, -0x248431d0, 0xafa20014, 0x8f86011c, 0x8f8700a0, -0x3c050005, 0xc0029d3, 0x34a51300, 0x8f82011c, +0x24843294, 0xafa20014, 0x8f86011c, 0x8f8700a0, +0x3c050005, 0xc002a03, 0x34a51300, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, 0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, 0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, -0x24c63e14, 0x40f809, 0x24070004, 0x8f82011c, +0x24c63f24, 0x40f809, 0x24070004, 0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, -0xafa20010, 0x8f420128, 0x3c040001, 0x248431dc, +0xafa20010, 0x8f420128, 0x3c040001, 0x248432a0, 0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, -0x34a51400, 0xc0029d3, 0x0, 0x8fbf0020, +0x34a51400, 0xc002a03, 0x0, 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, 0x3c060080, 0x3c050100, 0x8f820070, 0x481024, 0x1040fffd, 0x0, 0x8f820054, 0x24420005, @@ -5479,8 +5480,8 @@ 0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048, 0x30c20001, 0x10400004, 0x24020001, 0xaf820064, 0x10000063, 0x0, 0x30c20002, 0x1440000b, -0x3c050003, 0x3c040001, 0x248432a4, 0x34a50500, -0x3821, 0xafa00010, 0xc0029d3, 0xafa00014, +0x3c050003, 0x3c040001, 0x24843364, 0x34a50500, +0x3821, 0xafa00010, 0xc002a03, 0xafa00014, 0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c, 0x8c02010c, 0x12020047, 0x101080, 0x8c450300, 0x26020001, 0x3050003f, 0x24020003, 0xac10022c, @@ -5508,29 +5509,29 @@ 0x808021, 0x101602, 0x2442ffff, 0x304300ff, 0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c, -0x31080, 0x3c010001, 0x220821, 0x8c2232e8, +0x31080, 0x3c010001, 0x220821, 0x8c2233a8, 0x400008, 0x0, 0x101302, 0x30440fff, 0x24020001, 0x10820005, 0x24020002, 0x1082000a, 0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, -0x3c020001, 0x8c423e40, 0xaf4401f0, 0xaf4401f4, +0x3c020001, 0x8c423f50, 0xaf4401f0, 0xaf4401f4, 0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0, -0xaf4401f4, 0x621824, 0x3c020001, 0x2442c254, +0xaf4401f4, 0x621824, 0x3c020001, 0x2442c344, 0x21100, 0x21182, 0xaf430004, 0x3c030800, 0x431025, 0x3c010000, 0xac224138, 0x8f840054, 0x41442, 0x41c82, 0x431021, 0x41cc2, 0x431023, 0x41d02, 0x431021, 0x41d42, 0x431023, 0x10000009, 0xaf4201f8, 0x3c040001, -0x248432b0, 0x34a51000, 0x2003021, 0x3821, -0xafa00010, 0xc0029d3, 0xafa00014, 0x8f420290, +0x24843370, 0x34a51000, 0x2003021, 0x3821, +0xafa00010, 0xc002a03, 0xafa00014, 0x8f420290, 0x24420001, 0xaf420290, 0x10000215, 0x8f420290, -0x27b00028, 0x2002021, 0x24050210, 0xc002a57, +0x27b00028, 0x2002021, 0x24050210, 0xc002a87, 0x24060008, 0xc0023a0, 0x2002021, 0x1000020c, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c, 0xafa50028, 0xc0023a0, 0xafa3002c, 0x100001fc, 0x0, 0x27b00028, 0x2002021, 0x24050210, -0xc002a57, 0x24060008, 0xc0024df, 0x2002021, +0xc002a87, 0x24060008, 0xc0024df, 0x2002021, 0x100001f3, 0x0, 0x8c06022c, 0x27a40028, 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, @@ -5550,8 +5551,8 @@ 0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009, -0x2c2b024, 0x3c040001, 0x248432bc, 0x34a51100, -0x2003021, 0x3821, 0xafa00010, 0xc0029d3, +0x2c2b024, 0x3c040001, 0x2484337c, 0x34a51100, +0x2003021, 0x3821, 0xafa00010, 0xc002a03, 0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc, 0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff, 0x24020001, 0x10a20005, 0x24020002, 0x10a2000d, @@ -5560,24 +5561,24 @@ 0x621824, 0x34630008, 0xaf830220, 0x10000012, 0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220, -0x10000009, 0xaf450288, 0x3c040001, 0x248432c8, +0x10000009, 0xaf450288, 0x3c040001, 0x24843388, 0x34a51200, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x8f4202ac, 0x24420001, +0xc002a03, 0xafa00014, 0x8f4202ac, 0x24420001, 0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208, -0x24050200, 0xc002a57, 0x24060008, 0x27440214, -0x24050200, 0xc002a57, 0x24060008, 0x8f4202b4, +0x24050200, 0xc002a87, 0x24060008, 0x27440214, +0x24050200, 0xc002a87, 0x24060008, 0x8f4202b4, 0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4, 0x101302, 0x30430fff, 0x24020001, 0x10620011, 0x28620002, 0x50400005, 0x24020002, 0x10600007, 0x0, 0x10000017, 0x0, 0x1062000f, 0x0, 0x10000013, 0x0, 0x8c060248, -0x2021, 0xc004878, 0x24050004, 0x10000007, -0x0, 0x8c060248, 0x2021, 0xc004878, +0x2021, 0xc0048a8, 0x24050004, 0x10000007, +0x0, 0x8c060248, 0x2021, 0xc0048a8, 0x24050004, 0x10000010, 0x0, 0x8c06024c, -0x2021, 0xc004878, 0x24050001, 0x1000000a, -0x0, 0x3c040001, 0x248432d4, 0x3c050003, +0x2021, 0xc0048a8, 0x24050001, 0x1000000a, +0x0, 0x3c040001, 0x24843394, 0x3c050003, 0x34a51300, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x8f4202b0, 0x24420001, +0xc002a03, 0xafa00014, 0x8f4202b0, 0x24420001, 0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022b4, 0x0, 0x10000132, 0x0, 0x24020001, 0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c, @@ -5590,7 +5591,7 @@ 0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, -0x8f42032c, 0x8c020228, 0x3c040001, 0x2484326c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x2484332c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, @@ -5605,7 +5606,7 @@ 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x24843278, 0x3c050009, 0xafa20014, 0x8d460000, +0x24843338, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, @@ -5617,26 +5618,26 @@ 0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, -0xafa20010, 0x8f820124, 0x3c040001, 0x24843280, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843340, 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc0029d3, 0x3c03821, 0x8f4202a0, 0x24420001, +0xc002a03, 0x3c03821, 0x8f4202a0, 0x24420001, 0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001, 0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, -0x24060008, 0xc002a57, 0xaf4201e8, 0x8f820220, +0x24060008, 0xc002a87, 0xaf4201e8, 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 0x24020002, 0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c, 0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff, 0x2021824, 0x32c20180, 0x14400006, 0x3402fffb, 0x43102b, 0x14400003, 0x0, 0x1000006c, -0xaf4300bc, 0x3c040001, 0x248432e0, 0x3c050003, +0xaf4300bc, 0x3c040001, 0x248433a0, 0x3c050003, 0x34a51500, 0x2003021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x3c020700, 0x34421000, +0xc002a03, 0xafa00014, 0x3c020700, 0x34421000, 0x101e02, 0x621825, 0xafa30020, 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, -0x3c040001, 0x24843254, 0x3c050009, 0xafa00014, +0x3c040001, 0x24843314, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, @@ -5645,15 +5646,15 @@ 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 0x822021, 0x100f809, 0x892021, 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x2484325c, 0x3c050009, 0xafa20014, +0x3c040001, 0x2484331c, 0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 0x0, 0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, -0x3c040001, 0x24843264, 0x3c050009, 0xafa20014, -0x8fa60020, 0x34a50300, 0xc0029d3, 0x2203821, +0x3c040001, 0x24843324, 0x3c050009, 0xafa20014, +0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, 0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0, 0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, @@ -5673,21 +5674,21 @@ 0x431024, 0x34420004, 0xaf820200, 0x8f53034c, 0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014, 0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0, -0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a40, +0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a70, 0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354, 0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4, 0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8, -0x24020006, 0xc002a57, 0xaf4201e4, 0x3c023b9a, +0x24020006, 0xc002a87, 0xaf4201e4, 0x3c023b9a, 0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002, 0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c, 0x8f820220, 0x30420008, 0x10400004, 0x0, 0xaf430288, 0x10000003, 0x3021, 0xaf440288, -0x3021, 0x3c030001, 0x661821, 0x90633c80, +0x3021, 0x3c030001, 0x661821, 0x90633d90, 0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f, 0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040, 0x24040080, 0x24050080, 0x21702, 0x24420030, -0xa062021c, 0x3461021, 0xc002a40, 0xa040021c, +0xa062021c, 0x3461021, 0xc002a70, 0xa040021c, 0x8fa7001c, 0x30e20004, 0x14400006, 0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006, @@ -5739,15 +5740,15 @@ 0x10c00014, 0x610c0, 0x571821, 0x3c010001, 0x230821, 0x8c2334d0, 0x571021, 0xafa30010, 0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, -0x248433f0, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc0029d3, 0x34a50400, 0x10000063, +0x248434b4, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc002a03, 0x34a50400, 0x10000063, 0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, 0x2e21021, 0x3c010001, 0x220821, 0x942234d0, 0xaf420100, 0xa03021, 0x14c00011, 0x628c0, 0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, -0x220821, 0x942230d0, 0x3c040001, 0x248433fc, +0x220821, 0x942230d0, 0x3c040001, 0x248434c0, 0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, -0xc0029d3, 0x34a50500, 0x10000048, 0x3c020800, +0xc002a03, 0x34a50500, 0x10000048, 0x3c020800, 0xb71821, 0x3c020001, 0x96040000, 0x344234d2, 0x621821, 0xa4640000, 0x8e020002, 0x720c0, 0xac620002, 0x2e41021, 0x3c030001, 0x621821, @@ -5770,7 +5771,7 @@ 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, -0x8c020228, 0x3c040001, 0x248433b8, 0x3c050009, +0x8c020228, 0x3c040001, 0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, @@ -5784,7 +5785,7 @@ 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x248433c4, +0xafa20010, 0x8f820124, 0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, @@ -5797,8 +5798,8 @@ 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x248433cc, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, +0x8f820124, 0x3c040001, 0x24843490, 0x3c050009, +0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4, 0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, @@ -5818,8 +5819,8 @@ 0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, 0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, 0x3c010001, 0x220821, 0x942230d0, 0x3c040001, -0x24843408, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc0029d3, 0x34a50900, 0x10000075, +0x248434cc, 0xafa20014, 0x8e260000, 0x8e270004, +0x3c050004, 0xc002a03, 0x34a50900, 0x10000075, 0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, 0x3c030001, 0x621821, 0x946334d0, 0x710c0, 0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, @@ -5854,7 +5855,7 @@ 0xafab0034, 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x248433b8, 0x3c050009, 0xafa00014, 0xafa20010, +0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, @@ -5868,7 +5869,7 @@ 0x0, 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, -0x3c040001, 0x248433c4, 0x3c050009, 0xafa20014, +0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, 0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, @@ -5881,14 +5882,14 @@ 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x248433cc, 0x3c050009, 0xafa20014, 0x8d660000, -0x34a50700, 0xc0029d3, 0x3c03821, 0x8f4202a8, +0x24843490, 0x3c050009, 0xafa20014, 0x8d660000, +0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a8, 0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4, 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 0x0, 0x0, 0x0, 0x27bdffe0, -0x27644000, 0xafbf0018, 0xc002a40, 0x24051000, +0x27644000, 0xafbf0018, 0xc002a70, 0x24051000, 0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, 0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, @@ -5897,15 +5898,15 @@ 0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, 0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, 0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, -0x3c040001, 0x248434d0, 0x3c050001, 0x34420001, +0x3c040001, 0x24843590, 0x3c050001, 0x34420001, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x34a50100, 0xc0029d3, 0x3821, 0x8c020218, +0x34a50100, 0xc002a03, 0x3821, 0x8c020218, 0x30420040, 0x10400014, 0x0, 0x8f82011c, -0x3c040001, 0x248434dc, 0x3c050001, 0x34420004, +0x3c040001, 0x2484359c, 0x3c050001, 0x34420004, 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x10000007, 0x34a50200, 0x3c040001, 0x248434e4, +0x10000007, 0x34a50200, 0x3c040001, 0x248435a4, 0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, -0xc0029d3, 0x3821, 0x8fbf0018, 0x3e00008, +0xc002a03, 0x3821, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, 0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, 0x24680020, 0x27684800, 0x8f820128, 0x11020004, @@ -5962,189 +5963,201 @@ 0xad0b0010, 0xaf890100, 0x10000006, 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0xaf430328, 0x8f430328, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x27bdffd8, 0x3c040001, 0x248434ec, +0x0, 0x27bdffd8, 0x3c040001, 0x248435ac, 0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, 0x2403021, 0x2203821, -0xafa20010, 0xc0029d3, 0xafb00014, 0x8e020008, -0xafa20010, 0x8e02000c, 0x3c040001, 0x248434f8, +0xafa20010, 0xc002a03, 0xafb00014, 0x8e020008, +0xafa20010, 0x8e02000c, 0x3c040001, 0x248435b8, 0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001, -0xc0029d3, 0x34a52510, 0x8e020018, 0xafa20010, -0x8e02001c, 0x3c040001, 0x24843504, 0xafa20014, -0x8e060010, 0x8e070014, 0x3c050001, 0xc0029d3, -0x34a52520, 0x3c030200, 0x2c31024, 0x1040000d, +0xc002a03, 0x34a52510, 0x8e020018, 0xafa20010, +0x8e02001c, 0x3c040001, 0x248435c4, 0xafa20014, +0x8e060010, 0x8e070014, 0x3c050001, 0xc002a03, +0x34a52520, 0x3c027f00, 0x2221024, 0x3c030800, +0x54430016, 0x3c030200, 0x8f82009c, 0x3042ffff, +0x14400012, 0x3c030200, 0x3c040001, 0x248435d0, +0x3c050002, 0x34a5f030, 0x3021, 0x3821, +0x36420002, 0xaf82011c, 0x36220001, 0xaf8200b0, +0xaf900104, 0xaf92011c, 0xafa00010, 0xc002a03, +0xafa00014, 0x10000024, 0x0, 0x2c31024, +0x1040000d, 0x2231024, 0x1040000b, 0x36420002, +0xaf82011c, 0x36220001, 0xaf8200b0, 0xaf900104, +0xaf92011c, 0x8f420320, 0x24420001, 0xaf420320, +0x10000015, 0x8f420320, 0x3c040001, 0x248435d8, +0x240202a2, 0xafa20010, 0xafa00014, 0x8f860144, +0x3c070001, 0x24e735e0, 0xc002a03, 0x3405dead, +0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, +0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, +0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, +0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, +0x27bdffd8, 0x3c040001, 0x24843608, 0x3c050001, +0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, +0x8f900124, 0x8f9100a0, 0x8f92011c, 0x34a52600, +0x8f820120, 0x2403021, 0x2203821, 0xafa20010, +0xc002a03, 0xafb00014, 0x8e020008, 0xafa20010, +0x8e02000c, 0x3c040001, 0x24843614, 0xafa20014, +0x8e060000, 0x8e070004, 0x3c050001, 0xc002a03, +0x34a52610, 0x8e020018, 0xafa20010, 0x8e02001c, +0x3c040001, 0x24843620, 0xafa20014, 0x8e060010, +0x8e070014, 0x3c050001, 0xc002a03, 0x34a52620, +0x3c027f00, 0x2221024, 0x3c030800, 0x54430016, +0x3c030200, 0x8f8200ac, 0x3042ffff, 0x14400012, +0x3c030200, 0x3c040001, 0x2484362c, 0x3c050001, +0x34a5f030, 0x3021, 0x3821, 0x36420002, +0xaf82011c, 0x36220001, 0xaf8200a0, 0xaf900124, +0xaf92011c, 0xafa00010, 0xc002a03, 0xafa00014, +0x10000024, 0x0, 0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, 0x36420002, 0xaf82011c, -0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, -0x8f420320, 0x24420001, 0xaf420320, 0x10000015, -0x8f420320, 0x3c040001, 0x24843510, 0x24020290, +0x36220001, 0xaf8200a0, 0xaf900124, 0xaf92011c, +0x8f42031c, 0x24420001, 0xaf42031c, 0x10000015, +0x8f42031c, 0x3c040001, 0x248435d8, 0x240202db, 0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001, -0x24e73518, 0xc0029d3, 0x3405dead, 0x8f82011c, +0x24e735e0, 0xc002a03, 0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0028, 0x27bdffd8, -0x3c040001, 0x24843540, 0x3c050001, 0xafbf0024, -0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900124, -0x8f9100a0, 0x8f92011c, 0x34a52600, 0x8f820120, -0x2403021, 0x2203821, 0xafa20010, 0xc0029d3, -0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, -0x3c040001, 0x2484354c, 0xafa20014, 0x8e060000, -0x8e070004, 0x3c050001, 0xc0029d3, 0x34a52610, -0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, -0x24843558, 0xafa20014, 0x8e060010, 0x8e070014, -0x3c050001, 0xc0029d3, 0x34a52620, 0x3c030200, -0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, -0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, -0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001, -0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001, -0x24843510, 0x240202bc, 0xafa20010, 0xafa00014, -0x8f860144, 0x3c070001, 0x24e73518, 0xc0029d3, -0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, -0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, -0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, -0x27bd0028, 0x6021, 0x5021, 0x3021, -0x2821, 0x6821, 0x4821, 0x7821, -0x7021, 0x8f880124, 0x8f870104, 0x1580002e, -0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, -0x10460029, 0x0, 0x3c040001, 0x8c843e20, -0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, -0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, -0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c843e20, 0x8d020000, 0x8d030004, -0xac820000, 0xac830004, 0x8d020008, 0xac820008, -0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, -0xac820014, 0x27624fe0, 0x43102b, 0x54400001, -0x27634800, 0x603021, 0x1540002f, 0x31620100, -0x11200014, 0x31628000, 0x8f820100, 0x1045002a, -0x31620100, 0x3c040001, 0x8c843e1c, 0x8ca20000, -0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, -0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, -0x24a50020, 0x10400018, 0x31620100, 0x3c040001, -0x8c843e1c, 0x8ce20000, 0x8ce30004, 0xac820000, -0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, -0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, -0x276247e0, 0x43102b, 0x54400001, 0x27634000, -0x602821, 0x31620100, 0x5440001d, 0x31621000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, -0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, -0x8f880124, 0x6821, 0x11800011, 0x31621000, -0x3c040001, 0x8c843e20, 0x8c820000, 0x8c830004, -0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, -0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, -0x1440ff82, 0x0, 0x1120000f, 0x31220800, -0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1221024, 0x10400004, 0x24e20020, -0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, -0x8f870104, 0x4821, 0x1140ff70, 0x0, -0x3c040001, 0x8c843e1c, 0x8c820000, 0x8c830004, -0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, -0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, -0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, -0x3e00008, 0x0, 0x6021, 0x5821, -0x3021, 0x2821, 0x6821, 0x5021, -0x7821, 0x7021, 0x8f880124, 0x8f870104, -0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, -0x31220800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c843e20, 0x8cc20000, 0x8cc30004, +0x8fb00018, 0x3e00008, 0x27bd0028, 0x6021, +0x5021, 0x3021, 0x2821, 0x6821, +0x4821, 0x7821, 0x7021, 0x8f880124, +0x8f870104, 0x1580002e, 0x8f8b011c, 0x11a00014, +0x31620800, 0x8f820120, 0x10460029, 0x0, +0x3c040001, 0x8c843f30, 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, -0x10400017, 0x0, 0x3c040001, 0x8c843e20, +0x10400017, 0x0, 0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, 0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, 0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, 0x43102b, 0x54400001, 0x27634800, 0x603021, -0x1560002f, 0x31220100, 0x11400014, 0x31228000, -0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, -0x8c843e1c, 0x8ca20000, 0x8ca30004, 0xac820000, +0x1540002f, 0x31620100, 0x11200014, 0x31628000, +0x8f820100, 0x1045002a, 0x31620100, 0x3c040001, +0x8c843f2c, 0x8ca20000, 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, -0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, +0xa482000e, 0x8ca20010, 0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, -0x31220100, 0x3c040001, 0x8c843e1c, 0x8ce20000, +0x31620100, 0x3c040001, 0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, -0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, +0x24e50020, 0xac820010, 0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31220100, -0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, +0x54400001, 0x27634000, 0x602821, 0x31620100, +0x5440001d, 0x31621000, 0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 0x8f880124, 0x6821, -0x11800011, 0x31221000, 0x3c040001, 0x8c843e20, +0x11800011, 0x31621000, 0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, -0x8c8f0014, 0x31221000, 0x14400022, 0x0, -0x1140000f, 0x31420800, 0x10400004, 0x3c020002, -0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, +0x8c8f0014, 0x31621000, 0x1440ff82, 0x0, +0x1120000f, 0x31220800, 0x10400004, 0x3c020002, +0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1221024, 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x5021, -0x11600010, 0x0, 0x3c040001, 0x8c843e1c, +0x24e20020, 0xaf820104, 0x8f870104, 0x4821, +0x1140ff70, 0x0, 0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, -0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, -0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, -0x1040ff5c, 0x0, 0x8f820054, 0x24420005, -0xaf820078, 0x8c040234, 0x10800016, 0x1821, -0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, -0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, -0x571021, 0x8c4240e8, 0x44102b, 0x14400009, -0x24020001, 0x3c030080, 0x3c010001, 0x370821, -0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, -0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, -0x14400006, 0x3c020080, 0x3c020001, 0x571021, -0x904240f1, 0x10400002, 0x3c020080, 0x621825, -0x8c040230, 0x10800013, 0x0, 0x3c020001, -0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, -0x370821, 0xac2240ec, 0x3c020001, 0x571021, -0x8c4240ec, 0x44102b, 0x14400006, 0x0, -0x3c010001, 0x370821, 0xac2040ec, 0x10000006, -0x781825, 0x3c020001, 0x571021, 0x904240f2, -0x54400001, 0x781825, 0x1060ff1a, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x431025, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x1000ff05, -0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, -0x0, 0x0, 0x0, 0x3c020001, -0x8c423ca8, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26103ec0, 0x2002021, -0xc002a40, 0x24052000, 0x26021fe0, 0x3c010001, -0xac223e28, 0x3c010001, 0xac223e24, 0xac020250, +0x8c820010, 0x5021, 0xaf8200b0, 0x8c890010, +0x1000ff60, 0x8c8e0014, 0x3e00008, 0x0, +0x6021, 0x5821, 0x3021, 0x2821, +0x6821, 0x5021, 0x7821, 0x7021, +0x8f880124, 0x8f870104, 0x3c180100, 0x1580002e, +0x8f89011c, 0x11a00014, 0x31220800, 0x8f820120, +0x10460029, 0x0, 0x3c040001, 0x8c843f30, +0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, +0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, +0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, +0x10000012, 0x24c60020, 0x10400017, 0x0, +0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, +0xac820000, 0xac830004, 0x8d020008, 0xac820008, +0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, +0xac820010, 0x8d020014, 0x240c0001, 0xc01821, +0xac820014, 0x27624fe0, 0x43102b, 0x54400001, +0x27634800, 0x603021, 0x1560002f, 0x31220100, +0x11400014, 0x31228000, 0x8f820100, 0x1045002a, +0x31220100, 0x3c040001, 0x8c843f2c, 0x8ca20000, +0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, +0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, +0x240b0001, 0xac820010, 0x8ca20014, 0x10000012, +0x24a50020, 0x10400018, 0x31220100, 0x3c040001, +0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, +0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, +0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, +0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, +0x276247e0, 0x43102b, 0x54400001, 0x27634000, +0x602821, 0x31220100, 0x5440001d, 0x31221000, +0x11a00009, 0x31a20800, 0x10400004, 0x25020020, +0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, +0x8f880124, 0x6821, 0x11800011, 0x31221000, +0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, +0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, +0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, +0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31221000, +0x14400022, 0x0, 0x1140000f, 0x31420800, +0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, +0x3c020002, 0x1421024, 0x10400004, 0x24e20020, +0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, +0x8f870104, 0x5021, 0x11600010, 0x0, +0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, +0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, +0x9482000e, 0xaf82009c, 0x8c820010, 0x5821, +0xaf8200b0, 0x8c8a0010, 0x8c8e0014, 0x8f820070, +0x3c031000, 0x431024, 0x1040ff5c, 0x0, +0x8f820054, 0x24420005, 0xaf820078, 0x8c040234, +0x10800016, 0x1821, 0x3c020001, 0x571021, +0x8c4240e8, 0x24420005, 0x3c010001, 0x370821, +0xac2240e8, 0x3c020001, 0x571021, 0x8c4240e8, +0x44102b, 0x14400009, 0x24020001, 0x3c030080, +0x3c010001, 0x370821, 0xac2040e8, 0x3c010001, +0x370821, 0x1000000c, 0xa02240f0, 0x3c020001, +0x571021, 0x904240f0, 0x14400006, 0x3c020080, +0x3c020001, 0x571021, 0x904240f1, 0x10400002, +0x3c020080, 0x621825, 0x8c040230, 0x10800013, +0x0, 0x3c020001, 0x571021, 0x8c4240ec, +0x24420005, 0x3c010001, 0x370821, 0xac2240ec, +0x3c020001, 0x571021, 0x8c4240ec, 0x44102b, +0x14400006, 0x0, 0x3c010001, 0x370821, +0xac2040ec, 0x10000006, 0x781825, 0x3c020001, +0x571021, 0x904240f2, 0x54400001, 0x781825, +0x1060ff1a, 0x0, 0x8f420000, 0x10400007, +0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, +0x0, 0x10000005, 0x0, 0xaf800048, +0x8f820048, 0x1040fffd, 0x0, 0x8f820060, +0x431025, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x1000ff05, 0xaf80004c, 0x1000ff03, +0xaf800048, 0x3e00008, 0x0, 0x3c020001, +0x8c423db8, 0x27bdffe8, 0xafbf0014, 0x14400012, +0xafb00010, 0x3c100001, 0x26103fd0, 0x2002021, +0xc002a70, 0x24052000, 0x26021fe0, 0x3c010001, +0xac223f38, 0x3c010001, 0xac223f34, 0xac020250, 0x24022000, 0xac100254, 0xac020258, 0x24020001, -0x3c010001, 0xac223ca8, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e28, +0x3c010001, 0xac223db8, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293f38, 0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, 0x8c820004, 0xad250008, 0xad220004, 0x8f820054, 0xad260010, 0xad270014, 0xad230018, 0xad28001c, -0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423ec0, +0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423fd0, 0x122102b, 0x10400003, 0x0, 0x3c090001, -0x8d293e24, 0x3c020001, 0x8c423c90, 0xad220000, -0x3c020001, 0x8c423c90, 0x3c010001, 0xac293e28, +0x8d293f34, 0x3c020001, 0x8c423da0, 0xad220000, +0x3c020001, 0x8c423da0, 0x3c010001, 0xac293f38, 0xad220004, 0xac090250, 0x3e00008, 0x0, -0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e28, -0x3c020001, 0x8c423c90, 0xafb10014, 0x808821, +0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103f38, +0x3c020001, 0x8c423da0, 0xafb10014, 0x808821, 0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, 0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, -0xae020000, 0x3c020001, 0x8c423c90, 0xc09821, +0xae020000, 0x3c020001, 0x8c423da0, 0xc09821, 0xe0a821, 0x10800006, 0xae020004, 0x26050008, -0xc002a4b, 0x24060018, 0x10000005, 0x2610ffe0, -0x26040008, 0xc002a40, 0x24050018, 0x2610ffe0, -0x3c030001, 0x24633ec0, 0x203102b, 0x10400003, -0x0, 0x3c100001, 0x8e103e24, 0x8e220000, +0xc002a7b, 0x24060018, 0x10000005, 0x2610ffe0, +0x26040008, 0xc002a70, 0x24050018, 0x2610ffe0, +0x3c030001, 0x24633fd0, 0x203102b, 0x10400003, +0x0, 0x3c100001, 0x8e103f34, 0x8e220000, 0xae020000, 0x8e220004, 0xae120008, 0xae020004, 0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, 0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, 0x203102b, 0x10400003, 0x0, 0x3c100001, -0x8e103e24, 0x3c020001, 0x8c423c90, 0xae020000, -0x3c020001, 0x8c423c90, 0x3c010001, 0xac303e28, +0x8e103f34, 0x3c020001, 0x8c423da0, 0xae020000, +0x3c020001, 0x8c423da0, 0x3c010001, 0xac303f38, 0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, 0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, @@ -6186,7 +6199,7 @@ 0x27bdffc0, 0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030, 0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028, 0x10000002, 0x0, 0x8f530020, -0x8f420030, 0x105300e4, 0x21100, 0x8f43001c, +0x8f420030, 0x105300eb, 0x21100, 0x8f43001c, 0x628021, 0x8e040000, 0x8e050004, 0x96120008, 0x8f420090, 0x9611000a, 0x3246ffff, 0x46102a, 0x10400017, 0x0, 0x8f8200d8, 0x8f430098, @@ -6194,9 +6207,9 @@ 0x2842fff9, 0x10400005, 0x0, 0x8f420090, 0x8f430138, 0x431021, 0xaf420090, 0x8f420090, 0x46102a, 0x10400006, 0x0, 0x8f420338, -0x24420001, 0xaf420338, 0x100000da, 0x8f420338, +0x24420001, 0xaf420338, 0x100000e1, 0x8f420338, 0x8f8200fc, 0x14400006, 0x32c20008, 0x8f420334, -0x24420001, 0xaf420334, 0x100000d2, 0x8f420334, +0x24420001, 0xaf420334, 0x100000d9, 0x8f420334, 0x5040000c, 0xaf4000ac, 0x934205b3, 0x10400008, 0x32220200, 0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, 0x21400, 0x10000002, 0xaf4200b0, @@ -6205,7 +6218,7 @@ 0x24020004, 0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, 0x3c030002, 0x431025, 0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, 0x0, -0x104000b0, 0x0, 0x8f42009c, 0x8f430094, +0x104000b7, 0x0, 0x8f42009c, 0x8f430094, 0x2421021, 0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008, 0x3c034000, 0x8f420094, 0x431025, 0xafa20020, 0x8f42009c, 0x8f4300b0, 0x10000004, @@ -6232,123 +6245,124 @@ 0x8f420090, 0x8f430094, 0x862024, 0x441023, 0x65182b, 0x14600005, 0xaf420090, 0x8f420094, 0x8f430138, 0x431023, 0xaf420094, 0x8f420094, -0x10000023, 0xaf40009c, 0x3247ffff, 0x10e00021, -0x0, 0x14400002, 0x24020010, 0x24020002, +0x10000023, 0xaf40009c, 0x3247ffff, 0x50e00022, +0x32c20020, 0x14400002, 0x24020010, 0x24020002, 0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, -0x0, 0x10400033, 0x3245ffff, 0x8f420098, +0x0, 0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090, 0x8f460130, 0x451021, 0xaf420098, 0x8f42009c, 0x8f440098, 0xa34005b3, 0x651823, 0xaf430090, 0x451021, 0x86202b, 0x14800005, 0xaf42009c, 0x8f420098, 0x8f430138, 0x431023, -0xaf420098, 0x8f420030, 0x8f430040, 0x24420001, -0x2463ffff, 0x431024, 0xaf420030, 0x8f420030, -0x14530018, 0x0, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x2403fff7, 0x431024, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x8fbf0038, 0x8fb30034, 0x8fb20030, -0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0040, -0x3e00008, 0x0, 0x27bdffd0, 0x32c20020, -0xafbf002c, 0xafb20028, 0xafb10024, 0x10400004, -0xafb00020, 0x8f520028, 0x10000002, 0x0, -0x8f520020, 0x8f420030, 0x105200b5, 0x21100, -0x8f43001c, 0x628021, 0x8e040000, 0x8e050004, -0x96110008, 0x8f420090, 0x9607000a, 0x3226ffff, -0x46102a, 0x10400017, 0x0, 0x8f8200d8, -0x8f430098, 0x431023, 0x2442ff80, 0xaf420090, -0x8f420090, 0x2842ff81, 0x10400005, 0x0, -0x8f420090, 0x8f430138, 0x431021, 0xaf420090, -0x8f420090, 0x46102a, 0x10400006, 0x0, -0x8f420338, 0x24420001, 0xaf420338, 0x100000ab, -0x8f420338, 0x8f8600fc, 0x10c0000c, 0x0, -0x8f8200f4, 0x2403fff8, 0x431024, 0x461023, -0x218c3, 0x50600001, 0x24030100, 0x8f42008c, -0x43102b, 0x14400006, 0x712c2, 0x8f420334, -0x24420001, 0xaf420334, 0x10000098, 0x8f420334, -0x934305b3, 0x1060000f, 0x30460001, 0x8f420010, -0x34480400, 0x32c20008, 0x10400008, 0x30e20200, -0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, -0x21400, 0x10000004, 0xaf4200b0, 0x10000002, -0xaf4000ac, 0x8f480010, 0x30e20004, 0x10400045, -0x3227ffff, 0x8f4900ac, 0x11200005, 0x30c200ff, -0x14400006, 0x24020040, 0x10000004, 0x24020008, -0x14400002, 0x24020020, 0x24020004, 0xafa20010, -0x8f430030, 0x11200004, 0xafa30014, 0x8f4200b0, -0x621025, 0xafa20014, 0x3c020002, 0x1021025, -0xafa20018, 0x8f460098, 0x8f420108, 0x40f809, -0x0, 0x10400069, 0x3224ffff, 0x8f42008c, -0x8f430094, 0x24420001, 0xaf42008c, 0x24020001, -0xae03000c, 0xa34205b3, 0x8f420098, 0x2406fff8, -0x8f450130, 0x441021, 0x24420007, 0x461024, -0x24840007, 0xaf420094, 0x8f420090, 0x8f430094, -0x862024, 0x441023, 0x65182b, 0x14600005, -0xaf420090, 0x8f420094, 0x8f430138, 0x431023, -0xaf420094, 0x8f430094, 0x8f420134, 0x43102b, -0x10400009, 0x0, 0x8f430130, 0x8f440094, -0x8f420090, 0x8f45012c, 0x641823, 0x431023, -0xaf420090, 0xaf450094, 0x8f420094, 0x1000001f, -0xaf420098, 0x10e0001d, 0x30c200ff, 0x14400002, -0x24020010, 0x24020002, 0xafa20010, 0x8f420030, -0xafa80018, 0xafa20014, 0x8f460098, 0x8f420108, -0x40f809, 0x0, 0x10400030, 0x3225ffff, -0x8f420098, 0x8f440130, 0x451021, 0xaf420098, -0x8f420090, 0x8f430098, 0xa34005b3, 0x451023, -0x64182b, 0x14600005, 0xaf420090, 0x8f420098, -0x8f430138, 0x431023, 0xaf420098, 0x8f420030, -0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf420030, 0x8f420030, 0x14520018, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x2403fff7, 0x431024, -0xaf820060, 0x8f420000, 0x10400003, 0x0, -0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, -0x27bd0030, 0x3e00008, 0x0, 0x27bdffd8, -0x3c020001, 0x34422ec0, 0xafbf0020, 0x8f4300f0, -0x8f840108, 0x2e21021, 0x54620004, 0x24620008, -0x3c020001, 0x34422cc0, 0x2e21021, 0x401821, -0xaf4300f0, 0xac600000, 0x8f4200ec, 0x8c660004, -0x14620004, 0x3c020001, 0x24820020, 0x1000000f, -0xaf820108, 0x8f4300f0, 0x34422ec0, 0x2e21021, -0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, -0x2e21021, 0x401821, 0x8c620004, 0x21140, -0x821021, 0xaf820108, 0xac600000, 0x8c850018, -0x30a20036, 0x1040006c, 0x30a20001, 0x8c82001c, -0x8f430040, 0x8f440034, 0x24420001, 0x2463ffff, -0x431024, 0x862021, 0xaf42002c, 0x30a20030, -0x14400006, 0xaf440034, 0x8f420034, 0x8c03023c, -0x43102b, 0x144000c9, 0x0, 0x32c20010, -0x10400028, 0x24070008, 0x8f440160, 0x8f450164, -0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020080, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x24020001, -0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x24843800, -0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51100, 0x10000036, 0x0, -0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, -0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, -0xaf430038, 0x8f440160, 0x8f450164, 0x8f43002c, -0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, +0xaf420098, 0x32c20020, 0x10400005, 0x0, +0x8f420348, 0x2442ffff, 0xaf420348, 0x8f420348, +0x8f420030, 0x8f430040, 0x24420001, 0x2463ffff, +0x431024, 0xaf420030, 0x8f420030, 0x14530018, +0x0, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x2403fff7, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, +0x8fb00028, 0x3e00008, 0x27bd0040, 0x3e00008, +0x0, 0x27bdffd0, 0x32c20020, 0xafbf002c, +0xafb20028, 0xafb10024, 0x10400004, 0xafb00020, +0x8f520028, 0x10000002, 0x0, 0x8f520020, +0x8f420030, 0x105200b5, 0x21100, 0x8f43001c, +0x628021, 0x8e040000, 0x8e050004, 0x96110008, +0x8f420090, 0x9607000a, 0x3226ffff, 0x46102a, +0x10400017, 0x0, 0x8f8200d8, 0x8f430098, +0x431023, 0x2442ff80, 0xaf420090, 0x8f420090, +0x2842ff81, 0x10400005, 0x0, 0x8f420090, +0x8f430138, 0x431021, 0xaf420090, 0x8f420090, +0x46102a, 0x10400006, 0x0, 0x8f420338, +0x24420001, 0xaf420338, 0x100000ab, 0x8f420338, +0x8f8600fc, 0x10c0000c, 0x0, 0x8f8200f4, +0x2403fff8, 0x431024, 0x461023, 0x218c3, +0x50600001, 0x24030100, 0x8f42008c, 0x43102b, +0x14400006, 0x712c2, 0x8f420334, 0x24420001, +0xaf420334, 0x10000098, 0x8f420334, 0x934305b3, +0x1060000f, 0x30460001, 0x8f420010, 0x34480400, +0x32c20008, 0x10400008, 0x30e20200, 0x10400006, +0x3c034000, 0x9602000e, 0xaf4300ac, 0x21400, +0x10000004, 0xaf4200b0, 0x10000002, 0xaf4000ac, +0x8f480010, 0x30e20004, 0x10400045, 0x3227ffff, +0x8f4900ac, 0x11200005, 0x30c200ff, 0x14400006, +0x24020040, 0x10000004, 0x24020008, 0x14400002, +0x24020020, 0x24020004, 0xafa20010, 0x8f430030, +0x11200004, 0xafa30014, 0x8f4200b0, 0x621025, +0xafa20014, 0x3c020002, 0x1021025, 0xafa20018, +0x8f460098, 0x8f420108, 0x40f809, 0x0, +0x10400069, 0x3224ffff, 0x8f42008c, 0x8f430094, +0x24420001, 0xaf42008c, 0x24020001, 0xae03000c, +0xa34205b3, 0x8f420098, 0x2406fff8, 0x8f450130, +0x441021, 0x24420007, 0x461024, 0x24840007, +0xaf420094, 0x8f420090, 0x8f430094, 0x862024, +0x441023, 0x65182b, 0x14600005, 0xaf420090, +0x8f420094, 0x8f430138, 0x431023, 0xaf420094, +0x8f430094, 0x8f420134, 0x43102b, 0x10400009, +0x0, 0x8f430130, 0x8f440094, 0x8f420090, +0x8f45012c, 0x641823, 0x431023, 0xaf420090, +0xaf450094, 0x8f420094, 0x1000001f, 0xaf420098, +0x10e0001d, 0x30c200ff, 0x14400002, 0x24020010, +0x24020002, 0xafa20010, 0x8f420030, 0xafa80018, +0xafa20014, 0x8f460098, 0x8f420108, 0x40f809, +0x0, 0x10400030, 0x3225ffff, 0x8f420098, +0x8f440130, 0x451021, 0xaf420098, 0x8f420090, +0x8f430098, 0xa34005b3, 0x451023, 0x64182b, +0x14600005, 0xaf420090, 0x8f420098, 0x8f430138, +0x431023, 0xaf420098, 0x8f420030, 0x8f430040, +0x24420001, 0x2463ffff, 0x431024, 0xaf420030, +0x8f420030, 0x14520018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403fff7, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf002c, 0x8fb20028, +0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030, +0x3e00008, 0x0, 0x27bdffd8, 0x3c020001, +0x34422ec0, 0xafbf0020, 0x8f4300f0, 0x8f840108, +0x2e21021, 0x54620004, 0x24620008, 0x3c020001, +0x34422cc0, 0x2e21021, 0x401821, 0xaf4300f0, +0xac600000, 0x8f4200ec, 0x8c660004, 0x14620004, +0x3c020001, 0x24820020, 0x1000000f, 0xaf820108, +0x8f4300f0, 0x34422ec0, 0x2e21021, 0x54620004, +0x24620008, 0x3c020001, 0x34422cc0, 0x2e21021, +0x401821, 0x8c620004, 0x21140, 0x821021, +0xaf820108, 0xac600000, 0x8c850018, 0x30a20036, +0x1040006c, 0x30a20001, 0x8c82001c, 0x8f430040, +0x8f440034, 0x24420001, 0x2463ffff, 0x431024, +0x862021, 0xaf42002c, 0x30a20030, 0x14400006, +0xaf440034, 0x8f420034, 0x8c03023c, 0x43102b, +0x144000c6, 0x0, 0x32c20010, 0x10400028, +0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, +0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, -0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x248437f4, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, -0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, -0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, -0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, -0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, -0xaf400034, 0x8f420304, 0x24420001, 0xaf420304, -0x1000006e, 0x8f420304, 0x10400025, 0x30a27000, -0x8c85001c, 0x8f420028, 0xa22023, 0x4810003, -0x0, 0x8f420040, 0x822021, 0x8f420348, -0x8f430000, 0x441021, 0xaf420348, 0x8f42035c, -0xaf450028, 0x441021, 0x10600007, 0xaf42035c, +0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, +0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, +0x34a51100, 0x10000036, 0x0, 0x8f4202f0, +0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, +0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, +0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, +0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, +0x1000000f, 0x0, 0x8f4202f0, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, +0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, +0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, +0x8f420304, 0x24420001, 0xaf420304, 0x1000006b, +0x8f420304, 0x10400022, 0x30a27000, 0x8c85001c, +0x8f420028, 0xa22023, 0x4810003, 0x0, +0x8f420040, 0x822021, 0x8f420348, 0x8f430000, +0xaf450028, 0x441021, 0x10600007, 0xaf420348, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 0x34420008, @@ -6367,7 +6381,7 @@ 0x441021, 0xaf420358, 0x3c020800, 0x2c21024, 0x5040001a, 0x36940040, 0x10000018, 0x0, 0x30a20100, 0x10400015, 0x0, 0x3c020001, -0x8c423c54, 0x1040000c, 0x0, 0x274301b0, +0x8c423d64, 0x1040000c, 0x0, 0x274301b0, 0x24650400, 0x65102b, 0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, @@ -6376,7 +6390,7 @@ 0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, 0x8f910108, 0x26220020, 0xaf820108, 0x8e320018, -0xa821, 0x32420024, 0x104001b1, 0xf021, +0xa821, 0x32420024, 0x104001b7, 0xf021, 0x8e26001c, 0x8f42001c, 0x61900, 0x431021, 0x8c50000c, 0x9603000c, 0x962d0016, 0x9453000a, 0x2c6205dd, 0x10400015, 0x2821, 0x32c20040, @@ -6400,8 +6414,8 @@ 0x431021, 0x904c0009, 0x318900ff, 0x39230006, 0x3182b, 0x39220011, 0x2102b, 0x621824, 0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, -0x24843810, 0xafa20010, 0x8f4200a0, 0x34a54600, -0x1203821, 0xc0029d3, 0xafa20014, 0x1000004e, +0x248438f4, 0xafa20010, 0x8f4200a0, 0x34a54600, +0x1203821, 0xc002a03, 0xafa20014, 0x1000004e, 0x0, 0x32c20004, 0x14400013, 0x2821, 0x316200ff, 0x14400004, 0x0, 0x95020002, 0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, @@ -6429,7 +6443,7 @@ 0x8f4200b4, 0x24430001, 0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, 0x220821, -0xac2438ec, 0x100000a5, 0xaf40009c, 0x10400064, +0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064, 0x0, 0x8f4200b4, 0x24430001, 0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, @@ -6463,41 +6477,44 @@ 0xaf450264, 0x92020000, 0x30420001, 0x1440000c, 0x2402ffff, 0x8f420268, 0x8f43026c, 0x24630001, 0x2c640001, 0x441021, 0xaf420268, 0xaf43026c, -0x8f420268, 0x8f43026c, 0x1000001c, 0xaf40009c, +0x8f420268, 0x8f43026c, 0x1000001c, 0x32c20020, 0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004, 0x1462000c, 0x0, 0x8f420278, 0x8f43027c, 0x24630001, 0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, 0x8f420278, 0x8f43027c, 0x1000000b, -0xaf40009c, 0x8f420270, 0x8f430274, 0x24630001, +0x32c20020, 0x8f420270, 0x8f430274, 0x24630001, 0x2c640001, 0x441021, 0xaf420270, 0xaf430274, -0x8f420270, 0x8f430274, 0xaf40009c, 0x8e22001c, +0x8f420270, 0x8f430274, 0x32c20020, 0x10400005, +0xaf40009c, 0x8f420348, 0x2442ffff, 0xaf420348, +0x8f420348, 0x8e22001c, 0x8f430040, 0x24420001, +0x2463ffff, 0x431024, 0xaf42002c, 0x32420060, +0x14400008, 0x32c20010, 0x8f420034, 0x24420001, +0xaf420034, 0x8c03023c, 0x43102b, 0x14400114, +0x32c20010, 0x10400018, 0x24070008, 0x8f440160, +0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, +0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, +0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047, +0x24020001, 0x8f4202f0, 0x8f43002c, 0x24420001, +0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, +0x1000007c, 0xaf430038, 0x8f440160, 0x8f450164, +0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020, +0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, +0x40f809, 0x24c6001c, 0x10400057, 0x24020001, +0x10000065, 0x0, 0x32420012, 0x10400075, +0x32420001, 0x9622000e, 0x8f43009c, 0x621821, +0x32c20020, 0x10400005, 0xaf43009c, 0x8f420348, +0x2442ffff, 0xaf420348, 0x8f420348, 0x8e22001c, 0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf42002c, 0x32420060, 0x14400008, 0x32c20010, +0xaf42002c, 0x32420010, 0x14400008, 0x32c20010, 0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c, -0x43102b, 0x14400111, 0x32c20010, 0x10400018, -0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, -0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, -0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x10400041, 0x24020001, 0x8f4202f0, -0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, -0x24020001, 0xa34205b2, 0x10000076, 0xaf430038, -0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, -0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x10400051, 0x24020001, 0x1000005f, 0x0, -0x32420012, 0x1040006f, 0x32420001, 0x9623000e, -0x8f42009c, 0x431021, 0xaf42009c, 0x8e23001c, -0x8f420040, 0x24630001, 0x2442ffff, 0x621824, -0x32420010, 0x14400008, 0xaf43002c, 0x8f420034, -0x24420001, 0xaf420034, 0x8c03023c, 0x43102b, -0x144000d2, 0x0, 0x32c20010, 0x10400028, +0x43102b, 0x144000ce, 0x32c20010, 0x10400028, 0x24070008, 0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24843800, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029d3, +0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, +0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, @@ -6506,46 +6523,45 @@ 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248437f4, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc0029d3, 0x34a50900, +0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, -0x8f420304, 0x24420001, 0xaf420304, 0x10000077, -0x8f420304, 0x10400025, 0x32427000, 0x8e25001c, +0x8f420304, 0x24420001, 0xaf420304, 0x10000074, +0x8f420304, 0x10400022, 0x32427000, 0x8e25001c, 0x8f420028, 0xa22023, 0x4810003, 0x0, 0x8f420040, 0x822021, 0x8f420348, 0x8f430000, -0x441021, 0xaf420348, 0x8f42035c, 0xaf450028, -0x441021, 0x10600007, 0xaf42035c, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420008, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000053, -0xaf80004c, 0x10000051, 0xaf800048, 0x1040002f, -0x32421000, 0x1040000c, 0x32424000, 0x8e23001c, -0x8f420050, 0x622023, 0x4820001, 0x24840200, -0x8f42034c, 0x441021, 0xaf42034c, 0x8f420358, -0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000, -0x8e23001c, 0x8f420070, 0x622023, 0x4820001, -0x24840400, 0x8f420354, 0x441021, 0xaf420354, -0x8f420358, 0x1000000d, 0xaf430070, 0x1040000e, -0x3c020800, 0x8e23001c, 0x8f420060, 0x622023, -0x4820001, 0x24840100, 0x8f420350, 0x441021, -0xaf420350, 0x8f420358, 0xaf430060, 0x441021, -0xaf420358, 0x3c020800, 0x2c21024, 0x50400023, -0x36940040, 0x10000021, 0x0, 0x32420048, -0x10400007, 0x24150001, 0x8e22001c, 0x3c03ffff, -0x43f024, 0x3042ffff, 0x1000fd81, 0xae22001c, -0x32420100, 0x10400015, 0x0, 0x3c020001, -0x8c423c54, 0x1040000c, 0x0, 0x274301b0, -0x24650400, 0x65102b, 0x10400007, 0x26e40028, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, -0x24420001, 0xaf4202cc, 0x8f4202cc, 0x8fbf0050, -0x8fbe004c, 0x8fb50048, 0x8fb30044, 0x8fb20040, -0x8fb1003c, 0x8fb00038, 0x3e00008, 0x27bd0058, -0x3e00008, 0x0, 0x0, 0x8f8600e4, +0xaf450028, 0x441021, 0x10600007, 0xaf420348, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x34420008, +0xaf820060, 0x8f420000, 0x10400003, 0x0, +0x10000053, 0xaf80004c, 0x10000051, 0xaf800048, +0x1040002f, 0x32421000, 0x1040000c, 0x32424000, +0x8e23001c, 0x8f420050, 0x622023, 0x4820001, +0x24840200, 0x8f42034c, 0x441021, 0xaf42034c, +0x8f420358, 0x1000001a, 0xaf430050, 0x1040000c, +0x32c28000, 0x8e23001c, 0x8f420070, 0x622023, +0x4820001, 0x24840400, 0x8f420354, 0x441021, +0xaf420354, 0x8f420358, 0x1000000d, 0xaf430070, +0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060, +0x622023, 0x4820001, 0x24840100, 0x8f420350, +0x441021, 0xaf420350, 0x8f420358, 0xaf430060, +0x441021, 0xaf420358, 0x3c020800, 0x2c21024, +0x50400023, 0x36940040, 0x10000021, 0x0, +0x32420048, 0x10400007, 0x24150001, 0x8e22001c, +0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd78, +0xae22001c, 0x32420100, 0x10400015, 0x0, +0x3c020001, 0x8c423d64, 0x1040000c, 0x0, +0x274301b0, 0x24650400, 0x65102b, 0x10400007, +0x26e40028, 0x8c820000, 0xac620000, 0x24630004, +0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, +0xa34005b6, 0x24420001, 0xaf4202cc, 0x8f4202cc, +0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, +0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, +0x27bd0058, 0x3e00008, 0x0, 0x8f8600e4, 0x8f8200e0, 0x2403fff8, 0x431024, 0x10c20007, 0x803821, 0x8cc20000, 0x8cc30004, 0xace20000, 0xace30004, 0x10000002, 0x24020001, 0x1021, @@ -6601,8 +6617,8 @@ 0x10400014, 0x307000ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 0x8f4201d8, 0x8faa007c, 0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 0x34a50800, 0x12000010, 0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c, 0x3c020080, 0x34420100, 0x1621024, 0x10400005, 0x0, @@ -6624,22 +6640,22 @@ 0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, 0x1000023f, 0x8f420340, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 0x34a52250, 0x1000022f, 0x0, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x24020002, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, +0x248439e4, 0x24020002, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 0x34a52450, 0x1000021f, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, -0xafbe0014, 0x8ea70018, 0x34a52800, 0xc0029d3, +0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, +0xafbe0014, 0x8ea70018, 0x34a52800, 0xc002a03, 0x603021, 0x10000213, 0x0, 0xa6b1000a, -0x8f820124, 0x3c040001, 0x24843920, 0xafbe0014, +0x8f820124, 0x3c040001, 0x24843a04, 0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007, -0xc0029d3, 0x34a53000, 0x10000206, 0x0, +0xc002a03, 0x34a53000, 0x10000206, 0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124, 0x3c040001, -0x2484392c, 0xafbe0014, 0xafa20010, 0x8f460044, -0x8f870120, 0x3c050007, 0xc0029d3, 0x34a53200, +0x24843a10, 0xafbe0014, 0xafa20010, 0x8f460044, +0x8f870120, 0x3c050007, 0xc002a03, 0x34a53200, 0x100001f8, 0x0, 0x8f420084, 0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001, 0x2c21024, 0x10400004, 0x0, 0x240b0002, 0xafab005c, @@ -6650,17 +6666,17 @@ 0x3403ecc0, 0xafab004c, 0x27c20001, 0x304201ff, 0xafa20054, 0x1e1140, 0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001, -0x248438dc, 0xafaa0014, 0xafa20010, 0x8f460054, -0x8f470050, 0x3c050007, 0xc0029d3, 0x34a51300, +0x248439c0, 0xafaa0014, 0xafa20010, 0x8f460054, +0x8f470050, 0x3c050007, 0xc002a03, 0x34a51300, 0x8f430340, 0x2402ffbf, 0x282a024, 0x24630001, 0xaf430340, 0x100001c3, 0x8f420340, 0x1562001d, 0x0, 0x8f430074, 0x8f420070, 0x1062000a, 0x274a0074, 0x8f5e0074, 0xafaa004c, 0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140, 0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, 0x8fab006c, -0x3c040001, 0x248438e8, 0x3c050007, 0xafab0014, +0x3c040001, 0x248439cc, 0x3c050007, 0xafab0014, 0xafa20010, 0x8f460074, 0x8f470070, 0x34a51500, -0x240a0001, 0xc0029d3, 0xafaa005c, 0x1000ffc3, +0x240a0001, 0xc002a03, 0xafaa005c, 0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, 0x1062001a, 0x274b0064, 0x8f5e0064, 0x8faa005c, 0xafab004c, 0x27c20001, 0x304200ff, 0xafa20054, 0x24020004, @@ -6669,8 +6685,8 @@ 0x8faa006c, 0x4a102b, 0x10400024, 0x25750020, 0x240b0001, 0x10000021, 0xa3ab0097, 0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, -0x3c040001, 0x248438f4, 0xafaa0014, 0xafa20010, -0x8f460064, 0x8f470060, 0x3c050007, 0xc0029d3, +0x3c040001, 0x248439d8, 0xafaa0014, 0xafa20010, +0x8f460064, 0x8f470060, 0x3c050007, 0xc002a03, 0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff34, 0x0, 0x8f420360, 0x240b0001, 0xafab005c, 0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, @@ -6691,9 +6707,9 @@ 0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011, 0x24030001, 0x10000015, 0x306200ff, 0x8faa0064, 0x96070018, -0xafaa0010, 0x8e220008, 0x3c040001, 0x2484390c, +0xafaa0010, 0x8e220008, 0x3c040001, 0x248439f0, 0x8c430004, 0x8c420000, 0x34a52400, 0x2403021, -0xc0029d3, 0xafa30014, 0x1000002b, 0x0, +0xc002a03, 0xafa30014, 0x1000002b, 0x0, 0x8f420324, 0x1821, 0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, 0x5040fedc, 0x3c020800, 0x12600021, 0x9021, 0x8fb100a4, 0x2208021, @@ -6745,9 +6761,9 @@ 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, +0xafa20010, 0x8f820128, 0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51300, 0x1000000b, 0x0, +0xc002a03, 0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, @@ -6787,14 +6803,14 @@ 0xa7a00076, 0x10400007, 0xa7a0007e, 0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4, 0x10000129, 0xafab006c, 0x8f420114, 0x40f809, 0x27a40020, -0x304200ff, 0x1040029c, 0x0, 0x8fac0024, +0x304200ff, 0x1040029a, 0x0, 0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc, 0xafa20064, 0x3c020006, 0x2c21024, 0x14400015, 0xafac006c, 0x93c20000, 0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b, 0x0, 0xc002343, 0x3c02021, 0x304200ff, 0x14400006, 0x0, 0x8f420118, -0x40f809, 0x0, 0x1000027f, 0x0, +0x40f809, 0x0, 0x1000027d, 0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, 0x10000040, 0x8021, 0x3c020080, 0x621024, @@ -6817,13 +6833,13 @@ 0x10400015, 0x320200ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 0x8f4201d8, 0x8fac006c, 0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010, 0x8f8200e4, -0x24100001, 0x3c040001, 0x248438d0, 0xafa20014, -0x8fa60020, 0x8fa70024, 0x3c050007, 0xc0029d3, +0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, +0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 0x34a53600, 0x320200ff, 0x10400010, 0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, 0x8fab006c, 0x3c020080, 0x34420100, 0x1621024, 0x10400005, 0x0, 0x8f4201fc, 0x24420001, 0xaf4201fc, -0x8f4201fc, 0x10000201, 0x8fa30064, 0x32c20400, +0x8f4201fc, 0x100001ff, 0x8fa30064, 0x32c20400, 0x10400012, 0x34028100, 0x97c3000c, 0x1462000f, 0x0, 0x240c0200, 0xa7ac0076, 0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064, 0x8fc50000, @@ -6843,56 +6859,56 @@ 0x2c420001, 0x621825, 0x10600004, 0x3c020100, 0x94820002, 0x453821, 0x3c020100, 0x2c21024, 0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, -0x3c050007, 0x3c040001, 0x24843938, 0x8fa60064, -0x34a54000, 0xafa00010, 0xc0029d3, 0xafa00014, +0x3c050007, 0x3c040001, 0x24843a1c, 0x8fa60064, +0x34a54000, 0xafa00010, 0xc002a03, 0xafa00014, 0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, 0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, 0x10400034, 0x240b0003, 0x32c21000, 0x10400031, 0xafab005c, 0x1000002e, 0x240c0004, 0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, -0x10000175, 0x8f420340, 0x3c020800, 0x2c2b025, +0x10000173, 0x8f420340, 0x3c020800, 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x24843900, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc0029d3, -0x34a55300, 0x10000164, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x24843918, 0xafb00010, -0xafb20014, 0x8ea70018, 0x34a55900, 0xc0029d3, -0x603021, 0x10000158, 0x0, 0x8f420084, +0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, +0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, +0x34a55300, 0x10000162, 0x0, 0x8ea20000, +0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, +0xafb10014, 0x8ea70018, 0x34a55900, 0xc002a03, +0x603021, 0x10000156, 0x0, 0x8f420084, 0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, 0x2c21024, 0x10400004, 0x0, 0x240c0002, -0xafac005c, 0x8fab0064, 0x11600168, 0x27ac0020, +0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020, 0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, 0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, -0x274b0054, 0x8f520054, 0x3403ecc0, 0xafab004c, -0x26420001, 0x304201ff, 0xafa20054, 0x121140, +0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, +0x26220001, 0x304201ff, 0xafa20054, 0x111140, 0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, -0x8fac0064, 0x3c040001, 0x248438dc, 0xafac0014, +0x8fac0064, 0x3c040001, 0x248439c0, 0xafac0014, 0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, -0xc0029d3, 0x34a54300, 0x8f430340, 0x2402ffbf, -0x282a024, 0x24630001, 0xaf430340, 0x10000126, +0xc002a03, 0x34a54300, 0x8f430340, 0x2402ffbf, +0x282a024, 0x24630001, 0xaf430340, 0x10000124, 0x8f420340, 0x156c001d, 0x0, 0x8f430074, -0x8f420070, 0x1062000a, 0x274b0074, 0x8f520074, -0xafab004c, 0x26420001, 0x304203ff, 0xafa20054, -0x121140, 0x24426cc0, 0x1000004a, 0x2e2a821, -0x8f420044, 0x8fac0064, 0x3c040001, 0x248438e8, +0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, +0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, +0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, +0x8f420044, 0x8fac0064, 0x3c040001, 0x248439cc, 0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, -0x8f470070, 0x34a54500, 0x240b0001, 0xc0029d3, +0x8f470070, 0x34a54500, 0x240b0001, 0xc002a03, 0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, -0x8f420060, 0x1062001a, 0x274c0064, 0x8f520064, -0x8fab005c, 0xafac004c, 0x26420001, 0x304200ff, -0xafa20054, 0x24020004, 0x1562000e, 0x121140, -0x121180, 0x24420cc0, 0x2e21021, 0xafa20044, +0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, +0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, +0xafa20054, 0x24020004, 0x1562000e, 0x111140, +0x111180, 0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, 0x10400024, 0x25950020, 0x240c0001, 0x10000021, 0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, -0x8f420044, 0x8fab0064, 0x3c040001, 0x248438f4, +0x8f420044, 0x8fab0064, 0x3c040001, 0x248439d8, 0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, -0x3c050007, 0xc0029d3, 0x34a54800, 0x3c020008, +0x3c050007, 0xc002a03, 0x34a54800, 0x3c020008, 0x2c21024, 0x1440ff61, 0x0, 0x8f420360, 0x240c0001, 0xafac005c, 0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, 0x27a30036, 0x131040, 0x621821, 0x94620000, 0x441021, 0x1000001f, -0xa4620000, 0xaebe0018, 0x93a20087, 0x10400086, +0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084, 0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, 0x25620020, 0xafa20028, 0x25620008, 0xafa20030, 0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, @@ -6906,289 +6922,288 @@ 0x431023, 0x21943, 0x58600001, 0x24630040, 0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, -0x1000001a, 0x306200ff, 0x8fac008c, 0x111040, -0x4c1021, 0x94470018, 0x111080, 0x4c1021, -0xafbe0010, 0x8c420008, 0x3c040001, 0x2484390c, +0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, +0x4c1021, 0x94470018, 0x101080, 0x4c1021, +0xafbe0010, 0x8c420008, 0x3c040001, 0x248439f0, 0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, -0x2203021, 0xc0029d3, 0xafa30014, 0x1000003b, +0x2003021, 0xc002a03, 0xafa30014, 0x10000039, 0x0, 0x8f420324, 0x1821, 0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, 0x1040ff06, -0x8821, 0x8f430008, 0x2402fbff, 0x621824, -0x605021, 0x1260002d, 0xaf430008, 0x2669ffff, -0x8fb0008c, 0x3c0b4000, 0x24b4025, 0x2009021, -0x8e420008, 0x96070018, 0x8c440000, 0x8c450004, -0x56290004, 0x240b0001, 0x240c0002, 0x10000002, -0xafac0010, 0xafab0010, 0x16200004, 0xafa80014, -0x8f420008, 0x10000002, 0xafa20018, 0xafaa0018, -0x8f42010c, 0x3c03021, 0xafa80098, 0xafa9009c, -0x40f809, 0xafaa00a0, 0x8fa80098, 0x8fa9009c, -0x8faa00a0, 0x1040ffc0, 0x3c02001f, 0x96030018, -0x3442ffff, 0x3c3f021, 0x5e102b, 0x10400003, -0x26100002, 0x8f42013c, 0x3c2f023, 0x26310001, -0x233102b, 0x1440ffda, 0x26520004, 0x8fb00064, -0x1000001a, 0x0, 0x96a3000a, 0x8fb00064, -0x70102b, 0x54400001, 0x608021, 0x8ea40000, -0x8ea50004, 0x8fab005c, 0x240c0002, 0xafac0010, -0x934305b5, 0xb1700, 0x10600003, 0x2423025, -0x3c020800, 0xc23025, 0xafa60014, 0x8f420008, -0xafa20018, 0x8f42010c, 0x3c03021, 0x40f809, -0x2003821, 0x1040fec9, 0x3c050007, 0x97ac0076, -0x11800007, 0x96a3000e, 0x934205b5, 0x14400004, -0x0, 0x97ab007e, 0x6c1825, 0xa6ab0016, -0x8fac006c, 0x3c02ffff, 0x1821024, 0x10400003, -0xc1402, 0x34630400, 0xa6a20014, 0xa6b0000a, -0x8fab0064, 0x560b0006, 0x3d0f021, 0x34620004, -0xafa00064, 0xa6a2000e, 0x1000000d, 0xa34005b5, -0x8fac0064, 0x3c02001f, 0x3442ffff, 0x5e102b, -0x1906023, 0xafac0064, 0xa6a3000e, 0x240b0001, -0x10400003, 0xa34b05b5, 0x8f42013c, 0x3c2f023, -0x8fab0054, 0x8fac004c, 0xad8b0000, 0x8fac0064, -0x1580feb8, 0x0, 0x8fab0064, 0x1160001b, -0x0, 0x934205b5, 0x10400006, 0x0, -0xaf5e00c4, 0xaf4b00c0, 0x8fac006c, 0x1000000e, -0xaf4c00c8, 0x97ab0076, 0x1160000b, 0x34038100, -0x8fa20020, 0x8c46000c, 0xa443000c, 0x97ac007e, -0x8c440004, 0x8c450008, 0xa44c000e, 0xac440000, -0xac450004, 0xac460008, 0x8f42033c, 0x24420001, -0xaf42033c, 0x10000010, 0x8f42033c, 0x8fab006c, -0x3164ffff, 0x2484fffc, 0x801821, 0x8f440240, -0x8f450244, 0x8f460118, 0x1021, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0xaf440240, -0xc0f809, 0xaf450244, 0x8fbf00c0, 0x8fbe00bc, -0x8fb500b8, 0x8fb300b4, 0x8fb200b0, 0x8fb100ac, -0x8fb000a8, 0x3e00008, 0x27bd00c8, 0x3e00008, -0x0, 0x27bdffd8, 0xafbf0024, 0xafb00020, -0x8f43004c, 0x8f420048, 0x10620034, 0x0, -0x8f430048, 0x8f42004c, 0x622023, 0x4820001, -0x24840200, 0x8f430054, 0x8f42004c, 0x43102b, -0x14400004, 0x24020200, 0x8f43004c, 0x10000005, -0x431023, 0x8f420054, 0x8f43004c, 0x431023, -0x2442ffff, 0x405021, 0x8a102a, 0x54400001, -0x805021, 0x8f49004c, 0x8f48004c, 0x8f440178, -0x8f45017c, 0x8f46004c, 0x24071000, 0xafa70010, -0x84140, 0x1001821, 0x12a4821, 0x313001ff, -0xafb00014, 0x8f470014, 0x1021, 0x63140, -0xafa70018, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0x3402ecc0, 0xc23021, 0x8f420108, -0x2e63021, 0x40f809, 0xa3940, 0x54400001, -0xaf50004c, 0x8f43004c, 0x8f420048, 0x14620018, +0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, +0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c, +0x2669ffff, 0x2209021, 0x8e420008, 0x96270018, +0x8c440000, 0x8c450004, 0x56090004, 0x240b0001, +0x240c0002, 0x10000002, 0xafac0010, 0xafab0010, +0x16000004, 0xafa80014, 0x8f420008, 0x10000002, +0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021, +0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0, +0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2, +0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021, +0x5e102b, 0x10400003, 0x26310002, 0x8f42013c, +0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda, +0x26520004, 0x8fb00064, 0x1000001a, 0x0, +0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001, +0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c, +0x240c0002, 0xafac0010, 0x934305b5, 0xb1700, +0x10600003, 0x2223025, 0x3c020800, 0xc23025, +0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c, +0x3c03021, 0x40f809, 0x2003821, 0x1040fecb, +0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e, +0x934205b5, 0x14400004, 0x0, 0x97ab007e, +0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff, +0x1821024, 0x10400003, 0xc1402, 0x34630400, +0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006, +0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e, +0x1000000d, 0xa34005b5, 0x8fac0064, 0x3c02001f, +0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064, +0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05b5, +0x8f42013c, 0x3c2f023, 0x8fab0054, 0x8fac004c, +0xad8b0000, 0x8fac0064, 0x1580feba, 0x0, +0x8fab0064, 0x1160001b, 0x0, 0x934205b5, +0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0, +0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076, +0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, +0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008, +0xa44c000e, 0xac440000, 0xac450004, 0xac460008, +0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, +0x8f42033c, 0x8fab006c, 0x3164ffff, 0x2484fffc, +0x801821, 0x8f440240, 0x8f450244, 0x8f460118, +0x1021, 0xa32821, 0xa3382b, 0x822021, +0x872021, 0xaf440240, 0xc0f809, 0xaf450244, +0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, +0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008, +0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8, +0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048, +0x10620034, 0x0, 0x8f430048, 0x8f42004c, +0x622023, 0x4820001, 0x24840200, 0x8f430054, +0x8f42004c, 0x43102b, 0x14400004, 0x24020200, +0x8f43004c, 0x10000005, 0x431023, 0x8f420054, +0x8f43004c, 0x431023, 0x2442ffff, 0x405021, +0x8a102a, 0x54400001, 0x805021, 0x8f49004c, +0x8f48004c, 0x8f440178, 0x8f45017c, 0x8f46004c, +0x24071000, 0xafa70010, 0x84140, 0x1001821, +0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014, +0x1021, 0x63140, 0xafa70018, 0xa32821, +0xa3382b, 0x822021, 0x872021, 0x3402ecc0, +0xc23021, 0x8f420108, 0x2e63021, 0x40f809, +0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c, +0x8f420048, 0x14620018, 0x0, 0x8f420000, +0x10400007, 0x0, 0xaf80004c, 0x8f82004c, +0x1040fffd, 0x0, 0x10000005, 0x0, +0xaf800048, 0x8f820048, 0x1040fffd, 0x0, +0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, +0x8f420000, 0x10400003, 0x0, 0x10000002, +0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x3e00008, 0x0, +0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c, +0x8f420058, 0x10620049, 0x0, 0x8f430058, +0x8f42005c, 0x622023, 0x4820001, 0x24840100, +0x8f430064, 0x8f42005c, 0x43102b, 0x14400004, +0x24020100, 0x8f43005c, 0x10000005, 0x431023, +0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff, +0x403821, 0x87102a, 0x54400001, 0x803821, +0x8f42005c, 0x471021, 0x305000ff, 0x32c21000, +0x10400015, 0x24082000, 0x8f49005c, 0x8f440180, +0x8f450184, 0x8f46005c, 0x73980, 0xafa80010, +0xafb00014, 0x8f480014, 0x94980, 0x1201821, +0x1021, 0xa32821, 0xa3482b, 0x822021, +0x892021, 0x63180, 0xafa80018, 0x8f420108, +0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440180, +0x8f450184, 0x8f46005c, 0x73940, 0xafa80010, +0xafb00014, 0x8f480014, 0x94940, 0x1201821, +0x1021, 0xa32821, 0xa3482b, 0x822021, +0x892021, 0x63140, 0xafa80018, 0x8f420108, +0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001, +0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018, 0x0, 0x8f420000, 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403fdff, +0x1040fffd, 0x0, 0x8f820060, 0x2403feff, 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049, -0x0, 0x8f430058, 0x8f42005c, 0x622023, -0x4820001, 0x24840100, 0x8f430064, 0x8f42005c, -0x43102b, 0x14400004, 0x24020100, 0x8f43005c, -0x10000005, 0x431023, 0x8f420064, 0x8f43005c, -0x431023, 0x2442ffff, 0x403821, 0x87102a, -0x54400001, 0x803821, 0x8f42005c, 0x471021, -0x305000ff, 0x32c21000, 0x10400015, 0x24082000, -0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, -0x73980, 0xafa80010, 0xafb00014, 0x8f480014, -0x94980, 0x1201821, 0x1021, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x63180, -0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0, -0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, -0x73940, 0xafa80010, 0xafb00014, 0x8f480014, -0x94940, 0x1201821, 0x1021, 0xa32821, -0xa3482b, 0x822021, 0x892021, 0x63140, -0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809, -0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c, -0x8f420058, 0x14620018, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403feff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c, -0x8f420068, 0x10620033, 0x0, 0x8f430068, -0x8f42006c, 0x622023, 0x4820001, 0x24840400, -0x8f430074, 0x8f42006c, 0x43102b, 0x14400004, -0x24020400, 0x8f43006c, 0x10000005, 0x431023, -0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff, -0x405021, 0x8a102a, 0x54400001, 0x805021, -0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c, -0x8f46006c, 0x24074000, 0xafa70010, 0x84140, -0x1001821, 0x12a4821, 0x313003ff, 0xafb00014, -0x8f470014, 0x1021, 0x63140, 0x24c66cc0, -0xafa70018, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0x8f420108, 0x2e63021, 0x40f809, -0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c, -0x8f420068, 0x14620018, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8, -0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021, -0x54820004, 0x24820008, 0x3c020001, 0x34422ec8, -0x2e21021, 0x401821, 0xaf4300f8, 0xac600000, -0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020, -0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8, -0x2e21021, 0x54620004, 0x24620008, 0x3c020001, -0x34422ec8, 0x2e21021, 0x401821, 0x8c620004, -0x21140, 0xa21021, 0xaf820128, 0xac600000, -0x8ca30018, 0x30620070, 0x1040002d, 0x30620020, +0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033, +0x0, 0x8f430068, 0x8f42006c, 0x622023, +0x4820001, 0x24840400, 0x8f430074, 0x8f42006c, +0x43102b, 0x14400004, 0x24020400, 0x8f43006c, +0x10000005, 0x431023, 0x8f420074, 0x8f43006c, +0x431023, 0x2442ffff, 0x405021, 0x8a102a, +0x54400001, 0x805021, 0x8f49006c, 0x8f48006c, +0x8f440188, 0x8f45018c, 0x8f46006c, 0x24074000, +0xafa70010, 0x84140, 0x1001821, 0x12a4821, +0x313003ff, 0xafb00014, 0x8f470014, 0x1021, +0x63140, 0x24c66cc0, 0xafa70018, 0xa32821, +0xa3382b, 0x822021, 0x872021, 0x8f420108, +0x2e63021, 0x40f809, 0xa3940, 0x54400001, +0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018, +0x0, 0x8f420000, 0x10400007, 0x0, +0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, +0x10000005, 0x0, 0xaf800048, 0x8f820048, +0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff, +0x431024, 0xaf820060, 0x8f420000, 0x10400003, +0x0, 0x10000002, 0xaf80004c, 0xaf800048, +0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, +0x3e00008, 0x0, 0x8f4200fc, 0x3c030001, +0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc, +0x8f850128, 0x2e31021, 0x54820004, 0x24820008, +0x3c020001, 0x34422ec8, 0x2e21021, 0x401821, +0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004, +0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128, +0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, +0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, +0x401821, 0x8c620004, 0x21140, 0xa21021, +0xaf820128, 0xac600000, 0x8ca30018, 0x30620070, +0x1040002d, 0x30620020, 0x10400004, 0x3c020010, +0x2c21024, 0x1040000d, 0x0, 0x30620040, +0x10400004, 0x3c020020, 0x2c21024, 0x10400007, +0x0, 0x30620010, 0x1040001f, 0x3c020040, +0x2c21024, 0x1440001c, 0x0, 0x8f820040, +0x30420001, 0x14400008, 0x2021, 0x8c030104, +0x24020001, 0x50620005, 0x24040001, 0x8c020264, +0x10400003, 0x801021, 0x24040001, 0x801021, +0x10400006, 0x0, 0x8f4202fc, 0x24420001, +0xaf4202fc, 0x10000008, 0x8f4202fc, 0x8f820044, +0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, +0xaf4202f8, 0x8f4202f8, 0x3e00008, 0x0, +0x3e00008, 0x0, 0x27bdffa0, 0xafbf0058, +0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, +0xafb10044, 0xafb00040, 0x8f4200fc, 0x24420001, +0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128, +0x8d030018, 0x30620070, 0x1040002e, 0x30620020, 0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, 0x0, 0x30620040, 0x10400004, 0x3c020020, 0x2c21024, 0x10400007, 0x0, 0x30620010, -0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c, +0x10400193, 0x3c020040, 0x2c21024, 0x14400190, 0x0, 0x8f820040, 0x30420001, 0x14400008, 0x2021, 0x8c030104, 0x24020001, 0x50620005, 0x24040001, 0x8c020264, 0x10400003, 0x801021, 0x24040001, 0x801021, 0x10400006, 0x0, -0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, +0x8f4202fc, 0x24420001, 0xaf4202fc, 0x1000017c, 0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, -0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x27bdffa0, 0xafbf0058, 0xafbe0054, 0xafb50050, -0xafb3004c, 0xafb20048, 0xafb10044, 0xafb00040, -0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128, -0x25020020, 0xaf820128, 0x8d030018, 0x30620070, -0x1040002e, 0x30620020, 0x10400004, 0x3c020010, -0x2c21024, 0x1040000d, 0x0, 0x30620040, -0x10400004, 0x3c020020, 0x2c21024, 0x10400007, -0x0, 0x30620010, 0x10400193, 0x3c020040, -0x2c21024, 0x14400190, 0x0, 0x8f820040, -0x30420001, 0x14400008, 0x2021, 0x8c030104, -0x24020001, 0x50620005, 0x24040001, 0x8c020264, -0x10400003, 0x801021, 0x24040001, 0x801021, -0x10400006, 0x0, 0x8f4202fc, 0x24420001, -0xaf4202fc, 0x1000017c, 0x8f4202fc, 0x8f820044, -0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, -0xaf4202f8, 0x10000174, 0x8f4202f8, 0x30620002, -0x10400135, 0x3c020800, 0x8d0a001c, 0x1422024, -0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024, -0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c, -0x8faa0034, 0x24020001, 0x15420007, 0x24020002, -0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021, -0x10000014, 0x2e2a821, 0x15420006, 0x24020003, -0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d, -0x2e2a821, 0x8faa0034, 0x15420006, 0x0, -0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005, -0x2e2a821, 0x8faa0024, 0xa1180, 0x571021, -0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400, -0x144000c5, 0x8821, 0x10800004, 0x24091000, -0x97b1002e, 0x100000c1, 0x0, 0x8eb30018, -0x9663000c, 0x2c6205dd, 0x10400015, 0x2021, -0x32c20800, 0x10400015, 0x24020800, 0x96630014, -0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007, -0x2821, 0x96630010, 0x24020300, 0x14620004, -0xa01021, 0x96620012, 0x2c450001, 0xa01021, -0x54400006, 0x24040016, 0x10000004, 0x0, -0x24020800, 0x50620001, 0x2404000e, 0x108000a2, -0x2649021, 0x92420000, 0x3042000f, 0x28080, -0x32c20100, 0x1040001e, 0x2501821, 0x3c020020, -0x43102b, 0x1440000e, 0x2402021, 0x2821, -0x94820000, 0x24840002, 0xa22821, 0x83102b, -0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821, -0x51c02, 0x30a2ffff, 0x10000009, 0x622821, -0x8f47013c, 0x8f420110, 0x102842, 0x3c060020, -0x40f809, 0xafa80038, 0x3045ffff, 0x8fa80038, -0x50a00001, 0x3405ffff, 0x10000002, 0x37de0002, -0x2821, 0x32c20080, 0x1040007b, 0xa6a50010, -0x26430009, 0x3c02001f, 0x3442ffff, 0x43102b, -0x10400003, 0x0, 0x8f42013c, 0x621823, -0x90660000, 0x30c200ff, 0x38430006, 0x2c630001, -0x38420011, 0x2c420001, 0x621825, 0x1060006b, -0x24091000, 0x8821, 0x2602021, 0x94820000, -0x24840002, 0x2228821, 0x92102b, 0x1440fffb, -0x111c02, 0x3222ffff, 0x628821, 0x111c02, -0x3222ffff, 0x628821, 0x32c20200, 0x10400003, -0x26440006, 0x1000003e, 0x8021, 0x3c05001f, -0x34a5ffff, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x30421fff, -0x10400004, 0x2644000c, 0x96420002, 0x10000030, -0x508023, 0x96420002, 0x26430014, 0x508023, -0x3c020020, 0x43102b, 0x1440000a, 0xd08021, -0x9642000c, 0x2028021, 0x9642000e, 0x96430010, -0x96440012, 0x2028021, 0x2038021, 0x10000020, -0x2048021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x24840002, -0x2028021, 0xa4102b, 0x10400003, 0x0, -0x8f42013c, 0x822023, 0x94820000, 0x2028021, -0x3c020100, 0x2c21024, 0x1040000c, 0x33c20004, -0x1040000a, 0x0, 0x9504000e, 0x2642021, -0xc003cc8, 0x2484fffc, 0x3042ffff, 0x2228821, -0x111c02, 0x3222ffff, 0x628821, 0x8faa002c, -0x1518823, 0x111402, 0x2228821, 0x2308821, -0x111402, 0x2228821, 0x3231ffff, 0x52200001, -0x3411ffff, 0x37de0001, 0x24091000, 0x33c20004, -0xa6b10012, 0x10400002, 0xa6be000e, 0x34098000, -0x8f480044, 0x8f440190, 0x8f450194, 0xafa90010, -0x8f490044, 0x84140, 0x1001821, 0xafa90014, -0x8f48000c, 0x2a03021, 0x24070020, 0xafa80018, -0x8f48010c, 0x1021, 0xa32821, 0xa3482b, -0x822021, 0x100f809, 0x892021, 0x1440000c, -0x0, 0x8f820128, 0x8faa0024, 0x3c040001, -0x24843944, 0xafaa0014, 0xafa20010, 0x8f860124, -0x8f870120, 0x3c050007, 0xc0029d3, 0x34a59920, -0x8f420358, 0x2442ffff, 0xaf420358, 0x8f420044, -0x8f430088, 0x24420001, 0x431024, 0xaf420044, -0x8faa0034, 0x8f440358, 0x24020001, 0x15420006, -0x24020002, 0x8f42034c, 0x2442ffff, 0xaf42034c, -0x10000049, 0x8f42034c, 0x15420006, 0x0, -0x8f420354, 0x2442ffff, 0xaf420354, 0x10000042, -0x8f420354, 0x8f420350, 0x2442ffff, 0xaf420350, -0x1000003d, 0x8f420350, 0x30621000, 0x10400005, -0x30628000, 0x8f420078, 0x24420001, 0x10000036, -0xaf420078, 0x10400034, 0x0, 0x8f420078, -0x24420001, 0xaf420078, 0x8c030240, 0x43102b, -0x1440002d, 0x24070008, 0x8f440158, 0x8f45015c, -0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x24020001, -0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x248438c8, -0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc0029d3, 0x34a51300, 0x1000000b, 0x0, -0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, -0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, -0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, -0xaf420308, 0x8f420308, 0x8fbf0058, 0x8fbe0054, -0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, -0x8fb00040, 0x3e00008, 0x27bd0060, 0x3e00008, -0x0, 0x0, 0x0, 0x8f420130, +0x8f4202f8, 0x24420001, 0xaf4202f8, 0x10000174, +0x8f4202f8, 0x30620002, 0x10400135, 0x3c020800, +0x8d0a001c, 0x1422024, 0xafaa0024, 0xa5702, +0xafaa0034, 0x8faa0024, 0x314affff, 0xafaa0024, +0x950a0016, 0xafaa002c, 0x8faa0034, 0x24020001, +0x15420007, 0x24020002, 0x8faa0024, 0xa1140, +0x3403ecc0, 0x431021, 0x10000014, 0x2e2a821, +0x15420006, 0x24020003, 0x8faa0024, 0xa1140, +0x24426cc0, 0x1000000d, 0x2e2a821, 0x8faa0034, +0x15420006, 0x0, 0x8faa0024, 0xa1140, +0x24424cc0, 0x10000005, 0x2e2a821, 0x8faa0024, +0xa1180, 0x571021, 0x24550ce0, 0x96a2000e, +0x305efffc, 0x30420400, 0x144000c5, 0x8821, +0x10800004, 0x24091000, 0x97b1002e, 0x100000c1, +0x0, 0x8eb30018, 0x9663000c, 0x2c6205dd, +0x10400015, 0x2021, 0x32c20800, 0x10400015, +0x24020800, 0x96630014, 0x14620012, 0x3402aaaa, +0x9663000e, 0x14620007, 0x2821, 0x96630010, +0x24020300, 0x14620004, 0xa01021, 0x96620012, +0x2c450001, 0xa01021, 0x54400006, 0x24040016, +0x10000004, 0x0, 0x24020800, 0x50620001, +0x2404000e, 0x108000a2, 0x2649021, 0x92420000, +0x3042000f, 0x28080, 0x32c20100, 0x1040001e, +0x2501821, 0x3c020020, 0x43102b, 0x1440000e, +0x2402021, 0x2821, 0x94820000, 0x24840002, +0xa22821, 0x83102b, 0x1440fffb, 0x30a2ffff, +0x51c02, 0x622821, 0x51c02, 0x30a2ffff, +0x10000009, 0x622821, 0x8f47013c, 0x8f420110, +0x102842, 0x3c060020, 0x40f809, 0xafa80038, +0x3045ffff, 0x8fa80038, 0x50a00001, 0x3405ffff, +0x10000002, 0x37de0002, 0x2821, 0x32c20080, +0x1040007b, 0xa6a50010, 0x26430009, 0x3c02001f, +0x3442ffff, 0x43102b, 0x10400003, 0x0, +0x8f42013c, 0x621823, 0x90660000, 0x30c200ff, +0x38430006, 0x2c630001, 0x38420011, 0x2c420001, +0x621825, 0x1060006b, 0x24091000, 0x8821, +0x2602021, 0x94820000, 0x24840002, 0x2228821, +0x92102b, 0x1440fffb, 0x111c02, 0x3222ffff, +0x628821, 0x111c02, 0x3222ffff, 0x628821, +0x32c20200, 0x10400003, 0x26440006, 0x1000003e, +0x8021, 0x3c05001f, 0x34a5ffff, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x30421fff, 0x10400004, 0x2644000c, +0x96420002, 0x10000030, 0x508023, 0x96420002, +0x26430014, 0x508023, 0x3c020020, 0x43102b, +0x1440000a, 0xd08021, 0x9642000c, 0x2028021, +0x9642000e, 0x96430010, 0x96440012, 0x2028021, +0x2038021, 0x10000020, 0x2048021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x24840002, 0x2028021, 0xa4102b, +0x10400003, 0x0, 0x8f42013c, 0x822023, +0x94820000, 0x2028021, 0x3c020100, 0x2c21024, +0x1040000c, 0x33c20004, 0x1040000a, 0x0, +0x9504000e, 0x2642021, 0xc003cf8, 0x2484fffc, +0x3042ffff, 0x2228821, 0x111c02, 0x3222ffff, +0x628821, 0x8faa002c, 0x1518823, 0x111402, +0x2228821, 0x2308821, 0x111402, 0x2228821, +0x3231ffff, 0x52200001, 0x3411ffff, 0x37de0001, +0x24091000, 0x33c20004, 0xa6b10012, 0x10400002, +0xa6be000e, 0x34098000, 0x8f480044, 0x8f440190, +0x8f450194, 0xafa90010, 0x8f490044, 0x84140, +0x1001821, 0xafa90014, 0x8f48000c, 0x2a03021, +0x24070020, 0xafa80018, 0x8f48010c, 0x1021, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x1440000c, 0x0, 0x8f820128, +0x8faa0024, 0x3c040001, 0x24843a28, 0xafaa0014, +0xafa20010, 0x8f860124, 0x8f870120, 0x3c050007, +0xc002a03, 0x34a59920, 0x8f420358, 0x2442ffff, +0xaf420358, 0x8f420044, 0x8f430088, 0x24420001, +0x431024, 0xaf420044, 0x8faa0034, 0x8f440358, +0x24020001, 0x15420006, 0x24020002, 0x8f42034c, +0x2442ffff, 0xaf42034c, 0x10000049, 0x8f42034c, +0x15420006, 0x0, 0x8f420354, 0x2442ffff, +0xaf420354, 0x10000042, 0x8f420354, 0x8f420350, +0x2442ffff, 0xaf420350, 0x1000003d, 0x8f420350, +0x30621000, 0x10400005, 0x30628000, 0x8f420078, +0x24420001, 0x10000036, 0xaf420078, 0x10400034, +0x0, 0x8f420078, 0x24420001, 0xaf420078, +0x8c030240, 0x43102b, 0x1440002d, 0x24070008, +0x8f440158, 0x8f45015c, 0x8f430044, 0x8f48000c, +0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, +0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, +0x14400011, 0x24020001, 0x3c010001, 0x370821, +0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, +0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, +0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, +0x1000000b, 0x0, 0x8f4202f4, 0x24420001, +0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, +0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, +0x8f420308, 0x24420001, 0xaf420308, 0x8f420308, +0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, +0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, +0x27bd0060, 0x3e00008, 0x0, 0x8f420130, 0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130, 0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c, 0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8, 0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, -0xc002a57, 0x24060008, 0x8c020204, 0xc003dee, +0xc002a87, 0x24060008, 0x8c020204, 0xc003e1e, 0xaf820210, 0x2021, 0x8c060248, 0x24020004, -0x3c010001, 0xac223d18, 0xc004878, 0x24050004, -0x3c020001, 0x8c423d14, 0x30420001, 0x10400007, -0x24020001, 0x3c010001, 0xac223d18, 0x2021, -0x24050001, 0xc004878, 0x3c06601b, 0x3c040001, -0x24843a00, 0x8f420144, 0x8f430148, 0x3c050008, +0x3c010001, 0xac223e28, 0xc0048a8, 0x24050004, +0x3c020001, 0x8c423e24, 0x30420001, 0x10400007, +0x24020001, 0x3c010001, 0xac223e28, 0x2021, +0x24050001, 0xc0048a8, 0x3c06601b, 0x3c040001, +0x24843af0, 0x8f420144, 0x8f430148, 0x3c050008, 0x8f46014c, 0x21640, 0x31940, 0x34630403, 0x431025, 0x633c0, 0x461025, 0xaf82021c, 0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200, -0xc0029d3, 0x3821, 0x3c010001, 0xac203d10, -0x3c010001, 0xac203d28, 0x8fbf0018, 0x3e00008, +0xc002a03, 0x3821, 0x3c010001, 0xac203e20, +0x3c010001, 0xac203e38, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, -0x3c040001, 0x24843a0c, 0xc0029d3, 0x3821, +0x3c040001, 0x24843afc, 0xc002a03, 0x3821, 0x8f420400, 0x24420001, 0xaf420400, 0x8f420400, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394, 0x24420001, 0xaf420394, 0x8f420394, 0x8f900220, -0x8f4303a8, 0x3c020001, 0x8c423d28, 0x3c040001, -0x24843a18, 0x3c050008, 0xafa20014, 0xafa30010, -0x8f4703ac, 0x34a50400, 0xc0029d3, 0x2003021, +0x8f4303a8, 0x3c020001, 0x8c423e38, 0x3c040001, +0x24843b08, 0x3c050008, 0xafa20014, 0xafa30010, +0x8f4703ac, 0x34a50400, 0xc002a03, 0x2003021, 0x3c024000, 0x2021024, 0x104000e1, 0x3c040100, 0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, @@ -7243,83 +7258,81 @@ 0x8f42013c, 0x822021, 0x8f420140, 0x2c830001, 0x44102b, 0x431025, 0x50400008, 0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, -0x3c034000, 0x10000046, 0x431025, 0x3442ffff, +0x3c034000, 0x10000041, 0x431025, 0x3442ffff, 0x8f4303bc, 0x282a024, 0x24020001, 0xa34205b1, -0x24630001, 0xaf4303bc, 0x1000003e, 0x8f4203bc, -0x2041024, 0x10400013, 0x3c110200, 0x8f420398, +0x24630001, 0xaf4303bc, 0x10000039, 0x8f4203bc, +0x2041024, 0x1040000e, 0x3c110200, 0x8f420398, 0x24420001, 0xaf420398, 0x8f420398, 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 0x441025, -0xaf820220, 0x3c020004, 0x2021024, 0x14400005, -0x3c110200, 0xc003bad, 0x0, 0x10000029, -0x0, 0x2111024, 0x50400008, 0x3c110400, -0x8f42039c, 0x24420001, 0xaf42039c, 0xc003bad, -0x8f42039c, 0x10000019, 0x0, 0x2111024, -0x1040001c, 0x0, 0x8f830224, 0x24021402, -0x14620009, 0x3c050008, 0x3c040001, 0x24843a24, -0xafa00010, 0xafa00014, 0x8f860224, 0x34a50500, -0xc0029d3, 0x3821, 0x8f4203a0, 0x24420001, -0xaf4203a0, 0x8f4203a0, 0x8f820220, 0x2002021, -0x34420002, 0xc004610, 0xaf820220, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x511025, -0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x3c020001, 0x8c423d28, 0x27bdffb0, 0xafbf0048, -0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, -0xafb10034, 0x1040000f, 0xafb00030, 0x3c040001, -0x24843a30, 0x3c050008, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50600, 0x24020001, 0x3c010001, -0xac203d28, 0x3c010001, 0xac223d1c, 0xc0029d3, -0x3821, 0x3c037fff, 0x8c020268, 0x3463ffff, -0x3c04fdff, 0x431024, 0xac020268, 0x8f420004, -0x3484ffff, 0x30420002, 0x10400092, 0x284a024, -0x3c040600, 0x34842000, 0x8f420004, 0x2821, -0x2403fffd, 0x431024, 0xaf420004, 0xafa40020, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa002c, 0x27c50001, 0x8c020228, 0xa09021, -0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, -0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, -0x248439c8, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, +0xc003be0, 0xaf820220, 0x10000029, 0x0, +0x2111024, 0x50400008, 0x3c110400, 0x8f42039c, +0x24420001, 0xaf42039c, 0xc003be0, 0x8f42039c, +0x10000019, 0x0, 0x2111024, 0x1040001c, +0x0, 0x8f830224, 0x24021402, 0x14620009, +0x3c050008, 0x3c040001, 0x24843b14, 0xafa00010, +0xafa00014, 0x8f860224, 0x34a50500, 0xc002a03, +0x3821, 0x8f4203a0, 0x24420001, 0xaf4203a0, +0x8f4203a0, 0x8f820220, 0x2002021, 0x34420002, +0xc004640, 0xaf820220, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x511025, 0xaf820220, +0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, +0x27bd0028, 0x3e00008, 0x0, 0x3c020001, +0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, +0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, +0x1040000f, 0xafb00030, 0x3c040001, 0x24843b20, +0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, +0x34a50600, 0x24020001, 0x3c010001, 0xac203e38, +0x3c010001, 0xac223e2c, 0xc002a03, 0x3821, +0x3c037fff, 0x8c020268, 0x3463ffff, 0x3c04fdff, +0x431024, 0xac020268, 0x8f420004, 0x3484ffff, +0x30420002, 0x10400092, 0x284a024, 0x3c040600, +0x34842000, 0x8f420004, 0x2821, 0x2403fffd, +0x431024, 0xaf420004, 0xafa40020, 0x8f5e0018, +0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa002c, +0x27c50001, 0x8c020228, 0xa09021, 0x1642000e, +0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, +0x8f42032c, 0x8c020228, 0x3c040001, 0x24843ab8, +0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, +0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, +0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, +0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, +0x1040001b, 0x9821, 0xe08821, 0x263504c0, +0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004, +0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021, +0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008, +0xa32821, 0xa3482b, 0x822021, 0x100f809, +0x892021, 0x54400006, 0x24130001, 0x8f820054, +0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0, +0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, +0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, +0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, +0x24843ac4, 0x3c050009, 0xafa20014, 0x8d460000, +0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, +0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, +0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, +0x2021023, 0x2c4203e9, 0x10400016, 0x9821, +0x3c150020, 0x24110010, 0x8f42000c, 0x8f440150, +0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, +0x551025, 0xafa20018, 0x8f42010c, 0x24070008, +0x40f809, 0x24c6001c, 0x1440ffe3, 0x0, +0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffee, +0x0, 0x326200ff, 0x14400011, 0x0, 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x248439d4, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000035, 0x34a50600, 0x8f4202f8, -0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, -0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016, -0x9821, 0x3c150020, 0x24110010, 0x8f42000c, -0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010, -0xafb20014, 0x551025, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, -0x0, 0x8f820054, 0x2021023, 0x2c4203e9, -0x1440ffee, 0x0, 0x326200ff, 0x14400011, -0x0, 0x8f420368, 0x24420001, 0xaf420368, -0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x248439dc, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc0029d3, -0x3c03821, 0x8f4202dc, 0x24420001, 0xaf4202dc, -0x8f4202dc, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x3c020001, 0x8c423d28, -0x27bdffe0, 0x1440000d, 0xafbf0018, 0x3c040001, -0x24843a3c, 0x3c050008, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50700, 0x24020001, 0x3c010001, -0xac223d28, 0xc0029d3, 0x3821, 0x3c020004, -0x2c21024, 0x10400008, 0x2021, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x34420008, -0xaf820220, 0x2021, 0xc004981, 0x24050004, -0xac020268, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x0, 0x0, 0x0, 0x86102b, +0x3c040001, 0x24843acc, 0x3c050009, 0xafa20014, +0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, +0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, +0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, +0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, +0x27bd0050, 0x3c020001, 0x8c423e38, 0x27bdffe0, +0x1440000d, 0xafbf0018, 0x3c040001, 0x24843b2c, +0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, +0x34a50700, 0x24020001, 0x3c010001, 0xac223e38, +0xc002a03, 0x3821, 0x3c020004, 0x2c21024, +0x10400008, 0x2021, 0x8f820220, 0x3c0308ff, +0x3463ffff, 0x431024, 0x34420008, 0xaf820220, +0x2021, 0xc0049b1, 0x24050004, 0xac020268, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x86102b, 0x50400001, 0x872023, 0xc41023, 0x24843, 0x125102b, 0x1040001b, 0x91040, 0x824021, 0x88102b, 0x10400007, 0x1821, 0x94820000, @@ -7359,7 +7372,7 @@ 0x90a20000, 0x822021, 0x41c02, 0x3082ffff, 0x622021, 0x41c02, 0x3082ffff, 0x622021, 0x3e00008, 0x3082ffff, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x3c020001, 0x8c425f28, +0x34420002, 0xaf820220, 0x3c020001, 0x8c426038, 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, @@ -7406,43 +7419,43 @@ 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 0x10620008, 0x24020800, 0x10000008, 0x0, 0x10620004, 0x24020800, 0x10000004, 0x0, -0x24020700, 0x3c010001, 0xac223d2c, 0x3e00008, +0x24020700, 0x3c010001, 0xac223e3c, 0x3e00008, 0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030, -0xafb1002c, 0xafb00028, 0x3c010001, 0xc0045ed, -0xac203d14, 0x24040001, 0x2821, 0x27a60020, -0x34028000, 0xc00420a, 0xa7a20020, 0x8f830054, +0xafb1002c, 0xafb00028, 0x3c010001, 0xc00461d, +0xac203e24, 0x24040001, 0x2821, 0x27a60020, +0x34028000, 0xc00423a, 0xa7a20020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60020, 0x8f830054, +0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050002, 0xc0041c8, 0x27a60018, 0x8f830054, +0x24050002, 0xc0041f8, 0x27a60018, 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, -0x24050003, 0xc0041c8, 0x27a6001a, 0x97a20020, -0x10400029, 0x24020001, 0x3c020001, 0x8c423d14, -0x97a30018, 0x34420001, 0x3c010001, 0xac223d14, +0x24050003, 0xc0041f8, 0x27a6001a, 0x97a20020, +0x10400029, 0x24020001, 0x3c020001, 0x8c423e24, +0x97a30018, 0x34420001, 0x3c010001, 0xac223e24, 0x24020015, 0x14620009, 0x0, 0x97a2001a, 0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, 0x621825, 0x14600018, 0x24020003, 0x97a30018, 0x24027810, 0x14620014, 0x24020002, 0x97a3001a, 0x24020001, 0x14620010, 0x24020002, 0x1000000e, -0x24020004, 0x3c020001, 0x8c423d14, 0x34420008, -0x3c010001, 0xac223d14, 0x10000058, 0x24020004, -0x3c020001, 0x8c423d14, 0x34420004, 0x3c010001, -0x100000a9, 0xac223d14, 0x3c010001, 0xac223e70, +0x24020004, 0x3c020001, 0x8c423e24, 0x34420008, +0x3c010001, 0xac223e24, 0x10000058, 0x24020004, +0x3c020001, 0x8c423e24, 0x34420004, 0x3c010001, +0x100000a9, 0xac223e24, 0x3c010001, 0xac223f80, 0x24020e00, 0xaf820238, 0x8f840054, 0x8f820054, -0x24030008, 0x3c010001, 0xac233d18, 0x10000002, +0x24030008, 0x3c010001, 0xac233e28, 0x10000002, 0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, 0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, -0x8021, 0x24120001, 0x24110009, 0xc0040e8, -0x0, 0x3c010001, 0xac323d30, 0xc004194, -0x0, 0x3c020001, 0x8c423d30, 0x1451fffb, +0x8021, 0x24120001, 0x24110009, 0xc004118, +0x0, 0x3c010001, 0xac323e40, 0xc0041c4, +0x0, 0x3c020001, 0x8c423e40, 0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 0x0, @@ -7454,10 +7467,10 @@ 0x14440005, 0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa6, 0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, 0x3c010001, -0xac223d18, 0x8021, 0x24120009, 0x3c11ffff, -0x36313f7f, 0xc0040e8, 0x0, 0x24020001, -0x3c010001, 0xac223d30, 0xc004194, 0x0, -0x3c020001, 0x8c423d30, 0x1452fffb, 0x0, +0xac223e28, 0x8021, 0x24120009, 0x3c11ffff, +0x36313f7f, 0xc004118, 0x0, 0x24020001, +0x3c010001, 0xac223e40, 0xc0041c4, 0x0, +0x3c020001, 0x8c423e40, 0x1452fffb, 0x0, 0x8f820044, 0x511024, 0x34425080, 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, @@ -7475,131 +7488,131 @@ 0x1440fffc, 0x0, 0x8f820224, 0x14440005, 0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 0x34028000, 0x1082ff56, 0x26100001, 0x2e020064, -0x1440ffb0, 0x0, 0x3c020001, 0x8c423d14, +0x1440ffb0, 0x0, 0x3c020001, 0x8c423e24, 0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, 0x3c08fff0, 0x3508bdc0, 0x8f830054, 0x97a60018, -0x3c070001, 0x8ce73e70, 0x3c040001, 0x24843b00, -0x24020001, 0x3c010001, 0xac223d1c, 0xafa60010, -0x3c060001, 0x8cc63d14, 0x97a2001a, 0x3c05000d, -0x34a50100, 0x3c010001, 0xac203d18, 0x681821, -0x3c010001, 0xac233e68, 0xc0029d3, 0xafa20014, +0x3c070001, 0x8ce73f80, 0x3c040001, 0x24843c00, +0x24020001, 0x3c010001, 0xac223e2c, 0xafa60010, +0x3c060001, 0x8cc63e24, 0x97a2001a, 0x3c05000d, +0x34a50100, 0x3c010001, 0xac203e28, 0x681821, +0x3c010001, 0xac233f78, 0xc002a03, 0xafa20014, 0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038, 0x27bdffe8, 0x24070004, -0x3c040001, 0x8c843d18, 0x3021, 0x24020001, -0x1482000a, 0xafbf0010, 0x3c020001, 0x8c425f2c, +0x3c040001, 0x8c843e28, 0x3021, 0x24020001, +0x1482000a, 0xafbf0010, 0x3c020001, 0x8c42603c, 0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, -0x8c425f2c, 0x3c05000f, 0x30428000, 0x10400003, +0x8c42603c, 0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480, 0x3c020001, -0x8c423e68, 0x8f830054, 0x451021, 0x431023, +0x8c423f78, 0x8f830054, 0x451021, 0x431023, 0x45102b, 0x1440002e, 0x0, 0x3c020001, -0x8c423d20, 0x1440002a, 0x2cc20001, 0x7182b, +0x8c423e30, 0x1440002a, 0x2cc20001, 0x7182b, 0x431024, 0x1040001d, 0x0, 0x3c090001, -0x8d293d14, 0x240b0001, 0x3c054000, 0x3c080001, -0x25085f2c, 0x250afffc, 0x42042, 0x14800002, +0x8d293e24, 0x240b0001, 0x3c054000, 0x3c080001, +0x2508603c, 0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 0x10000003, 0x451024, 0x8d420000, 0x451024, 0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, 0x42042, 0x3c010001, -0x10c00020, 0xac243d18, 0x8f830054, 0x24020001, -0x3c010001, 0xac223d1c, 0x3c010001, 0xac233e68, -0x3c020001, 0x8c423d1c, 0x10400004, 0x24020001, -0x3c010001, 0xac203d1c, 0xaee204b8, 0x8ee304b8, -0x24020008, 0x10620005, 0x24020001, 0xc003f91, +0x10c00020, 0xac243e28, 0x8f830054, 0x24020001, +0x3c010001, 0xac223e2c, 0x3c010001, 0xac233f78, +0x3c020001, 0x8c423e2c, 0x10400004, 0x24020001, +0x3c010001, 0xac203e2c, 0xaee204b8, 0x8ee304b8, +0x24020008, 0x10620005, 0x24020001, 0xc003fc1, 0x0, 0x1000000b, 0x0, 0x3c030001, -0x8c633d18, 0x10620007, 0x2402000e, 0x3c030001, -0x8c635ec0, 0x10620003, 0x0, 0xc004610, +0x8c633e28, 0x10620007, 0x2402000e, 0x3c030001, +0x8c635fd0, 0x10620003, 0x0, 0xc004640, 0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843d18, -0x3c020001, 0x8c423d38, 0x3463ffff, 0x283a024, +0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843e28, +0x3c020001, 0x8c423e48, 0x3463ffff, 0x283a024, 0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, -0x8c423d3c, 0x10620006, 0x0, 0x8ee204b8, -0x3c010001, 0xac243d38, 0x3c010001, 0xac223d3c, -0x3c030001, 0x8c633d18, 0x24020002, 0x1062013c, +0x8c423e4c, 0x10620006, 0x0, 0x8ee204b8, +0x3c010001, 0xac243e48, 0x3c010001, 0xac223e4c, +0x3c030001, 0x8c633e28, 0x24020002, 0x1062013c, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x0, 0x10000134, 0x0, 0x24020004, 0x1062006d, 0x24020008, 0x1062009f, 0x24020001, 0x1000012d, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 0x1040012a, 0x31080, 0x3c010001, -0x220821, 0x8c223b18, 0x400008, 0x0, -0xc0040e8, 0x0, 0x3c020001, 0x8c423d24, -0x3c010001, 0xac203cb0, 0x104000d7, 0x24020002, -0xaee204b8, 0x3c010001, 0x10000119, 0xac203d24, -0xc00424b, 0x0, 0x3c030001, 0x8c633d40, -0x1000009e, 0x24020011, 0x3c050001, 0x8ca53d18, -0x3c060001, 0x8cc65f2c, 0xc004878, 0x2021, -0x24020005, 0x3c010001, 0xac203d24, 0x10000108, -0xaee204b8, 0x3c040001, 0x24843b0c, 0x3c05000f, +0x220821, 0x8c223c18, 0x400008, 0x0, +0xc004118, 0x0, 0x3c020001, 0x8c423e34, +0x3c010001, 0xac203dc0, 0x104000d7, 0x24020002, +0xaee204b8, 0x3c010001, 0x10000119, 0xac203e34, +0xc00427b, 0x0, 0x3c030001, 0x8c633e50, +0x1000009e, 0x24020011, 0x3c050001, 0x8ca53e28, +0x3c060001, 0x8cc6603c, 0xc0048a8, 0x2021, +0x24020005, 0x3c010001, 0xac203e34, 0x10000108, +0xaee204b8, 0x3c040001, 0x24843c0c, 0x3c05000f, 0x34a50100, 0x3021, 0x3821, 0xafa00010, -0xc0029d3, 0xafa00014, 0x100000fd, 0x0, +0xc002a03, 0xafa00014, 0x100000fd, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0x100000a4, 0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 0x144000ae, 0x24020007, 0x8f830054, 0x3c020001, -0x8c423e60, 0x2463d8f0, 0x431023, 0x2c422710, +0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, 0x144000eb, 0x24020001, 0x100000e7, 0x0, -0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, -0xc004a4c, 0x2021, 0x3c030001, 0x8c635f24, +0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, +0xc004a7c, 0x2021, 0x3c030001, 0x8c636034, 0x46100dd, 0x24020001, 0x3c020008, 0x621024, 0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 0x431024, 0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, 0x8f820220, 0x3c030200, 0x283a025, 0x34420002, -0xaf820220, 0x24020008, 0xc003c6b, 0xaee204b8, +0xaf820220, 0x24020008, 0xc003c9e, 0xaee204b8, 0x100000c7, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 0x104000c2, 0x31080, 0x3c010001, -0x220821, 0x8c223b38, 0x400008, 0x0, -0x3c020001, 0x8c425f28, 0x30424000, 0x10400004, +0x220821, 0x8c223c38, 0x400008, 0x0, +0x3c020001, 0x8c426038, 0x30424000, 0x10400004, 0x0, 0x8f820044, 0x10000006, 0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080, 0xaf820044, 0x8f830054, 0x1000005a, -0x24020004, 0xc003d2c, 0x0, 0x104000a6, +0x24020004, 0xc003d5c, 0x0, 0x104000a6, 0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x10800005, 0xaee204b8, 0x3c020001, -0x8c423da4, 0x1040006d, 0x24020001, 0x8f820220, +0x8c423eb4, 0x1040006d, 0x24020001, 0x8f820220, 0x3c030008, 0x431024, 0x10400073, 0x3c020200, 0x10000081, 0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e, 0x31080, 0x3c010001, -0x220821, 0x8c223b58, 0x400008, 0x0, -0xc003bad, 0x0, 0x3c010001, 0xac203d1c, -0xaf800204, 0x3c010001, 0xc0040e8, 0xac205f10, -0x24020001, 0x3c010001, 0xac223d30, 0x24020002, -0x1000007b, 0xaee204b8, 0xc004194, 0x0, -0x3c030001, 0x8c633d30, 0x24020009, 0x14620074, +0x220821, 0x8c223c58, 0x400008, 0x0, +0xc003be0, 0x0, 0x3c010001, 0xac203e2c, +0xaf800204, 0x3c010001, 0xc004118, 0xac206020, +0x24020001, 0x3c010001, 0xac223e40, 0x24020002, +0x1000007b, 0xaee204b8, 0xc0041c4, 0x0, +0x3c030001, 0x8c633e40, 0x24020009, 0x14620074, 0x24020003, 0x10000072, 0xaee204b8, 0x3c020001, -0x8c425f28, 0x30424000, 0x10400003, 0x3c0200c8, +0x8c426038, 0x30424000, 0x10400003, 0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, 0x8f830054, 0x10000014, 0x24020004, 0x8f830054, -0x3c020001, 0x8c423e60, 0x2463d8f0, 0x431023, +0x3c020001, 0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440005e, 0x24020005, 0x1000005c, 0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010001, 0xac205f10, +0xaf820220, 0xaf800204, 0x3c010001, 0xac206020, 0x8f830054, 0x24020006, 0xaee204b8, 0x3c010001, -0x1000004f, 0xac233e60, 0x8f830054, 0x3c020001, -0x8c423e60, 0x2463fff6, 0x431023, 0x2c42000a, +0x1000004f, 0xac233f70, 0x8f830054, 0x3c020001, +0x8c423f70, 0x2463fff6, 0x431023, 0x2c42000a, 0x14400047, 0x0, 0x24020007, 0x10000044, -0xaee204b8, 0xc003d2c, 0x0, 0x1040003e, +0xaee204b8, 0xc003d5c, 0x0, 0x1040003e, 0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, -0x8c843e58, 0x431024, 0x3442251f, 0xaf820214, +0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, -0x8c423da4, 0x1440000b, 0x0, 0x8f820220, +0x8c423eb4, 0x1440000b, 0x0, 0x8f820220, 0x34420002, 0xaf820220, 0x24020001, 0x3c010001, -0xac225ec0, 0xc004610, 0x8f840220, 0x10000016, +0xac225fd0, 0xc004640, 0x8f840220, 0x10000016, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x14400011, 0x3c020200, 0x282a025, 0x2402000e, -0x3c010001, 0xac225ec0, 0xc004a4c, 0x2021, -0x8f820220, 0x34420002, 0xc003c6b, 0xaf820220, -0x3c050001, 0x8ca53d18, 0xc004981, 0x2021, -0x10000013, 0x0, 0x3c020001, 0x8c423da4, -0x1040000f, 0x0, 0x3c020001, 0x8c423da0, -0x2442ffff, 0x3c010001, 0xac223da0, 0x14400008, -0x24020002, 0x3c010001, 0xac203da4, 0x3c010001, -0x10000003, 0xac223da0, 0x3c010001, 0xac223d1c, +0x3c010001, 0xac225fd0, 0xc004a7c, 0x2021, +0x8f820220, 0x34420002, 0xc003c9e, 0xaf820220, +0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, +0x10000013, 0x0, 0x3c020001, 0x8c423eb4, +0x1040000f, 0x0, 0x3c020001, 0x8c423eb0, +0x2442ffff, 0x3c010001, 0xac223eb0, 0x14400008, +0x24020002, 0x3c010001, 0xac203eb4, 0x3c010001, +0x10000003, 0xac223eb0, 0x3c010001, 0xac223e2c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820200, 0x3c040001, 0x8c843d18, 0x34420004, +0x8f820200, 0x3c040001, 0x8c843e28, 0x34420004, 0xaf820200, 0x24020002, 0x1082003a, 0x2c820003, 0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, 0x10000098, 0x0, 0x24020004, 0x10820059, @@ -7607,300 +7620,300 @@ 0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, 0x34a53f7f, 0x431024, 0x3c030700, 0x431025, 0xaf820050, 0x24020e00, 0xaf840200, 0xaf840220, -0xaf820238, 0x8f820044, 0x3c030001, 0x8c633d08, -0x3c040001, 0x8c843e70, 0x451024, 0x34630022, +0xaf820238, 0x8f820044, 0x3c030001, 0x8c633e18, +0x3c040001, 0x8c843f80, 0x451024, 0x34630022, 0xaf820044, 0x24020004, 0x1082000c, 0xaf830200, -0x3c020001, 0x8c423d2c, 0x3c030001, 0x8c633d10, -0x3c040001, 0x8c843d0c, 0x34428000, 0x621825, +0x3c020001, 0x8c423e3c, 0x3c030001, 0x8c633e20, +0x3c040001, 0x8c843e1c, 0x34428000, 0x621825, 0x641825, 0x1000006e, 0x34620002, 0x3c020001, -0x8c423d10, 0x3c030001, 0x8c633d2c, 0x3c040001, -0x8c843d0c, 0x431025, 0x441025, 0x10000064, +0x8c423e20, 0x3c030001, 0x8c633e3c, 0x3c040001, +0x8c843e1c, 0x431025, 0x441025, 0x10000064, 0x34420002, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843e58, 0x621824, 0x3c020d00, +0x3c040001, 0x8c843f68, 0x621824, 0x3c020d00, 0x621825, 0x24020001, 0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00, 0x10800009, 0xaf820238, -0x3c020001, 0x8c423da4, 0x14400005, 0x3c033f00, -0x3c020001, 0x8c423d00, 0x10000005, 0x34630070, -0x3c020001, 0x8c423d00, 0x3c033f00, 0x34630072, -0x431025, 0xaf820200, 0x3c030001, 0x8c633d04, -0x3c04f700, 0x3c020001, 0x8c423d10, 0x3c050001, -0x8ca53d2c, 0x641825, 0x431025, 0x1000003c, +0x3c020001, 0x8c423eb4, 0x14400005, 0x3c033f00, +0x3c020001, 0x8c423e10, 0x10000005, 0x34630070, +0x3c020001, 0x8c423e10, 0x3c033f00, 0x34630072, +0x431025, 0xaf820200, 0x3c030001, 0x8c633e14, +0x3c04f700, 0x3c020001, 0x8c423e20, 0x3c050001, +0x8ca53e3c, 0x641825, 0x431025, 0x1000003c, 0x451025, 0x8f830050, 0x3c02f0ff, 0x3442ffff, -0x3c040001, 0x8c843e58, 0x621824, 0x3c020a00, +0x3c040001, 0x8c843f68, 0x621824, 0x3c020a00, 0x621825, 0x24020001, 0xaf830050, 0xaf820200, -0x1080001e, 0xaf820220, 0x3c020001, 0x8c423da4, -0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423d00, +0x1080001e, 0xaf820220, 0x3c020001, 0x8c423eb4, +0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423e10, 0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, -0x8c843e58, 0x3442ffff, 0x621824, 0x1080000f, -0xaf830050, 0x3c020001, 0x8c423da4, 0x1440000b, -0x3c043f00, 0x3c030001, 0x8c633d00, 0x348400e0, +0x8c843f68, 0x3442ffff, 0x621824, 0x1080000f, +0xaf830050, 0x3c020001, 0x8c423eb4, 0x1440000b, +0x3c043f00, 0x3c030001, 0x8c633e10, 0x348400e0, 0x24020001, 0xaf820200, 0xaf820220, 0x641825, 0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, -0x8c423d00, 0x3c033f00, 0x346300e2, 0x431025, +0x8c423e10, 0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, -0x8c633d04, 0x3c020001, 0x8c423d10, 0x3c040001, -0x8c843d2c, 0x651825, 0x431025, 0x441025, +0x8c633e14, 0x3c020001, 0x8c423e20, 0x3c040001, +0x8c843e3c, 0x651825, 0x431025, 0x441025, 0xaf820220, 0x3e00008, 0x0, 0x3c030001, -0x8c633d30, 0x3c020001, 0x8c423d34, 0x10620003, -0x24020002, 0x3c010001, 0xac233d34, 0x1062001d, +0x8c633e40, 0x3c020001, 0x8c423e44, 0x10620003, +0x24020002, 0x3c010001, 0xac233e44, 0x1062001d, 0x2c620003, 0x10400025, 0x24020001, 0x14620023, -0x24020004, 0x3c030001, 0x8c633d18, 0x10620006, +0x24020004, 0x3c030001, 0x8c633e28, 0x10620006, 0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080, 0xaf820044, 0x8f830054, 0x24020002, -0x3c010001, 0xac223d30, 0x3c010001, 0x1000000b, -0xac233e64, 0x8f830054, 0x3c020001, 0x8c423e64, +0x3c010001, 0xac223e40, 0x3c010001, 0x1000000b, +0xac233f74, 0x8f830054, 0x3c020001, 0x8c423f74, 0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, -0x24020009, 0x3c010001, 0xac223d30, 0x3e00008, +0x24020009, 0x3c010001, 0xac223e40, 0x3e00008, 0x0, 0x0, 0x0, 0x27bdffd8, 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc0045c7, 0x24040001, +0xafbf0020, 0xa6200000, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc0045c7, 0x2021, 0xc0045c7, 0x24040001, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fffa, +0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fffa, 0x2701024, 0xc0045ed, 0x34108000, -0xc0045ed, 0x0, 0xc0045a7, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fffa, 0x2701024, 0xc00461d, 0x34108000, +0xc00461d, 0x0, 0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc0045ed, 0x0, 0x8fbf0020, 0x8fb3001c, +0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc0045c7, +0xafb00010, 0x8021, 0xafbf0020, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x2501024, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x2501024, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8fbf0020, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633d40, -0x3c020001, 0x8c423d84, 0x27bdffd8, 0xafbf0020, +0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633e50, +0x3c020001, 0x8c423e94, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac233d84, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c223b80, -0x400008, 0x0, 0xc0045ed, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc0045c7, +0xac233e94, 0x2463ffff, 0x2c620013, 0x10400349, +0x31080, 0x3c010001, 0x220821, 0x8c223c80, +0x400008, 0x0, 0xc00461d, 0x8021, +0x34028000, 0xa7a20010, 0x27b10010, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc0045c7, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fffa, 0x32020001, 0x24100010, 0xc0045f7, 0x2021, 0x108042, 0x1600fffc, 0x0, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc0045c7, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc0045c7, -0x2021, 0xc0045c7, 0x24040001, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x24100010, +0x8021, 0xc0045f7, 0x24040001, 0x26100001, +0x2e020020, 0x1440fffb, 0x0, 0xc0045f7, +0x2021, 0xc0045f7, 0x24040001, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x24100010, 0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc0045c7, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc0045ed, 0x34108000, -0xc0045ed, 0x0, 0xc0045a7, 0x0, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, +0x24100010, 0xc0045f7, 0x2021, 0x108042, +0x1600fffc, 0x0, 0xc00461d, 0x34108000, +0xc00461d, 0x0, 0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc0045ed, 0x0, 0x97a20010, 0x30428000, +0xc00461d, 0x0, 0x97a20010, 0x30428000, 0x144002dc, 0x24020003, 0x100002d8, 0x0, 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc0045c7, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc0045c7, 0x24040001, 0xc0045c7, +0xc0045f7, 0x2021, 0x108042, 0x1600fffc, +0x0, 0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fff8, 0x0, 0xc0045ed, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000296, 0x24020004, -0x8f830054, 0x3c020001, 0x8c423e6c, 0x2463ff9c, +0x8f830054, 0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c633e70, 0x10620297, 0x2c620003, +0x3c030001, 0x8c633f80, 0x10620297, 0x2c620003, 0x14400296, 0x24020011, 0x24020003, 0x10620005, 0x24020004, 0x10620291, 0x2402000f, 0x1000028f, 0x24020011, 0x1000028d, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x32020012, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x32020012, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8f830054, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000248, 0x24020006, 0x8f830054, 0x3c020001, -0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400250, 0x24020007, 0x1000024c, 0x0, 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020013, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020013, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000207, 0x24020008, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020017, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400127, 0x24020012, 0x10000123, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020014, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, -0x3c020001, 0x8c423e6c, 0x2463ff9c, 0x431023, +0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, 0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x24040001, -0xc0045c7, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, +0xc0045f7, 0x2021, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045ed, 0x34108000, 0xc0045ed, 0x0, -0xc0045a7, 0x0, 0x50400005, 0x108042, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc00461d, 0x34108000, 0xc00461d, 0x0, +0xc0045d7, 0x0, 0x50400005, 0x108042, 0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc0045ed, 0x8021, +0x1600fff7, 0x0, 0xc00461d, 0x8021, 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc0045c7, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, -0xc0045c7, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, +0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, +0x1440fffb, 0x0, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, +0xc0045f7, 0x24040001, 0x24100010, 0x32020001, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc0045c7, 0x108042, 0x1600fffa, 0x32020018, -0xc0045c7, 0x24040001, 0xc0045c7, 0x2021, +0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, +0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, -0x1600fff8, 0x0, 0xc0045ed, 0x0, +0x2021, 0x24040001, 0xc0045f7, 0x108042, +0x1600fff8, 0x0, 0xc00461d, 0x0, 0x8f830054, 0x10000037, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc0045c7, +0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc0045c7, 0x2021, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0xc0045c7, +0x0, 0xc0045f7, 0x2021, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc0045c7, 0x108042, +0x2021, 0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc0045c7, -0x108042, 0x1600fffa, 0x32020013, 0xc0045c7, -0x24040001, 0xc0045c7, 0x2021, 0x34108000, +0x10400002, 0x2021, 0x24040001, 0xc0045f7, +0x108042, 0x1600fffa, 0x32020013, 0xc0045f7, +0x24040001, 0xc0045f7, 0x2021, 0x34108000, 0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc0045c7, 0x108042, 0x1600fff8, -0x0, 0xc0045ed, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac223d40, 0x3c010001, -0x1000000c, 0xac233e6c, 0x8f830054, 0x3c020001, -0x8c423e6c, 0x2463ff9c, 0x431023, 0x2c420064, +0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, +0x0, 0xc00461d, 0x0, 0x8f830054, +0x24020010, 0x3c010001, 0xac223e50, 0x3c010001, +0x1000000c, 0xac233f7c, 0x8f830054, 0x3c020001, +0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac223d40, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, +0xac223e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 0x8f840054, 0x8f820054, 0xa32824, 0x10000002, @@ -7929,136 +7942,136 @@ 0x621023, 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 0x0, 0x0, 0x27bdffe8, 0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, -0x0, 0x3c020001, 0x8c423e58, 0x14400005, -0x0, 0xc003bad, 0x8f840224, 0x100001d8, +0x0, 0x3c020001, 0x8c423f68, 0x14400005, +0x0, 0xc003be0, 0x8f840224, 0x100001d8, 0x0, 0x8f820220, 0x3c030008, 0x431024, 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 0x3c030400, 0x431024, 0x10400006, 0x0, -0x3c010001, 0xac205ed0, 0x3c010001, 0x1000000b, -0xac205ef0, 0x3c030001, 0x24635ed0, 0x8c620000, +0x3c010001, 0xac205fe0, 0x3c010001, 0x1000000b, +0xac206000, 0x3c030001, 0x24635fe0, 0x8c620000, 0x24420001, 0xac620000, 0x2c420002, 0x14400003, -0x24020001, 0x3c010001, 0xac225ef0, 0x3c020001, -0x8c425ef0, 0x10400006, 0x30820040, 0x10400004, -0x24020001, 0x3c010001, 0x10000003, 0xac225ef4, -0x3c010001, 0xac205ef4, 0x3c010001, 0xac245ecc, -0x3c010001, 0x1000000b, 0xac205f00, 0x3c010001, -0xac225f00, 0x3c010001, 0xac205ef0, 0x3c010001, -0xac205ed0, 0x3c010001, 0xac205ef4, 0x3c010001, -0xac205ecc, 0x3c030001, 0x8c635ec0, 0x3c020001, -0x8c425ec4, 0x50620004, 0x2463ffff, 0x3c010001, -0xac235ec4, 0x2463ffff, 0x2c62000e, 0x10400194, -0x31080, 0x3c010001, 0x220821, 0x8c223bd0, +0x24020001, 0x3c010001, 0xac226000, 0x3c020001, +0x8c426000, 0x10400006, 0x30820040, 0x10400004, +0x24020001, 0x3c010001, 0x10000003, 0xac226004, +0x3c010001, 0xac206004, 0x3c010001, 0xac245fdc, +0x3c010001, 0x1000000b, 0xac206010, 0x3c010001, +0xac226010, 0x3c010001, 0xac206000, 0x3c010001, +0xac205fe0, 0x3c010001, 0xac206004, 0x3c010001, +0xac205fdc, 0x3c030001, 0x8c635fd0, 0x3c020001, +0x8c425fd4, 0x50620004, 0x2463ffff, 0x3c010001, +0xac235fd4, 0x2463ffff, 0x2c62000e, 0x10400194, +0x31080, 0x3c010001, 0x220821, 0x8c223cd0, 0x400008, 0x0, 0x24020002, 0x3c010001, -0xac205ef0, 0x3c010001, 0xac205ed0, 0x3c010001, -0xac205ecc, 0x3c010001, 0xac205ef4, 0x3c010001, -0xac205ee8, 0x3c010001, 0xac205ee0, 0xaf800224, -0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425f00, -0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003bad, +0xac206000, 0x3c010001, 0xac205fe0, 0x3c010001, +0xac205fdc, 0x3c010001, 0xac206004, 0x3c010001, +0xac205ff8, 0x3c010001, 0xac205ff0, 0xaf800224, +0x3c010001, 0xac225fd0, 0x3c020001, 0x8c426010, +0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003be0, 0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, -0x431024, 0xaf820200, 0x3c010001, 0xac205f10, -0x8f830054, 0x3c020001, 0x8c425ee8, 0x24040001, -0x3c010001, 0xac245efc, 0x24420001, 0x3c010001, -0xac225ee8, 0x2c420004, 0x3c010001, 0xac235ee4, -0x14400006, 0x24020003, 0x3c010001, 0xac243d1c, -0x3c010001, 0x1000015e, 0xac205ee8, 0x3c010001, -0x1000015b, 0xac225ec0, 0x8f830054, 0x3c020001, -0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020004, 0x3c010001, 0xac225ec0, -0x3c020001, 0x8c425f00, 0x14400021, 0x3c02fdff, +0x431024, 0xaf820200, 0x3c010001, 0xac206020, +0x8f830054, 0x3c020001, 0x8c425ff8, 0x24040001, +0x3c010001, 0xac24600c, 0x24420001, 0x3c010001, +0xac225ff8, 0x2c420004, 0x3c010001, 0xac235ff4, +0x14400006, 0x24020003, 0x3c010001, 0xac243e2c, +0x3c010001, 0x1000015e, 0xac205ff8, 0x3c010001, +0x1000015b, 0xac225fd0, 0x8f830054, 0x3c020001, +0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400003, 0x24020004, 0x3c010001, 0xac225fd0, +0x3c020001, 0x8c426010, 0x14400021, 0x3c02fdff, 0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, -0x8c843e5c, 0x3c010001, 0xc0047f8, 0xac205ed8, -0x3c020001, 0x8c425f0c, 0xaf820204, 0x3c020001, -0x8c425f00, 0x14400012, 0x3c03fdff, 0x8f820204, +0x8c843f6c, 0x3c010001, 0xc004828, 0xac205fe8, +0x3c020001, 0x8c42601c, 0xaf820204, 0x3c020001, +0x8c426010, 0x14400012, 0x3c03fdff, 0x8f820204, 0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, -0x3c030001, 0x8c635f0c, 0x24020005, 0x3c010001, -0xac225ec0, 0x3c010001, 0x10000131, 0xac235f10, -0x3c020001, 0x8c425f00, 0x10400010, 0x3c02fdff, -0x3c020001, 0x8c423d9c, 0x24420001, 0x3c010001, -0xac223d9c, 0x2c420002, 0x14400125, 0x24020001, -0x3c010001, 0xac223da4, 0x3c010001, 0xac203d9c, -0x3c010001, 0x1000011e, 0xac223d1c, 0x3c030001, -0x8c635ef0, 0x3442ffff, 0x10600119, 0x282a024, -0x3c020001, 0x8c425ecc, 0x10400115, 0x0, -0x3c010001, 0xac225ef8, 0x24020003, 0x3c010001, -0xac225ed0, 0x100000b8, 0x24020006, 0x3c010001, -0xac205ed8, 0x8f820204, 0x34420040, 0xaf820204, -0x3c020001, 0x8c425f10, 0x24030007, 0x3c010001, -0xac235ec0, 0x34420040, 0x3c010001, 0xac225f10, -0x3c020001, 0x8c425ef0, 0x10400005, 0x0, -0x3c020001, 0x8c425ecc, 0x104000f0, 0x24020002, -0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, -0x104000ea, 0x24020002, 0x3c020001, 0x8c425ef4, -0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425ecc, -0x3c030001, 0x8c635ef8, 0x441024, 0x641824, +0x3c030001, 0x8c63601c, 0x24020005, 0x3c010001, +0xac225fd0, 0x3c010001, 0x10000131, 0xac236020, +0x3c020001, 0x8c426010, 0x10400010, 0x3c02fdff, +0x3c020001, 0x8c423eac, 0x24420001, 0x3c010001, +0xac223eac, 0x2c420002, 0x14400125, 0x24020001, +0x3c010001, 0xac223eb4, 0x3c010001, 0xac203eac, +0x3c010001, 0x1000011e, 0xac223e2c, 0x3c030001, +0x8c636000, 0x3442ffff, 0x10600119, 0x282a024, +0x3c020001, 0x8c425fdc, 0x10400115, 0x0, +0x3c010001, 0xac226008, 0x24020003, 0x3c010001, +0xac225fe0, 0x100000b8, 0x24020006, 0x3c010001, +0xac205fe8, 0x8f820204, 0x34420040, 0xaf820204, +0x3c020001, 0x8c426020, 0x24030007, 0x3c010001, +0xac235fd0, 0x34420040, 0x3c010001, 0xac226020, +0x3c020001, 0x8c426000, 0x10400005, 0x0, +0x3c020001, 0x8c425fdc, 0x104000f0, 0x24020002, +0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, +0x104000ea, 0x24020002, 0x3c020001, 0x8c426004, +0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425fdc, +0x3c030001, 0x8c636008, 0x441024, 0x641824, 0x10430004, 0x24020001, 0x3c010001, 0x100000e4, -0xac225ec0, 0x24020003, 0xaca20000, 0x24020008, -0x3c010001, 0xac225ec0, 0x3c020001, 0x8c425efc, -0x1040000c, 0x24020001, 0x3c040001, 0xc004805, -0x8c845ecc, 0x3c020001, 0x8c425f18, 0x14400005, -0x24020001, 0x3c020001, 0x8c425f14, 0x10400006, -0x24020001, 0x3c010001, 0xac223d1c, 0x3c010001, -0x100000cb, 0xac205ee8, 0x3c020001, 0x8c425ee0, -0x3c030001, 0x8c635ecc, 0x2c420001, 0x210c0, -0x30630008, 0x3c010001, 0xac225ee0, 0x3c010001, -0xac235edc, 0x8f830054, 0x24020009, 0x3c010001, -0xac225ec0, 0x3c010001, 0x100000b9, 0xac235ee4, -0x8f830054, 0x3c020001, 0x8c425ee4, 0x2463d8f0, +0xac225fd0, 0x24020003, 0xaca20000, 0x24020008, +0x3c010001, 0xac225fd0, 0x3c020001, 0x8c42600c, +0x1040000c, 0x24020001, 0x3c040001, 0xc004835, +0x8c845fdc, 0x3c020001, 0x8c426028, 0x14400005, +0x24020001, 0x3c020001, 0x8c426024, 0x10400006, +0x24020001, 0x3c010001, 0xac223e2c, 0x3c010001, +0x100000cb, 0xac205ff8, 0x3c020001, 0x8c425ff0, +0x3c030001, 0x8c635fdc, 0x2c420001, 0x210c0, +0x30630008, 0x3c010001, 0xac225ff0, 0x3c010001, +0xac235fec, 0x8f830054, 0x24020009, 0x3c010001, +0xac225fd0, 0x3c010001, 0x100000b9, 0xac235ff4, +0x8f830054, 0x3c020001, 0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, 0x1440009f, 0x0, -0x3c020001, 0x8c425ef0, 0x10400005, 0x0, -0x3c020001, 0x8c425ecc, 0x104000a0, 0x24020002, -0x3c030001, 0x24635ed0, 0x8c620000, 0x2c424e21, -0x1040009a, 0x24020002, 0x3c020001, 0x8c425efc, -0x1040000e, 0x0, 0x3c020001, 0x8c425ecc, -0x3c010001, 0xac205efc, 0x30420080, 0x1040002f, +0x3c020001, 0x8c426000, 0x10400005, 0x0, +0x3c020001, 0x8c425fdc, 0x104000a0, 0x24020002, +0x3c030001, 0x24635fe0, 0x8c620000, 0x2c424e21, +0x1040009a, 0x24020002, 0x3c020001, 0x8c42600c, +0x1040000e, 0x0, 0x3c020001, 0x8c425fdc, +0x3c010001, 0xac20600c, 0x30420080, 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, 0x24020003, 0x10000029, 0x2402000c, 0x3c020001, -0x8c425ecc, 0x30420080, 0x14400005, 0x24020003, +0x8c425fdc, 0x30420080, 0x14400005, 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, -0xac620000, 0x2402000a, 0x3c010001, 0xac225ec0, -0x3c040001, 0x24845f08, 0x8c820000, 0x3c030001, -0x8c635ee0, 0x431025, 0xaf820204, 0x8c830000, -0x3c040001, 0x8c845ee0, 0x2402000b, 0x3c010001, -0xac225ec0, 0x641825, 0x3c010001, 0xac235f10, -0x3c050001, 0x24a55ed0, 0x8ca20000, 0x2c424e21, -0x10400066, 0x24020002, 0x3c020001, 0x8c425f00, +0xac620000, 0x2402000a, 0x3c010001, 0xac225fd0, +0x3c040001, 0x24846018, 0x8c820000, 0x3c030001, +0x8c635ff0, 0x431025, 0xaf820204, 0x8c830000, +0x3c040001, 0x8c845ff0, 0x2402000b, 0x3c010001, +0xac225fd0, 0x641825, 0x3c010001, 0xac236020, +0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, +0x10400066, 0x24020002, 0x3c020001, 0x8c426010, 0x10400005, 0x0, 0x2402000c, 0x3c010001, -0x10000067, 0xac225ec0, 0x3c020001, 0x8c425ef0, -0x10400063, 0x0, 0x3c040001, 0x8c845ecc, -0x10800055, 0x30820008, 0x3c030001, 0x8c635edc, -0x1062005b, 0x24020003, 0x3c010001, 0xac245ef8, +0x10000067, 0xac225fd0, 0x3c020001, 0x8c426000, +0x10400063, 0x0, 0x3c040001, 0x8c845fdc, +0x10800055, 0x30820008, 0x3c030001, 0x8c635fec, +0x1062005b, 0x24020003, 0x3c010001, 0xac246008, 0xaca20000, 0x24020006, 0x3c010001, 0x10000054, -0xac225ec0, 0x8f820200, 0x34420002, 0xaf820200, -0x8f830054, 0x2402000d, 0x3c010001, 0xac225ec0, -0x3c010001, 0xac235ee4, 0x8f830054, 0x3c020001, -0x8c425ee4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400031, 0x0, 0x3c020001, 0x8c425f00, -0x10400020, 0x2402000e, 0x3c030001, 0x8c635f14, -0x3c010001, 0x14600015, 0xac225ec0, 0xc003c6b, -0x0, 0x3c050001, 0x8ca53d18, 0xc004981, -0x2021, 0x3c030001, 0x8c633d18, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d14, -0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d14, -0x431024, 0x3c010001, 0xac223d14, 0x8f830224, -0x3c020200, 0x3c010001, 0xac235f1c, 0x10000020, -0x282a025, 0x3c020001, 0x8c425ef0, 0x10400005, -0x0, 0x3c020001, 0x8c425ecc, 0x1040000f, -0x24020002, 0x3c020001, 0x8c425ed0, 0x2c424e21, -0x1040000a, 0x24020002, 0x3c020001, 0x8c425ef0, -0x1040000f, 0x0, 0x3c020001, 0x8c425ecc, +0xac225fd0, 0x8f820200, 0x34420002, 0xaf820200, +0x8f830054, 0x2402000d, 0x3c010001, 0xac225fd0, +0x3c010001, 0xac235ff4, 0x8f830054, 0x3c020001, +0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, +0x14400031, 0x0, 0x3c020001, 0x8c426010, +0x10400020, 0x2402000e, 0x3c030001, 0x8c636024, +0x3c010001, 0x14600015, 0xac225fd0, 0xc003c9e, +0x0, 0x3c050001, 0x8ca53e28, 0xc0049b1, +0x2021, 0x3c030001, 0x8c633e28, 0x24020004, +0x14620005, 0x2403fffb, 0x3c020001, 0x8c423e24, +0x10000003, 0x2403fff7, 0x3c020001, 0x8c423e24, +0x431024, 0x3c010001, 0xac223e24, 0x8f830224, +0x3c020200, 0x3c010001, 0xac23602c, 0x10000020, +0x282a025, 0x3c020001, 0x8c426000, 0x10400005, +0x0, 0x3c020001, 0x8c425fdc, 0x1040000f, +0x24020002, 0x3c020001, 0x8c425fe0, 0x2c424e21, +0x1040000a, 0x24020002, 0x3c020001, 0x8c426000, +0x1040000f, 0x0, 0x3c020001, 0x8c425fdc, 0x1440000b, 0x0, 0x24020002, 0x3c010001, -0x10000007, 0xac225ec0, 0x3c020001, 0x8c425ef0, -0x10400003, 0x0, 0xc003bad, 0x0, +0x10000007, 0xac225fd0, 0x3c020001, 0x8c426000, +0x10400003, 0x0, 0xc003be0, 0x0, 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, -0x24635f18, 0x8c620000, 0x10400005, 0x34422000, -0x3c010001, 0xac225f0c, 0x10000003, 0xac600000, -0x3c010001, 0xac245f0c, 0x3e00008, 0x0, +0x24636028, 0x8c620000, 0x10400005, 0x34422000, +0x3c010001, 0xac22601c, 0x10000003, 0xac600000, +0x3c010001, 0xac24601c, 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, -0xac225f14, 0x14400067, 0x3c02ffff, 0x34421f0e, +0xac226024, 0x14400067, 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 0x31a02, 0x30820001, -0x21200, 0x3c040001, 0x8c843e5c, 0x621825, -0x331c2, 0x3c030001, 0x24633da8, 0x30828000, +0x21200, 0x3c040001, 0x8c843f6c, 0x621825, +0x331c2, 0x3c030001, 0x24633eb8, 0x30828000, 0x21202, 0x30840001, 0x42200, 0x441025, 0x239c2, 0x61080, 0x431021, 0x471021, 0x90430000, 0x24020001, 0x10620025, 0x0, @@ -8066,86 +8079,86 @@ 0x1062002c, 0x3c05000f, 0x10000037, 0x0, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x3c010001, 0xac205f34, 0x3c010001, -0x10000034, 0xac205f3c, 0x8f820200, 0x34420100, +0xaf820220, 0x3c010001, 0xac206044, 0x3c010001, +0x10000034, 0xac20604c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 0x24020100, 0x3c010001, -0xac225f34, 0x3c010001, 0x10000026, 0xac205f3c, +0xac226044, 0x3c010001, 0x10000026, 0xac20604c, 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x3c010001, 0xac205f34, 0x3c010001, 0x10000019, -0xac235f3c, 0x8f820200, 0x34420100, 0xaf820200, +0x3c010001, 0xac206044, 0x3c010001, 0x10000019, +0xac23604c, 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x24020100, 0x3c010001, 0xac225f34, 0x3c010001, -0x1000000c, 0xac235f3c, 0x34a5ffff, 0x3c040001, -0x24843c08, 0xafa30010, 0xc0029d3, 0xafa00014, +0x24020100, 0x3c010001, 0xac226044, 0x3c010001, +0x1000000c, 0xac23604c, 0x34a5ffff, 0x3c040001, +0x24843d08, 0xafa30010, 0xc002a03, 0xafa00014, 0x10000004, 0x0, 0x24020030, 0x3c010001, -0xac225f18, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0xac226028, 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, 0x0, 0x0, 0x27bdffc8, 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x24843c20, -0x3c050009, 0x3c020001, 0x8c423d18, 0x34a59001, +0xafb00020, 0xc08021, 0x3c040001, 0x24843d20, +0x3c050009, 0x3c020001, 0x8c423e28, 0x34a59001, 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, -0xa7a0001a, 0xafb00014, 0xc0029d3, 0xafa20010, +0xa7a0001a, 0xafb00014, 0xc002a03, 0xafa20010, 0x24020002, 0x126200eb, 0x2e620003, 0x10400005, 0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5, 0x0, 0x24020004, 0x1262006d, 0x24020008, 0x1262006c, 0x3c02ffec, 0x100000de, 0x0, 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, -0x320821, 0xac305f2c, 0x3c024000, 0x2021024, +0x320821, 0xac30603c, 0x3c024000, 0x2021024, 0x10400046, 0x1023c2, 0x30840030, 0x101382, -0x3042000c, 0x3c030001, 0x24633d44, 0x431021, +0x3042000c, 0x3c030001, 0x24633e54, 0x431021, 0x823821, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010001, 0x320821, 0xac225f30, +0x24020100, 0x3c010001, 0x320821, 0xac226040, 0x10000005, 0x3c020080, 0x3c010001, 0x320821, -0xac205f30, 0x3c020080, 0x2021024, 0x10400006, +0xac206040, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac225f38, 0x111140, 0x3c010001, -0x220821, 0xac205f38, 0x94e30000, 0x32024000, +0x10000005, 0xac226048, 0x111140, 0x3c010001, +0x220821, 0xac206048, 0x94e30000, 0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, -0x34420001, 0xc00420a, 0xa4e20002, 0x24040001, -0x2821, 0xc00420a, 0x27a60018, 0x3c020001, -0x8c423d18, 0x24110001, 0x3c010001, 0xac313d24, -0x14530004, 0x32028000, 0xc003bad, 0x0, -0x32028000, 0x10400097, 0x0, 0xc003bad, -0x0, 0x24020002, 0x3c010001, 0xac313d1c, -0x3c010001, 0x1000008f, 0xac223d18, 0x24040001, -0x24050004, 0x27b0001a, 0xc00420a, 0x2003021, -0x24040001, 0x2821, 0xc00420a, 0x2003021, -0x3c020001, 0x521021, 0x8c425f24, 0x3c040001, -0x8c843d18, 0x3c03bfff, 0x3463ffff, 0x3c010001, -0xac333d24, 0x431024, 0x3c010001, 0x320821, -0x10930076, 0xac225f24, 0x10000076, 0x0, +0x34420001, 0xc00423a, 0xa4e20002, 0x24040001, +0x2821, 0xc00423a, 0x27a60018, 0x3c020001, +0x8c423e28, 0x24110001, 0x3c010001, 0xac313e34, +0x14530004, 0x32028000, 0xc003be0, 0x0, +0x32028000, 0x10400097, 0x0, 0xc003be0, +0x0, 0x24020002, 0x3c010001, 0xac313e2c, +0x3c010001, 0x1000008f, 0xac223e28, 0x24040001, +0x24050004, 0x27b0001a, 0xc00423a, 0x2003021, +0x24040001, 0x2821, 0xc00423a, 0x2003021, +0x3c020001, 0x521021, 0x8c426034, 0x3c040001, +0x8c843e28, 0x3c03bfff, 0x3463ffff, 0x3c010001, +0xac333e34, 0x431024, 0x3c010001, 0x320821, +0x10930076, 0xac226034, 0x10000076, 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 0x111140, 0x3c010001, 0x220821, -0xac305f28, 0x3c022000, 0x2021024, 0x10400009, -0x0, 0x3c020001, 0x8c423da4, 0x14400005, -0x24020001, 0x3c010001, 0xac223e58, 0x10000004, -0x3c024000, 0x3c010001, 0xac203e58, 0x3c024000, +0xac306038, 0x3c022000, 0x2021024, 0x10400009, +0x0, 0x3c020001, 0x8c423eb4, 0x14400005, +0x24020001, 0x3c010001, 0xac223f68, 0x10000004, +0x3c024000, 0x3c010001, 0xac203f68, 0x3c024000, 0x2021024, 0x1440001a, 0x0, 0x3c020001, -0x8c423e58, 0x10400005, 0x24022020, 0x3c010001, -0xac223e5c, 0x24020001, 0xaee204b8, 0x3c04bfff, -0x111940, 0x3c020001, 0x431021, 0x8c425f20, -0x3c050001, 0x8ca53d18, 0x3484ffff, 0x441024, -0x3c010001, 0x230821, 0xac225f20, 0x24020001, +0x8c423f68, 0x10400005, 0x24022020, 0x3c010001, +0xac223f6c, 0x24020001, 0xaee204b8, 0x3c04bfff, +0x111940, 0x3c020001, 0x431021, 0x8c426030, +0x3c050001, 0x8ca53e28, 0x3484ffff, 0x441024, +0x3c010001, 0x230821, 0xac226030, 0x24020001, 0x10a20044, 0x0, 0x10000040, 0x0, -0x3c020001, 0x8c423e58, 0x1040001c, 0x24022000, -0x3c010001, 0xac223e5c, 0x3c0300a0, 0x2031024, +0x3c020001, 0x8c423f68, 0x1040001c, 0x24022000, +0x3c010001, 0xac223f6c, 0x3c0300a0, 0x2031024, 0x14430005, 0x111140, 0x3402a000, 0x3c010001, -0x1000002d, 0xac223e5c, 0x3c030001, 0x621821, -0x8c635f28, 0x3c020020, 0x621024, 0x10400004, -0x24022001, 0x3c010001, 0x10000023, 0xac223e5c, +0x1000002d, 0xac223f6c, 0x3c030001, 0x621821, +0x8c636038, 0x3c020020, 0x621024, 0x10400004, +0x24022001, 0x3c010001, 0x10000023, 0xac223f6c, 0x3c020080, 0x621024, 0x1040001f, 0x3402a001, -0x3c010001, 0x1000001c, 0xac223e5c, 0x3c020020, +0x3c010001, 0x1000001c, 0xac223f6c, 0x3c020020, 0x2021024, 0x10400007, 0x111940, 0x24020100, -0x3c010001, 0x230821, 0xac225f34, 0x10000006, +0x3c010001, 0x230821, 0xac226044, 0x10000006, 0x3c020080, 0x111140, 0x3c010001, 0x220821, -0xac205f34, 0x3c020080, 0x2021024, 0x10400006, +0xac206044, 0x3c020080, 0x2021024, 0x10400006, 0x111940, 0x3c020001, 0x3c010001, 0x230821, -0x10000005, 0xac225f3c, 0x111140, 0x3c010001, -0x220821, 0xac205f3c, 0x3c030001, 0x8c633d18, -0x24020001, 0x10620003, 0x0, 0xc003bad, +0x10000005, 0xac22604c, 0x111140, 0x3c010001, +0x220821, 0xac20604c, 0x3c030001, 0x8c633e28, +0x24020001, 0x10620003, 0x0, 0xc003be0, 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020, @@ -8155,95 +8168,95 @@ 0x10400005, 0x24020001, 0x10a2000a, 0x158140, 0x100000ae, 0x2201021, 0x24020004, 0x10a2005e, 0x24020008, 0x10a2005d, 0x152940, 0x100000a7, -0x2201021, 0x3c030001, 0x701821, 0x8c635f2c, +0x2201021, 0x3c030001, 0x701821, 0x8c63603c, 0x3c024000, 0x621024, 0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, -0x300821, 0xac315f24, 0x10000098, 0x2201021, -0x24050001, 0xc0041c8, 0x27a60010, 0x24040001, -0x24050001, 0xc0041c8, 0x27a60010, 0x97a20010, +0x300821, 0xac316034, 0x10000098, 0x2201021, +0x24050001, 0xc0041f8, 0x27a60010, 0x24040001, +0x24050001, 0xc0041f8, 0x27a60010, 0x97a20010, 0x30420004, 0x10400034, 0x3c114000, 0x3c030001, -0x8c633e70, 0x24020003, 0x10620008, 0x2c620004, +0x8c633f80, 0x24020003, 0x10620008, 0x2c620004, 0x14400029, 0x3c028000, 0x24020004, 0x10620014, 0x24040001, 0x10000024, 0x3c028000, 0x24040001, -0x24050011, 0x27b00012, 0xc0041c8, 0x2003021, -0x24040001, 0x24050011, 0xc0041c8, 0x2003021, +0x24050011, 0x27b00012, 0xc0041f8, 0x2003021, +0x24040001, 0x24050011, 0xc0041f8, 0x2003021, 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x10000010, 0x30628000, -0x24050014, 0x27b00012, 0xc0041c8, 0x2003021, -0x24040001, 0x24050014, 0xc0041c8, 0x2003021, +0x24050014, 0x27b00012, 0xc0041f8, 0x2003021, +0x24040001, 0x24050014, 0xc0041f8, 0x2003021, 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 0x3c120002, 0x3c028000, 0x2221025, 0x2531825, 0x10000007, 0x438825, 0x3c110001, 0x2308821, -0x8e315f2c, 0x3c027fff, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0xac315f24, +0x8e31603c, 0x3c027fff, 0x3442ffff, 0x2228824, +0x151140, 0x3c010001, 0x220821, 0xac316034, 0x1000004e, 0x2201021, 0x152940, 0x3c030001, -0x651821, 0x8c635f28, 0x3c024000, 0x621024, +0x651821, 0x8c636038, 0x3c024000, 0x621024, 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010001, 0x250821, 0xac315f20, 0x1000003f, -0x2201021, 0x3c020001, 0x8c423d28, 0x10400033, -0x3c11c00c, 0x3c020001, 0x8c423da4, 0x3c04c00c, -0x34842000, 0x3c030001, 0x8c633e58, 0x2102b, +0x3c010001, 0x250821, 0xac316030, 0x1000003f, +0x2201021, 0x3c020001, 0x8c423e38, 0x10400033, +0x3c11c00c, 0x3c020001, 0x8c423eb4, 0x3c04c00c, +0x34842000, 0x3c030001, 0x8c633f68, 0x2102b, 0x21023, 0x441024, 0x10600003, 0x518825, 0x3c022000, 0x2228825, 0x3c020001, 0x451021, -0x8c425f34, 0x10400003, 0x3c020020, 0x10000004, +0x8c426044, 0x10400003, 0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x151140, 0x3c010001, 0x220821, 0x8c225f3c, +0x151140, 0x3c010001, 0x220821, 0x8c22604c, 0x10400003, 0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, -0x8c423d90, 0x10400002, 0x3c020800, 0x2228825, -0x3c020001, 0x8c423d94, 0x10400002, 0x3c020400, -0x2228825, 0x3c020001, 0x8c423d98, 0x10400006, +0x8c423ea0, 0x10400002, 0x3c020800, 0x2228825, +0x3c020001, 0x8c423ea4, 0x10400002, 0x3c020400, +0x2228825, 0x3c020001, 0x8c423ea8, 0x10400006, 0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, 0x3442ffff, 0x628824, 0x151140, 0x3c010001, -0x220821, 0xac315f20, 0x2201021, 0x8fbf002c, +0x220821, 0xac316030, 0x2201021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0, 0xafb20018, 0x809021, 0xafbf001c, 0xafb10014, -0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d18, +0xafb00010, 0x8f840200, 0x3c030001, 0x8c633e28, 0x8f860220, 0x24020002, 0x106200a6, 0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 0x121940, 0x100000a0, 0x0, 0x24020004, 0x10620053, 0x24020008, 0x10620052, 0x128940, 0x10000099, -0x0, 0x3c050001, 0xa32821, 0x8ca55f2c, -0x3c100001, 0x2038021, 0x8e105f24, 0x3c024000, +0x0, 0x3c050001, 0xa32821, 0x8ca5603c, +0x3c100001, 0x2038021, 0x8e106034, 0x3c024000, 0xa21024, 0x10400038, 0x3c020008, 0x2021024, 0x10400020, 0x34840002, 0x3c020001, 0x431021, -0x8c425f30, 0x10400005, 0x34840020, 0x34840100, +0x8c426040, 0x10400005, 0x34840020, 0x34840100, 0x3c020020, 0x10000006, 0x2028025, 0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024, -0x121140, 0x3c010001, 0x220821, 0x8c225f38, +0x121140, 0x3c010001, 0x220821, 0x8c226048, 0x10400005, 0x3c020001, 0xc23025, 0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, -0x2028024, 0x3c010001, 0x230821, 0xac205f30, -0x3c010001, 0x230821, 0xac205f38, 0xaf840200, +0x2028024, 0x3c010001, 0x230821, 0xac206040, +0x3c010001, 0x230821, 0xac206048, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd, 0x621824, -0xc003bad, 0xaf830200, 0x121140, 0x3c010001, -0x220821, 0x1000004b, 0xac305f24, 0x128940, -0x3c050001, 0xb12821, 0x8ca55f28, 0x3c100001, -0x2118021, 0x8e105f20, 0x3c024000, 0xa21024, -0x14400010, 0x0, 0x3c020001, 0x8c423e58, +0xc003be0, 0xaf830200, 0x121140, 0x3c010001, +0x220821, 0x1000004b, 0xac306034, 0x128940, +0x3c050001, 0xb12821, 0x8ca56038, 0x3c100001, +0x2118021, 0x8e106030, 0x3c024000, 0xa21024, +0x14400010, 0x0, 0x3c020001, 0x8c423f68, 0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003bad, +0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003be0, 0x2028024, 0x3c010001, 0x310821, 0x10000031, -0xac305f20, 0x3c020001, 0x8c423e58, 0x10400005, -0x3c020020, 0x3c020001, 0x8c423da4, 0x10400025, +0xac306030, 0x3c020001, 0x8c423f68, 0x10400005, +0x3c020020, 0x3c020001, 0x8c423eb4, 0x10400025, 0x3c020020, 0xa21024, 0x10400007, 0x34840020, -0x24020100, 0x3c010001, 0x310821, 0xac225f34, +0x24020100, 0x3c010001, 0x310821, 0xac226044, 0x10000006, 0x34840100, 0x3c010001, 0x310821, -0xac205f34, 0x2402feff, 0x822024, 0x3c020080, +0xac206044, 0x2402feff, 0x822024, 0x3c020080, 0xa21024, 0x10400007, 0x121940, 0x3c020001, -0x3c010001, 0x230821, 0xac225f3c, 0x10000008, +0x3c010001, 0x230821, 0xac22604c, 0x10000008, 0xc23025, 0x121140, 0x3c010001, 0x220821, -0xac205f3c, 0x3c02fffe, 0x3442ffff, 0xc23024, +0xac20604c, 0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 0x121140, 0x3c010001, 0x220821, -0xac305f20, 0x8fbf001c, 0x8fb20018, 0x8fb10014, +0xac306030, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821, 0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, 0x30420001, 0x10400004, 0x0, 0x8f820044, @@ -8255,11 +8268,11 @@ u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x66776d61, 0x696e2e63, 0x2c762031, 0x2e312e32, -0x2e343520, 0x31393939, 0x2f30312f, 0x32342030, -0x303a3130, 0x3a353520, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31, +0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234, +0x2030303a, 0x31303a35, 0x35207368, 0x75616e67, +0x20457870, 0x20240000, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, @@ -8326,27 +8339,27 @@ 0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469, 0x6d657200, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x74696d65, 0x722e632c, 0x7620312e, 0x312e322e, -0x33352031, 0x3939392f, 0x30312f32, 0x37203139, -0x3a30393a, 0x35302068, 0x61796573, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x542d446d, 0x61526432, 0x0, -0x542d446d, 0x61526431, 0x0, 0x542d446d, -0x61526442, 0x0, 0x542d446d, 0x61577232, -0x0, 0x542d446d, 0x61577231, 0x0, -0x542d446d, 0x61577242, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e, +0x322e3335, 0x20313939, 0x392f3031, 0x2f323720, +0x31393a30, 0x393a3530, 0x20686179, 0x65732045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x542d446d, 0x61526432, +0x0, 0x542d446d, 0x61526431, 0x0, +0x542d446d, 0x61526442, 0x0, 0x542d446d, +0x61577232, 0x0, 0x542d446d, 0x61577231, +0x0, 0x542d446d, 0x61577242, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x636f6d6d, 0x616e642e, 0x632c7620, 0x312e312e, -0x322e3238, 0x20313939, 0x392f3031, 0x2f323020, -0x31393a34, 0x393a3439, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x65767452, 0x6e674600, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e, +0x312e322e, 0x32382031, 0x3939392f, 0x30312f32, +0x30203139, 0x3a34393a, 0x34392073, 0x6875616e, +0x67204578, 0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, @@ -8363,25 +8376,25 @@ 0x8218, 0x827c, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d636173, 0x742e632c, 0x7620312e, 0x312e322e, -0x38203139, 0x39382f31, 0x322f3038, 0x2030323a, -0x33363a33, 0x36207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x6164644d, 0x63447570, 0x0, -0x6164644d, 0x6346756c, 0x0, 0x64656c4d, -0x634e6f45, 0x0, 0x0, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e, +0x322e3820, 0x31393938, 0x2f31322f, 0x30382030, +0x323a3336, 0x3a333620, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x6164644d, 0x63447570, +0x0, 0x6164644d, 0x6346756c, 0x0, +0x64656c4d, 0x634e6f45, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x646d612e, 0x632c7620, 0x312e312e, 0x322e3234, -0x20313939, 0x382f3132, 0x2f323120, 0x30303a33, -0x333a3039, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e, +0x32342031, 0x3939382f, 0x31322f32, 0x31203030, +0x3a33333a, 0x30392073, 0x6875616e, 0x67204578, +0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, @@ -8390,81 +8403,84 @@ 0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00, 0x2372446d, 0x6141544e, 0x0, 0x72446d61, 0x41544e30, 0x0, 0x72446d61, 0x41544e31, -0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e, -0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e, -0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f646d, -0x612e6300, 0x2377446d, 0x6141544e, 0x0, -0x77446d61, 0x41544e30, 0x0, 0x77446d61, -0x41544e31, 0x0, 0x0, 0x0, +0x0, 0x72446d61, 0x34476200, 0x2a50414e, +0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f, +0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63, +0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d, +0x6141544e, 0x0, 0x77446d61, 0x41544e30, +0x0, 0x77446d61, 0x41544e31, 0x0, +0x77446d61, 0x34476200, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x74726163, 0x652e632c, 0x7620312e, 0x312e322e, -0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, -0x35303a32, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x64617461, 0x2e632c76, 0x20312e31, 0x2e322e31, -0x32203139, 0x39392f30, 0x312f3230, 0x2031393a, -0x34393a35, 0x31207368, 0x75616e67, 0x20457870, -0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x2331204d, 0x6f6e2046, 0x65622031, 0x2031373a, -0x30313a30, 0x36205053, 0x54203139, 0x39390000, -0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031373a, 0x30313a30, 0x36000000, 0x46575f43, -0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, -0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, -0x4f53543a, 0x20636f6d, 0x70757465, 0x0, -0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, -0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f, -0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, -0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, -0x2e320000, 0x0, 0x12030303, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e, +0x322e3520, 0x31393938, 0x2f30392f, 0x33302031, +0x383a3530, 0x3a323820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d656d2e, 0x632c7620, 0x312e312e, 0x322e3520, -0x31393938, 0x2f30392f, 0x33302031, 0x383a3530, -0x3a303820, 0x73687561, 0x6e672045, 0x78702024, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32, +0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, +0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x46575f56, 0x45525349, +0x4f4e3a20, 0x23312054, 0x75652041, 0x70722032, +0x30203137, 0x3a32333a, 0x30322050, 0x44542031, +0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, +0x494d453a, 0x2031373a, 0x32333a30, 0x32000000, +0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, +0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, +0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, +0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44, +0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f, +0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, +0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e, +0x20322e37, 0x2e320000, 0x0, 0x12030303, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x73656e64, 0x2e632c76, 0x20312e31, 0x2e322e34, -0x34203139, 0x39382f31, 0x322f3231, 0x2030303a, -0x33333a31, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x69736e74, 0x54637055, 0x0, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e, +0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, +0x35303a30, 0x38207368, 0x75616e67, 0x20457870, +0x20240000, 0x24486561, 0x6465723a, 0x202f7072, +0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32, +0x2e343420, 0x31393938, 0x2f31322f, 0x32312030, +0x303a3333, 0x3a313820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x69736e74, 0x54637055, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x72656376, 0x2e632c76, 0x20312e31, 0x2e322e35, -0x33203139, 0x39392f30, 0x312f3136, 0x2030323a, -0x35353a34, 0x33207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x72784672, 0x6d324c67, 0x0, -0x72784e6f, 0x53744264, 0x0, 0x72784e6f, -0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264, -0x0, 0x7278436b, 0x446d6146, 0x0, -0x72785144, 0x6d457846, 0x0, 0x72785144, -0x6d614600, 0x72785144, 0x4c426446, 0x0, -0x72785144, 0x6d426446, 0x0, 0x72784372, -0x63506164, 0x0, 0x72536d51, 0x446d6146, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32, +0x2e353320, 0x31393939, 0x2f30312f, 0x31362030, +0x323a3535, 0x3a343320, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x72784672, 0x6d324c67, +0x0, 0x72784e6f, 0x53744264, 0x0, +0x72784e6f, 0x4d694264, 0x0, 0x72784e6f, +0x4a6d4264, 0x0, 0x7278436b, 0x446d6146, +0x0, 0x72785144, 0x6d457846, 0x0, +0x72785144, 0x6d614600, 0x72785144, 0x4c426446, +0x0, 0x72785144, 0x6d426446, 0x0, +0x72784372, 0x63506164, 0x0, 0x72536d51, +0x446d6146, 0x0, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x6d61632e, 0x632c7620, 0x312e312e, 0x322e3232, -0x20313939, 0x382f3132, 0x2f303820, 0x30323a33, -0x363a3330, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x65767452, 0x6e674600, 0x51657674, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e, +0x32322031, 0x3939382f, 0x31322f30, 0x38203032, +0x3a33363a, 0x33302073, 0x6875616e, 0x67204578, +0x70202400, 0x65767452, 0x6e674600, 0x51657674, 0x46000000, 0x51657674, 0x505f4600, 0x4d657674, 0x526e6746, 0x0, 0x4d516576, 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, @@ -8476,32 +8492,33 @@ 0x6c696e6b, 0x55500000, 0x0, 0x0, 0x0, 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f6e6963, 0x2f667732, 0x2f636f6d, 0x6d6f6e2f, -0x636b7375, 0x6d2e632c, 0x7620312e, 0x312e322e, -0x39203139, 0x39392f30, 0x312f3134, 0x2030303a, -0x30333a34, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0xff04, -0xff34, 0xff4c, 0xff78, 0xffa4, -0xffb8, 0xfff4, 0x10394, 0x10174, -0x101ac, 0x100a4, 0x10200, 0x10228, -0x1025c, 0x100e8, 0x10394, 0x10174, -0x101ac, 0x101d0, 0x10200, 0x10228, -0x1025c, 0x10288, 0x0, 0x0, -0x0, 0x1097c, 0x10a4c, 0x10b24, -0x10bf4, 0x10c50, 0x10d2c, 0x10d54, -0x10e30, 0x10e58, 0x11000, 0x11028, -0x111d0, 0x113c8, 0x1165c, 0x11570, -0x1165c, 0x11688, 0x111f8, 0x113a0, -0x0, 0x1198c, 0x119cc, 0x11a5c, -0x11aa0, 0x11b04, 0x11b90, 0x11bc4, -0x11c4c, 0x11ce4, 0x11db4, 0x11df4, -0x11e78, 0x11e9c, 0x11fac, 0x646f4261, +0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, +0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e, +0x322e3920, 0x31393939, 0x2f30312f, 0x31342030, +0x303a3033, 0x3a343820, 0x73687561, 0x6e672045, +0x78702024, 0x0, 0x65767452, 0x6e674600, +0x51657674, 0x46000000, 0x51657674, 0x505f4600, +0x4d657674, 0x526e6746, 0x0, 0x4d516576, +0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, +0x6e495f46, 0x0, 0x5173436f, 0x6e734600, +0x51725072, 0x6f644600, 0x0, 0x0, +0x0, 0x50726f62, 0x65506879, 0x0, +0x6c6e6b41, 0x53535254, 0x0, 0xffc4, +0xfff4, 0x1000c, 0x10038, 0x10064, +0x10078, 0x100b4, 0x10454, 0x10234, +0x1026c, 0x10164, 0x102c0, 0x102e8, +0x1031c, 0x101a8, 0x10454, 0x10234, +0x1026c, 0x10290, 0x102c0, 0x102e8, +0x1031c, 0x10348, 0x0, 0x0, +0x0, 0x10a3c, 0x10b0c, 0x10be4, +0x10cb4, 0x10d10, 0x10dec, 0x10e14, +0x10ef0, 0x10f18, 0x110c0, 0x110e8, +0x11290, 0x11488, 0x1171c, 0x11630, +0x1171c, 0x11748, 0x112b8, 0x11460, +0x0, 0x11a4c, 0x11a8c, 0x11b1c, +0x11b60, 0x11bc4, 0x11c50, 0x11c84, +0x11d0c, 0x11da4, 0x11e74, 0x11eb4, +0x11f38, 0x11f5c, 0x1206c, 0x646f4261, 0x73655067, 0x0, 0x0, 0x0, 0x0, 0x73746d61, 0x634c4e4b, 0x0, 0x0, 0x0 }; diff -u --recursive --new-file v2.2.10/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.2.10/linux/drivers/net/arcnet.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/arcnet.c Mon Aug 9 12:04:39 1999 @@ -471,9 +471,16 @@ #ifdef CONFIG_ARCNET_1051 /* Initialize the RFC1051-encap protocol driver */ - lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL); + lp->sdev=(struct device *)kmalloc(sizeof(struct device)+10,GFP_KERNEL); + if(lp->sdev = NULL) + { + if(lp->edev) + kfree(lp->edev); + lp->edev=NULL; + return -ENOMEM; + } memcpy(lp->sdev,dev,sizeof(struct device)); - lp->sdev->name=(char *)kmalloc(10,GFP_KERNEL); + lp->sdev->name=(char *)(lp+1); sprintf(lp->sdev->name,"%ss",dev->name); lp->sdev->init=arcnetS_init; register_netdevice(lp->sdev); diff -u --recursive --new-file v2.2.10/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c --- v2.2.10/linux/drivers/net/arlan-proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan-proc.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1059 @@ +#include +#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 --recursive --new-file v2.2.10/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.2.10/linux/drivers/net/arlan.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,2080 @@ +/* + * 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 +#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 --recursive --new-file v2.2.10/linux/drivers/net/arlan.h linux/drivers/net/arlan.h --- v2.2.10/linux/drivers/net/arlan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/arlan.h Mon Aug 9 12:04:39 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 --recursive --new-file v2.2.10/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c --- v2.2.10/linux/drivers/net/bagetlance.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/bagetlance.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1363 @@ +/* $Id$ + * vmelance.c: Ethernet driver for VME Lance cards on Baget/MIPS + * This code stolen and adopted from linux/drivers/net/atarilance.c + * See that for author info + * + * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov + */ + +/* + * Driver code for Baget/Lance taken from atarilance.c, which also + * works well in case of Besta. Most significant changes made here + * related with 16BIT-only access to A24 space. + */ + +static char *version = "bagetlance.c: v1.1 11/10/98\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#define BAGET_LANCE_IRQ BAGET_IRQ_MASK(0xdf) + +/* + * Define following if you don't need 16BIT-only access to Lance memory + * (Normally BAGET needs it) + */ +#undef NORMAL_MEM_ACCESS + +/* Debug level: + * 0 = silent, print only serious errors + * 1 = normal, print error messages + * 2 = debug, print debug infos + * 3 = debug, print even more debug infos (packet data) + */ + +#define LANCE_DEBUG 1 + +#ifdef LANCE_DEBUG +static int lance_debug = LANCE_DEBUG; +#else +static int lance_debug = 1; +#endif +MODULE_PARM(lance_debug, "i"); + +/* Print debug messages on probing? */ +#undef LANCE_DEBUG_PROBE + +#define DPRINTK(n,a) \ + do { \ + if (lance_debug >= n) \ + printk a; \ + } while( 0 ) + +#ifdef LANCE_DEBUG_PROBE +# define PROBE_PRINT(a) printk a +#else +# define PROBE_PRINT(a) +#endif + +/* These define the number of Rx and Tx buffers as log2. (Only powers + * of two are valid) + * Much more rx buffers (32) are reserved than tx buffers (8), since receiving + * is more time critical then sending and packets may have to remain in the + * board's memory when main memory is low. + */ + +/* Baget Lance has 64K on-board memory, so it looks we can't increase + buffer quantity (40*1.5K is about 64K) */ + +#define TX_LOG_RING_SIZE 3 +#define RX_LOG_RING_SIZE 5 + +/* These are the derived values */ + +#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE) +#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) + +#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE) +#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) + +/* The LANCE Rx and Tx ring descriptors. */ +struct lance_rx_head { + volatile unsigned short base; /* Low word of base addr */ +#ifdef NORMAL_MEM_ACCESS + /* Following two fields are joined into one short to guarantee + 16BIT access to Baget lance registers */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ +#else +/* Following macros are used as replecements to 8BIT fields */ +#define GET_FLAG(h) (((h)->flag_base_hi >> 8) & 0xff) +#define SET_FLAG(h,f) (h)->flag_base_hi = ((h)->flag_base_hi & 0xff) | \ + (((unsigned)(f)) << 8) + volatile unsigned short flag_base_hi; +#endif + volatile short buf_length; /* This length is 2s complement! */ + volatile short msg_length; /* This length is "normal". */ +}; + + +struct lance_tx_head { + volatile unsigned short base; /* Low word of base addr */ +#ifdef NORMAL_MEM_ACCESS +/* See comments above about 8BIT-access Baget A24-space problems */ + volatile unsigned char flag; + unsigned char base_hi; /* High word of base addr (unused) */ +#else + volatile unsigned short flag_base_hi; +#endif + volatile short length; /* Length is 2s complement! */ + volatile short misc; +}; + +struct ringdesc { + volatile unsigned short adr_lo; /* Low 16 bits of address */ +#ifdef NORMAL_MEM_ACCESS +/* See comments above about 8BIT-access Bage A24-space problems */ + unsigned char len; /* Length bits */ + unsigned char adr_hi; /* High 8 bits of address (unused) */ +#else + volatile unsigned short len_adr_hi; +#endif +}; + +/* The LANCE initialization block, described in databook. */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode */ + unsigned char hwaddr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter (unused). */ + /* Receive and transmit ring base, along with length bits. */ + struct ringdesc rx_ring; + struct ringdesc tx_ring; +}; + +/* The whole layout of the Lance shared memory */ +struct lance_memory { + struct lance_init_block init; + struct lance_tx_head tx_head[TX_RING_SIZE]; + struct lance_rx_head rx_head[RX_RING_SIZE]; + char packet_area[0]; /* packet data follow after the + * init block and the ring + * descriptors and are located + * at runtime */ +}; + +/* RieblCard specifics: + * The original TOS driver for these cards reserves the area from offset + * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the + * Ethernet address there, and the magic for verifying the data's validity. + * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe + * is reserved for the interrupt vector number. + */ +#define RIEBL_RSVD_START 0xee70 +#define RIEBL_RSVD_END 0xeec0 +#define RIEBL_MAGIC 0x09051990 +#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a)) +#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e)) +#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe)) + +/* This is a default address for the old RieblCards without a battery + * that have no ethernet address at boot time. 00:00:36:04 is the + * prefix for Riebl cards, the 00:00 at the end is arbitrary. + */ + +static unsigned char OldRieblDefHwaddr[6] = { + 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 +}; + +/* I/O registers of the Lance chip */ + +struct lance_ioreg { +/* base+0x0 */ volatile unsigned short data; +/* base+0x2 */ volatile unsigned short addr; + unsigned char _dummy1[3]; +/* base+0x7 */ volatile unsigned char ivec; + unsigned char _dummy2[5]; +/* base+0xd */ volatile unsigned char eeprom; + unsigned char _dummy3; +/* base+0xf */ volatile unsigned char mem; +}; + +/* Types of boards this driver supports */ + +enum lance_type { + OLD_RIEBL, /* old Riebl card without battery */ + NEW_RIEBL, /* new Riebl card with battery */ + PAM_CARD /* PAM card with EEPROM */ +}; + +static char *lance_names[] = { + "Riebl-Card (without battery)", + "Riebl-Card (with battery)", + "PAM intern card" +}; + +/* The driver's private device structure */ + +struct lance_private { + enum lance_type cardtype; + struct lance_ioreg *iobase; + struct lance_memory *mem; + int cur_rx, cur_tx; /* The next free ring entry */ + int dirty_tx; /* Ring entries to be freed. */ + /* copy function */ + void *(*memcpy_f)( void *, const void *, size_t ); + struct net_device_stats stats; +/* These two must be ints for set_bit() */ + int tx_full; + int lock; +}; + +/* I/O register access macros */ + +#define MEM lp->mem +#define DREG IO->data +#define AREG IO->addr +#define REGA(a) ( AREG = (a), DREG ) + +/* Definitions for packet buffer access: */ +#define PKT_BUF_SZ 1544 +/* Get the address of a packet buffer corresponding to a given buffer head */ +#define PKTBUF_ADDR(head) (((unsigned char *)(MEM)) + (head)->base) + +/* Possible memory/IO addresses for probing */ + +struct lance_addr { + unsigned long memaddr; + unsigned long ioaddr; + int slow_flag; +} lance_addr_list[] = { + { BAGET_LANCE_MEM_BASE, BAGET_LANCE_IO_BASE, 1 } /* Baget Lance */ +}; + +#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list)) + + +#define LANCE_HI_BASE (0xff & (BAGET_LANCE_MEM_BASE >> 16)) + +/* Definitions for the Lance */ + +/* tx_head flags */ +#define TMD1_ENP 0x01 /* end of packet */ +#define TMD1_STP 0x02 /* start of packet */ +#define TMD1_DEF 0x04 /* deferred */ +#define TMD1_ONE 0x08 /* one retry needed */ +#define TMD1_MORE 0x10 /* more than one retry needed */ +#define TMD1_ERR 0x40 /* error summary */ +#define TMD1_OWN 0x80 /* ownership (set: chip owns) */ + +#define TMD1_OWN_CHIP TMD1_OWN +#define TMD1_OWN_HOST 0 + +/* tx_head misc field */ +#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */ +#define TMD3_RTRY 0x0400 /* failed after 16 retries */ +#define TMD3_LCAR 0x0800 /* carrier lost */ +#define TMD3_LCOL 0x1000 /* late collision */ +#define TMD3_UFLO 0x4000 /* underflow (late memory) */ +#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */ + +/* rx_head flags */ +#define RMD1_ENP 0x01 /* end of packet */ +#define RMD1_STP 0x02 /* start of packet */ +#define RMD1_BUFF 0x04 /* buffer error */ +#define RMD1_CRC 0x08 /* CRC error */ +#define RMD1_OFLO 0x10 /* overflow */ +#define RMD1_FRAM 0x20 /* framing error */ +#define RMD1_ERR 0x40 /* error summary */ +#define RMD1_OWN 0x80 /* ownership (set: ship owns) */ + +#define RMD1_OWN_CHIP RMD1_OWN +#define RMD1_OWN_HOST 0 + +/* register names */ +#define CSR0 0 /* mode/status */ +#define CSR1 1 /* init block addr (low) */ +#define CSR2 2 /* init block addr (high) */ +#define CSR3 3 /* misc */ +#define CSR8 8 /* address filter */ +#define CSR15 15 /* promiscuous mode */ + +/* CSR0 */ +/* (R=readable, W=writeable, S=set on write, C=clear on write) */ +#define CSR0_INIT 0x0001 /* initialize (RS) */ +#define CSR0_STRT 0x0002 /* start (RS) */ +#define CSR0_STOP 0x0004 /* stop (RS) */ +#define CSR0_TDMD 0x0008 /* transmit demand (RS) */ +#define CSR0_TXON 0x0010 /* transmitter on (R) */ +#define CSR0_RXON 0x0020 /* receiver on (R) */ +#define CSR0_INEA 0x0040 /* interrupt enable (RW) */ +#define CSR0_INTR 0x0080 /* interrupt active (R) */ +#define CSR0_IDON 0x0100 /* initialization done (RC) */ +#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */ +#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */ +#define CSR0_MERR 0x0800 /* memory error (RC) */ +#define CSR0_MISS 0x1000 /* missed frame (RC) */ +#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */ +#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */ +#define CSR0_ERR 0x8000 /* error (RC) */ + +/* CSR3 */ +#define CSR3_BCON 0x0001 /* byte control */ +#define CSR3_ACON 0 // fixme: 0x0002 /* ALE control */ +#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */ + + + +/***************************** Prototypes *****************************/ + +static int addr_accessible( volatile void *regp, int wordflag, int + writeflag ); +static unsigned long lance_probe1( struct device *dev, struct lance_addr + *init_rec ); +static int lance_open( struct device *dev ); +static void lance_init_ring( struct device *dev ); +static int lance_start_xmit( struct sk_buff *skb, struct device *dev ); +static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp ); +static int lance_rx( struct device *dev ); +static int lance_close( struct device *dev ); +static struct net_device_stats *lance_get_stats( struct device *dev ); +static void set_multicast_list( struct device *dev ); +static int lance_set_mac_address( struct device *dev, void *addr ); + +/************************* End of Prototypes **************************/ + +/* Network traffic statistic (bytes) */ + +int lance_stat = 0; + +static void update_lance_stat (int len) { + lance_stat += len; +} + +/* + This function is used to access Baget/Lance memory to avoid + 8/32BIT access to VAC A24 space + ALL memcpy calls was chenged to this function to avoid dbe problems + Don't confuse with function name -- it stays from original code +*/ + +void *slow_memcpy( void *dst, const void *src, size_t len ) + +{ + unsigned long to = (unsigned long)dst; + unsigned long from = (unsigned long)src; + unsigned long to_end = to +len; + + /* Unaligned flags */ + + int odd_from = from & 1; + int odd_to = to & 1; + int odd_to_end = to_end & 1; + + /* Align for 16BIT-access first */ + + register unsigned short *from_a = (unsigned short*) (from & ~1); + register unsigned short *to_a = (unsigned short*) (to & ~1); + register unsigned short *to_end_a = (unsigned short*) (to_end & ~1); + + /* Caching values -- not in loop invariant */ + + register unsigned short from_v; + register unsigned short to_v; + + /* Invariant is: from_a and to_a are pointers before or exactly to + currently copying byte */ + + if (odd_to) { + /* First byte unaligned case */ + from_v = *from_a; + to_v = *to_a; + + to_v &= ~0xff; + to_v |= 0xff & (from_v >> (odd_from ? 0 : 8)); + *to_a++ = to_v; + + if (odd_from) from_a++; + } + if (odd_from == odd_to) { + /* Same parity */ + while (to_a + 7 < to_end_a) { + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "lh\t%2,0(%1)\n\t" + "nop\n\t" + "lh\t%3,2(%1)\n\t" + "sh\t%2,0(%0)\n\t" + "lh\t%4,4(%1)\n\t" + "sh\t%3,2(%0)\n\t" + "lh\t%5,6(%1)\n\t" + "sh\t%4,4(%0)\n\t" + "lh\t%2,8(%1)\n\t" + "sh\t%5,6(%0)\n\t" + "lh\t%3,10(%1)\n\t" + "sh\t%2,8(%0)\n\t" + "lh\t%4,12(%1)\n\t" + "sh\t%3,10(%0)\n\t" + "lh\t%5,14(%1)\n\t" + "sh\t%4,12(%0)\n\t" + "nop\n\t" + "sh\t%5,14(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + :"0" (to_a), "1" (from_a) + :"memory"); + + to_a += 8; + from_a += 8; + + } + while (to_a < to_end_a) { + *to_a++ = *from_a++; + } + } else { + /* Different parity */ + from_v = *from_a; + while (to_a < to_end_a) { + unsigned short from_v_next; + from_v_next = *++from_a; + *to_a++ = ((from_v & 0xff)<<8) | ((from_v_next>>8) & 0xff); + from_v = from_v_next; + } + + } + if (odd_to_end) { + /* Last byte unaligned case */ + to_v = *to_a; + from_v = *from_a; + + to_v &= ~0xff00; + if (odd_from == odd_to) { + to_v |= from_v & 0xff00; + } else { + to_v |= (from_v<<8) & 0xff00; + } + + *to_a = to_v; + } + + update_lance_stat( len ); + + return( dst ); +} + + +__initfunc(int bagetlance_probe( struct device *dev )) + +{ int i; + static int found = 0; + + if (found) + /* Assume there's only one board possible... That seems true, since + * the Riebl/PAM board's address cannot be changed. */ + return( ENODEV ); + + for( i = 0; i < N_LANCE_ADDR; ++i ) { + if (lance_probe1( dev, &lance_addr_list[i] )) { + found = 1; + return( 0 ); + } + } + + return( ENODEV ); +} + + + +/* Derived from hwreg_present() in vme/config.c: */ + +__initfunc(static int addr_accessible( volatile void *regp, + int wordflag, + int writeflag )) +{ + /* We have a fine function to do it */ + extern int try_read(unsigned long, int); + return try_read((unsigned long)regp, sizeof(short)) != -1; +} + + + +/* Original atari driver uses it */ +#define IRQ_TYPE_PRIO SA_INTERRUPT +#define IRQ_SOURCE_TO_VECTOR(x) (x) + +__initfunc(static unsigned long lance_probe1( struct device *dev, + struct lance_addr *init_rec )) + +{ volatile unsigned short *memaddr = + (volatile unsigned short *)init_rec->memaddr; + volatile unsigned short *ioaddr = + (volatile unsigned short *)init_rec->ioaddr; + struct lance_private *lp; + struct lance_ioreg *IO; + int i; + static int did_version = 0; + unsigned short save1, save2; + + PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", + (long)memaddr, (long)ioaddr )); + + /* Test whether memory readable and writable */ + PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" )); + if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; + + if ((unsigned long)memaddr >= KSEG2) { + extern int kseg2_alloc_io (unsigned long addr, unsigned long size); + if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) { + printk("bagetlance: unable map lance memory\n"); + goto probe_fail; + } + } + + /* Written values should come back... */ + PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" )); + save1 = *memaddr; + *memaddr = 0x0001; + if (*memaddr != 0x0001) goto probe_fail; + PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" )); + *memaddr = 0x0000; + if (*memaddr != 0x0000) goto probe_fail; + *memaddr = save1; + + /* First port should be readable and writable */ + PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" )); + if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail; + + /* and written values should be readable */ + PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" )); + save2 = ioaddr[1]; + ioaddr[1] = 0x0001; + if (ioaddr[1] != 0x0001) goto probe_fail; + + /* The CSR0_INIT bit should not be readable */ + PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" )); + save1 = ioaddr[0]; + ioaddr[1] = CSR0; + ioaddr[0] = CSR0_INIT | CSR0_STOP; + if (ioaddr[0] != CSR0_STOP) { + ioaddr[0] = save1; + ioaddr[1] = save2; + goto probe_fail; + } + PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" )); + ioaddr[0] = CSR0_STOP; + if (ioaddr[0] != CSR0_STOP) { + ioaddr[0] = save1; + ioaddr[1] = save2; + goto probe_fail; + } + + /* Now ok... */ + PROBE_PRINT(( "lance_probe1: Lance card detected\n" )); + goto probe_ok; + + probe_fail: + return( 0 ); + + probe_ok: + init_etherdev( dev, sizeof(struct lance_private) ); + if (!dev->priv) + dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); + lp = (struct lance_private *)dev->priv; + MEM = (struct lance_memory *)memaddr; + IO = lp->iobase = (struct lance_ioreg *)ioaddr; + dev->base_addr = (unsigned long)ioaddr; /* informational only */ + lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy; + + REGA( CSR0 ) = CSR0_STOP; + + /* Now test for type: If the eeprom I/O port is readable, it is a + * PAM card */ + if (addr_accessible( &(IO->eeprom), 0, 0 )) { + /* Switch back to Ram */ + i = IO->mem; + lp->cardtype = PAM_CARD; + } +#ifdef NORMAL_MEM_ACCESS + else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) { +#else + else if (({ + unsigned short *a = (unsigned short*)RIEBL_MAGIC_ADDR; + (((int)a[0]) << 16) + ((int)a[1]) == RIEBL_MAGIC; + })) { +#endif + lp->cardtype = NEW_RIEBL; + } + else + lp->cardtype = OLD_RIEBL; + + if (lp->cardtype == PAM_CARD || + memaddr == (unsigned short *)0xffe00000) { + /* PAMs card and Riebl on ST use level 5 autovector */ + request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev); + dev->irq = (unsigned short)BAGET_LANCE_IRQ; + } + else { + /* For VME-RieblCards, request a free VME int; + * (This must be unsigned long, since dev->irq is short and the + * IRQ_MACHSPEC bit would be cut off...) + */ + unsigned long irq = BAGET_LANCE_IRQ; + if (!irq) { + printk( "Lance: request for VME interrupt failed\n" ); + return( 0 ); + } + request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev); + dev->irq = irq; + } + + printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ", + dev->name, lance_names[lp->cardtype], + (unsigned long)ioaddr, + (unsigned long)memaddr, + dev->irq, + init_rec->slow_flag ? " (slow memcpy)" : "" ); + + /* Get the ethernet address */ + switch( lp->cardtype ) { + case OLD_RIEBL: + /* No ethernet address! (Set some default address) */ + slow_memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 ); + break; + case NEW_RIEBL: + lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 ); + break; + case PAM_CARD: + i = IO->eeprom; + for( i = 0; i < 6; ++i ) + dev->dev_addr[i] = + ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) | + ((((unsigned short *)MEM)[i*2+1] & 0x0f)); + i = IO->mem; + break; + } + for( i = 0; i < 6; ++i ) + printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); + if (lp->cardtype == OLD_RIEBL) { + printk( "%s: Warning: This is a default ethernet address!\n", + dev->name ); + printk( " Use \"ifconfig hw ether ...\" to set the address.\n" ); + } + + MEM->init.mode = 0x0000; /* Disable Rx and Tx. */ + + { + unsigned char hwaddr[6]; + for( i = 0; i < 6; i++ ) + hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */ + slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr)); + } + + MEM->init.filter[0] = 0x00000000; + MEM->init.filter[1] = 0x00000000; + MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head ); + +#ifdef NORMAL_MEM_ACCESS + MEM->init.rx_ring.adr_hi = LANCE_HI_BASE; + MEM->init.rx_ring.len = RX_RING_LEN_BITS; +#else + MEM->init.rx_ring.len_adr_hi = + ((unsigned)RX_RING_LEN_BITS << 8) | LANCE_HI_BASE; +#endif + + + MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head ); + +#ifdef NORMAL_MEM_ACCESS + MEM->init.tx_ring.adr_hi = LANCE_HI_BASE; + MEM->init.tx_ring.len = TX_RING_LEN_BITS; +#else + MEM->init.tx_ring.len_adr_hi = + ((unsigned)TX_RING_LEN_BITS<<8) | LANCE_HI_BASE; +#endif + + if (lp->cardtype == PAM_CARD) + IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq); + else + *RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq); + + if (did_version++ == 0) + DPRINTK( 1, ( version )); + + /* The LANCE-specific entries in the device structure. */ + dev->open = &lance_open; + dev->hard_start_xmit = &lance_start_xmit; + dev->stop = &lance_close; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &lance_set_mac_address; + dev->start = 0; + + memset( &lp->stats, 0, sizeof(lp->stats) ); + + return( 1 ); +} + + +static int lance_open( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + int i; + + DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); + + lance_init_ring(dev); + /* Re-initialize the LANCE, and start it when done. */ + + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + REGA( CSR2 ) = 0; + REGA( CSR1 ) = 0; + REGA( CSR0 ) = CSR0_INIT; + /* From now on, AREG is kept to point to CSR0 */ + + i = 1000000; + while (--i > 0) + if (DREG & CSR0_IDON) + break; + if (i < 0 || (DREG & CSR0_ERR)) { + DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n", + dev->name, i, DREG )); + DREG = CSR0_STOP; + return( -EIO ); + } + DREG = CSR0_IDON; + DREG = CSR0_STRT; + DREG = CSR0_INEA; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG )); + MOD_INC_USE_COUNT; + + return( 0 ); +} + + +/* Initialize the LANCE Rx and Tx rings. */ + +static void lance_init_ring( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + int i; + unsigned offset; + + lp->lock = 0; + lp->tx_full = 0; + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_tx = 0; + + offset = offsetof( struct lance_memory, packet_area ); + +/* If the packet buffer at offset 'o' would conflict with the reserved area + * of RieblCards, advance it */ +#define CHECK_OFFSET(o) \ + do { \ + if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) { \ + if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \ + : (o) < RIEBL_RSVD_END) \ + (o) = RIEBL_RSVD_END; \ + } \ + } while(0) + + for( i = 0; i < TX_RING_SIZE; i++ ) { + CHECK_OFFSET(offset); + MEM->tx_head[i].base = offset; +#ifdef NORMAL_MEM_ACCESS + MEM->tx_head[i].flag = TMD1_OWN_HOST; + MEM->tx_head[i].base_hi = LANCE_HI_BASE; +#else + MEM->tx_head[i].flag_base_hi = + (TMD1_OWN_HOST<<8) | LANCE_HI_BASE; +#endif + MEM->tx_head[i].length = 0; + MEM->tx_head[i].misc = 0; + offset += PKT_BUF_SZ; + } + + for( i = 0; i < RX_RING_SIZE; i++ ) { + CHECK_OFFSET(offset); + MEM->rx_head[i].base = offset; +#ifdef NORMAL_MEM_ACCESS + MEM->rx_head[i].flag = TMD1_OWN_CHIP; + MEM->rx_head[i].base_hi = LANCE_HI_BASE; +#else + MEM->rx_head[i].flag_base_hi = + (TMD1_OWN_CHIP<<8) | LANCE_HI_BASE; +#endif + MEM->rx_head[i].buf_length = -PKT_BUF_SZ; + MEM->rx_head[i].msg_length = 0; + offset += PKT_BUF_SZ; + } +} + + +static int lance_start_xmit( struct sk_buff *skb, struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + int entry, len; + struct lance_tx_head *head; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return( 1 ); + AREG = CSR0; + DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", + dev->name, DREG )); + DREG = CSR0_STOP; + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + lp->stats.tx_errors++; +#ifndef final_version + { int i; + DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n", + lp->dirty_tx, lp->cur_tx, + lp->tx_full ? " (full)" : "", + lp->cur_rx )); + for( i = 0 ; i < RX_RING_SIZE; i++ ) + DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n", + i, MEM->rx_head[i].base, + -MEM->rx_head[i].buf_length, + MEM->rx_head[i].msg_length )); + for( i = 0 ; i < TX_RING_SIZE; i++ ) + DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n", + i, MEM->tx_head[i].base, + -MEM->tx_head[i].length, + MEM->tx_head[i].misc )); + } +#endif + lance_init_ring(dev); + REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT; + + dev->tbusy = 0; + dev->trans_start = jiffies; + + return( 0 ); + } + + DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", + dev->name, DREG )); + + /* 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) { + DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name )); + return 1; + } + + if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { + DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name )); + /* don't clear dev->tbusy flag. */ + return 1; + } + + /* Fill in a Tx ring entry */ + if (lance_debug >= 3) { + u_char *p; + int i; + printk( "%s: TX pkt type 0x%04x from ", dev->name, + ((u_short *)skb->data)[6]); + for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data at 0x%08x len %d\n", (int)skb->data, + (int)skb->len ); + } + + /* We're not prepared for the int until the last flags are set/reset. And + * the int may happen already after setting the OWN_CHIP... */ + save_flags(flags); + cli(); + + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & TX_RING_MOD_MASK; + head = &(MEM->tx_head[entry]); + + /* Caution: the write order is important here, set the "ownership" bits + * last. + */ + + /* The old LANCE chips doesn't automatically pad buffers to min. size. */ + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + /* PAM-Card has a bug: Can only send packets with even number of bytes! */ + if (lp->cardtype == PAM_CARD && (len & 1)) + ++len; + + head->length = -len; + head->misc = 0; + lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); +#ifdef NORMAL_MEM_ACCESS + head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; +#else + SET_FLAG(head,(TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP)); +#endif + dev_kfree_skb( skb ); + lp->cur_tx++; + lp->stats.tx_bytes += skb->len; + while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { + lp->cur_tx -= TX_RING_SIZE; + lp->dirty_tx -= TX_RING_SIZE; + } + + /* Trigger an immediate send poll. */ + DREG = CSR0_INEA | CSR0_TDMD; + dev->trans_start = jiffies; + + lp->lock = 0; +#ifdef NORMAL_MEM_ACCESS + if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) == +#else + if ((GET_FLAG(&MEM->tx_head[(entry+1) & TX_RING_MOD_MASK]) & TMD1_OWN) == +#endif + TMD1_OWN_HOST) + dev->tbusy = 0; + else + lp->tx_full = 1; + restore_flags(flags); + + return 0; +} + +/* The LANCE interrupt handler. */ + +static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) +{ + struct device *dev = dev_id; + struct lance_private *lp; + struct lance_ioreg *IO; + int csr0, boguscnt = 10; + + if (dev == NULL) { + DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" )); + return; + } + + lp = (struct lance_private *)dev->priv; + IO = lp->iobase; + AREG = CSR0; + + if (dev->interrupt) { + DPRINTK( 1, ( "Re-entering CAUSE=%08x STATUS=%08x\n", + read_32bit_cp0_register(CP0_CAUSE), + read_32bit_cp0_register(CP0_STATUS) )); + panic("lance: interrupt handler reentered !"); + } + + dev->interrupt = 1; + + while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) && + --boguscnt >= 0) { + /* Acknowledge all of the current interrupt sources ASAP. */ + DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP | + CSR0_TDMD | CSR0_INEA); + + DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n", + dev->name, csr0, DREG )); + + if (csr0 & CSR0_RINT) /* Rx interrupt */ + lance_rx( dev ); + + if (csr0 & CSR0_TINT) { /* Tx-done interrupt */ + int dirty_tx = lp->dirty_tx; + + while( dirty_tx < lp->cur_tx) { + int entry = dirty_tx & TX_RING_MOD_MASK; +#ifdef NORMAL_MEM_ACCESS + int status = MEM->tx_head[entry].flag; +#else + int status = GET_FLAG(&MEM->tx_head[entry]); +#endif + if (status & TMD1_OWN_CHIP) + break; /* It still hasn't been Txed */ + +#ifdef NORMAL_MEM_ACCESS + MEM->tx_head[entry].flag = 0; +#else + SET_FLAG(&MEM->tx_head[entry],0); +#endif + + if (status & TMD1_ERR) { + /* There was an major error, log it. */ + int err_status = MEM->tx_head[entry].misc; + lp->stats.tx_errors++; + if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; + if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; + if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; + if (err_status & TMD3_UFLO) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + lp->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n", + dev->name, csr0 )); + /* Restart the chip. */ + DREG = CSR0_STRT; + } + } else { + if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF)) + lp->stats.collisions++; + lp->stats.tx_packets++; + } + dirty_tx++; + } + +#ifndef final_version + if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + DPRINTK( 0, ( "out-of-sync dirty pointer," + " %d vs. %d, full=%d.\n", + dirty_tx, lp->cur_tx, lp->tx_full )); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (lp->tx_full && dev->tbusy + && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + dev->tbusy = 0; + mark_bh( NET_BH ); + } + + lp->dirty_tx = dirty_tx; + } + + /* Log misc errors. */ + if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */ + if (csr0 & CSR0_MERR) { + DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " + "status %04x.\n", dev->name, csr0 )); + /* Restart the chip. */ + DREG = CSR0_STRT; + } + } + + /* Clear any other interrupt, and set interrupt enable. */ + DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR | + CSR0_IDON | CSR0_INEA; + + DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n", + dev->name, DREG )); + dev->interrupt = 0; + return; +} + + +static int lance_rx( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + int entry = lp->cur_rx & RX_RING_MOD_MASK; + int i; + +#ifdef NORMAL_MEM_ACCESS + DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name, + MEM->rx_head[entry].flag )); +#else + DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name, + GET_FLAG(&MEM->rx_head[entry]) )); +#endif + + /* If we own the next entry, it's a new packet. Send it up. */ +#ifdef NORMAL_MEM_ACCESS + while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) { +#else + while( (GET_FLAG(&MEM->rx_head[entry]) & RMD1_OWN) == RMD1_OWN_HOST ) { +#endif + struct lance_rx_head *head = &(MEM->rx_head[entry]); +#ifdef NORMAL_MEM_ACCESS + int status = head->flag; +#else + int status = GET_FLAG(head); +#endif + + if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */ + /* There is a tricky error noted by John Murphy, + to Russ Nelson: Even with full-sized + buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & RMD1_ENP) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ + if (status & RMD1_FRAM) lp->stats.rx_frame_errors++; + if (status & RMD1_OFLO) lp->stats.rx_over_errors++; + if (status & RMD1_CRC) lp->stats.rx_crc_errors++; + if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++; +#ifdef NORMAL_MEM_ACCESS + head->flag &= (RMD1_ENP|RMD1_STP); +#else + SET_FLAG(head,GET_FLAG(head) & (RMD1_ENP|RMD1_STP)); +#endif + } else { + /* Malloc up new buffer, compatible with net-3. */ + short pkt_len = head->msg_length & 0xfff; + struct sk_buff *skb; + + if (pkt_len < 60) { + printk( "%s: Runt packet!\n", dev->name ); + lp->stats.rx_errors++; + } + else { + skb = dev_alloc_skb( pkt_len+2 ); + if (skb == NULL) { + DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", + dev->name )); + for( i = 0; i < RX_RING_SIZE; i++ ) +#ifdef NORMAL_MEM_ACCESS + if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag & +#else + if (GET_FLAG(&MEM->rx_head[(entry+i) & \ + RX_RING_MOD_MASK]) & +#endif + RMD1_OWN_CHIP) + break; + + if (i > RX_RING_SIZE - 2) { + lp->stats.rx_dropped++; +#ifdef NORMAL_MEM_ACCESS + head->flag |= RMD1_OWN_CHIP; +#else + SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP); +#endif + lp->cur_rx++; + } + break; + } + + if (lance_debug >= 3) { + u_char *data = PKTBUF_ADDR(head), *p; + printk( "%s: RX pkt type 0x%04x from ", dev->name, + ((u_short *)data)[6]); + for( p = &data[6], i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" to "); + for( p = data, i = 0; i < 6; i++ ) + printk("%02x%s", *p++, i != 5 ? ":" : "" ); + printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " + "len %d\n", + data[15], data[16], data[17], data[18], + data[19], data[20], data[21], data[22], + pkt_len ); + } + + skb->dev = dev; + skb_reserve( skb, 2 ); /* 16 byte align */ + skb_put( skb, pkt_len ); /* Make room */ + lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; + } + } + +#ifdef NORMAL_MEM_ACCESS + head->flag |= RMD1_OWN_CHIP; +#else + SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP); +#endif + entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + } + lp->cur_rx &= RX_RING_MOD_MASK; + + /* From lance.c (Donald Becker): */ + /* We should check that at least two ring entries are free. If not, + we should free one and mark stats->rx_dropped++. */ + + return 0; +} + + +static int lance_close( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + + dev->start = 0; + dev->tbusy = 1; + + AREG = CSR0; + + DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, DREG )); + + /* We stop the LANCE here -- it occasionally polls + memory if we don't. */ + DREG = CSR0_STOP; + + MOD_DEC_USE_COUNT; + return 0; +} + + +static struct net_device_stats *lance_get_stats( struct device *dev ) + +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + return &lp->stats; +} + + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ + +static void set_multicast_list( struct device *dev ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_ioreg *IO = lp->iobase; + + if (!dev->start) + /* Only possible if board is already started */ + return; + + /* We take the simple way out and always enable promiscuous mode. */ + DREG = CSR0_STOP; /* Temporarily stop the lance. */ + + if (dev->flags & IFF_PROMISC) { + /* Log any net taps. */ + DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name )); + REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ + } else { + short multicast_table[4]; + int num_addrs = dev->mc_count; + int i; + /* We don't use the multicast table, but rely on upper-layer + * filtering. */ + memset( multicast_table, (num_addrs == 0) ? 0 : -1, + sizeof(multicast_table) ); + for( i = 0; i < 4; i++ ) + REGA( CSR8+i ) = multicast_table[i]; + REGA( CSR15 ) = 0; /* Unset promiscuous mode */ + } + + /* + * Always set BSWP after a STOP as STOP puts it back into + * little endian mode. + */ + REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); + + /* Resume normal operation and reset AREG to CSR0 */ + REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT; +} + + +/* This is needed for old RieblCards and possible for new RieblCards */ + +static int lance_set_mac_address( struct device *dev, void *addr ) + +{ struct lance_private *lp = (struct lance_private *)dev->priv; + struct sockaddr *saddr = addr; + int i; + + if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL) + return( -EOPNOTSUPP ); + + if (dev->start) { + /* Only possible while card isn't started */ + DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n", + dev->name )); + return( -EIO ); + } + + slow_memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len ); + + { + unsigned char hwaddr[6]; + for( i = 0; i < 6; i++ ) + hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */ + slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr)); + } + + lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 ); + /* set also the magic for future sessions */ +#ifdef NORMAL_MEM_ACCESS + *RIEBL_MAGIC_ADDR = RIEBL_MAGIC; +#else + { + unsigned long magic = RIEBL_MAGIC; + slow_memcpy(RIEBL_MAGIC_ADDR, &magic, sizeof(*RIEBL_MAGIC_ADDR)); + } +#endif + return( 0 ); +} + + +#ifdef MODULE +static char devicename[9] = { 0, }; + +static struct device bagetlance_dev = +{ + devicename, /* filled in by register_netdev() */ + 0, 0, 0, 0, /* memory */ + 0, 0, /* base, irq */ + 0, 0, 0, NULL, bagetlance_probe, +}; + +int init_module(void) + +{ int err; + + if ((err = register_netdev( &bagetlance_dev ))) { + if (err == -EIO) { + printk( "No Vme Lance board found. Module not loaded.\n"); + } + return( err ); + } + return( 0 ); +} + +void cleanup_module(void) + +{ + unregister_netdev( &bagetlance_dev ); +} + +#endif /* MODULE */ + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.2.10/linux/drivers/net/bmac.c Wed Dec 30 10:55:07 1998 +++ linux/drivers/net/bmac.c Mon Aug 9 12:04:57 1999 @@ -297,7 +297,6 @@ val = bmac_mif_readbits(dev, 17); bmwrite(dev, MIFCSR, 4); MIFDELAY; - /* printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val); */ return val; } @@ -431,18 +430,26 @@ static int bmac_init_chip(struct device *dev) { - if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) { - if (bmac_mif_read(dev, 4) == 0xa1) { - bmac_mif_write(dev, 0, 0x1000); - } else { - bmac_mif_write(dev, 4, 0xa1); + unsigned int addr; + + printk(KERN_DEBUG "phy registers:"); + for (addr = 0; addr < 32; ++addr) { + if ((addr & 7) == 0) + printk("\n" KERN_DEBUG); + printk(" %.4x", bmac_mif_read(dev, addr)); + } + printk("\n"); + if (is_bmac_plus) { + unsigned int capable, ctrl; + + ctrl = bmac_mif_read(dev, 0); + capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1; + if (bmac_mif_read(dev, 4) != capable + || (ctrl & 0x1000) == 0) { + bmac_mif_write(dev, 4, capable); bmac_mif_write(dev, 0, 0x1200); - } -#if 0 - /* XXX debugging */ - bmac_mif_read(dev, 0); - bmac_mif_read(dev, 4); -#endif + } else + bmac_mif_write(dev, 0, 0x1000); } bmac_init_registers(dev); return 1; @@ -1330,6 +1337,7 @@ dev->flags |= IFF_UP | IFF_RUNNING; + MOD_INC_USE_COUNT; return 0; } @@ -1374,6 +1382,8 @@ } bp->reset_and_enabled = 0; XXDEBUG(("bmac: all bufs freed\n")); + + MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.2.10/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c --- v2.2.10/linux/drivers/net/com90xx.c Mon Sep 14 11:32:22 1998 +++ linux/drivers/net/com90xx.c Mon Aug 9 12:04:39 1999 @@ -399,7 +399,7 @@ */ airqmask = probe_irq_on(); AINTMASK(NORXflag); - udelay(1); + mdelay(1); AINTMASK(0); airq = probe_irq_off(airqmask); diff -u --recursive --new-file v2.2.10/linux/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.2.10/linux/drivers/net/cosa.c Mon Jun 7 16:19:58 1999 +++ linux/drivers/net/cosa.c Mon Aug 9 12:04:57 1999 @@ -1,10 +1,7 @@ -/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */ +/* $Id: cosa.c,v 1.26 1999/07/09 15:02:37 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak - * - * 5/25/1999 : Marcelo Tosatti - * fixed a deadlock in cosa_sppp_open * * 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 @@ -105,6 +102,13 @@ #include "syncppp.h" #include "cosa.h" +/* Linux version stuff */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) +typedef struct wait_queue *wait_queue_head_t; +#define DECLARE_WAITQUEUE(wait, current) \ + struct wait_queue wait = { current, NULL } +#endif + /* Maximum length of the identification string. */ #define COSA_MAX_ID_STRING 128 @@ -133,7 +137,7 @@ struct semaphore rsem, wsem; char *rxdata; int rxsize; - struct wait_queue *txwaitq, *rxwaitq; + wait_queue_head_t txwaitq, rxwaitq; int tx_status, rx_status; /* SPPP/HDLC device parts */ @@ -365,7 +369,7 @@ #endif { int i; - printk(KERN_INFO "cosa v1.04 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -1273,10 +1277,8 @@ debug_status_out(cosa, 0); #endif } - cosa_putdata8(cosa, 0); cosa_putdata8(cosa, status); #ifdef DEBUG_IO - debug_data_cmd(cosa, 0); debug_data_cmd(cosa, status); #endif } @@ -1651,6 +1653,14 @@ * use the round-robin approach. The newer COSA firmwares have a simple * flow-control - in the status word has bits 2 and 3 set to 1 means that the * channel 0 or 1 doesn't want to receive data. + * + * It seems there is a bug in COSA firmware (need to trace it further): + * When the driver status says that the kernel has no more data for transmit + * (e.g. at the end of TX DMA) and then the kernel changes its mind + * (e.g. new packet is queued to hard_start_xmit()), the card issues + * the TX interrupt but does not mark the channel as ready-to-transmit. + * The fix seems to be to push the packet to COSA despite its request. + * We first try to obey the card's opinion, and then fall back to forced TX. */ static inline void tx_interrupt(struct cosa_data *cosa, int status) { @@ -1662,23 +1672,35 @@ spin_lock_irqsave(&cosa->lock, flags); set_bit(TXBIT, &cosa->rxtx); if (!test_bit(IRQBIT, &cosa->rxtx)) { - /* flow control */ + /* flow control, see the comment above */ int i=0; - do { - if (i++ > cosa->nchannels) { - printk(KERN_WARNING - "%s: No channel wants data in TX IRQ\n", - cosa->name); - put_driver_status_nolock(cosa); - clear_bit(TXBIT, &cosa->rxtx); - spin_unlock_irqrestore(&cosa->lock, flags); - return; - } + if (!cosa->txbitmap) { + printk(KERN_WARNING "%s: No channel wants data " + "in TX IRQ. Expect DMA timeout.", + cosa->name); + put_driver_status_nolock(cosa); + clear_bit(TXBIT, &cosa->rxtx); + spin_unlock_irqrestore(&cosa->lock, flags); + return; + } + while(1) { cosa->txchan++; + i++; if (cosa->txchan >= cosa->nchannels) cosa->txchan = 0; - } while ((!(cosa->txbitmap & (1<txchan))) - || status & (1<<(cosa->txchan+DRIVER_TXMAP_SHIFT))); + if (!(cosa->txbitmap & (1<txchan))) + continue; + if (~status & (1 << (cosa->txchan+DRIVER_TXMAP_SHIFT))) + break; + /* in second pass, accept first ready-to-TX channel */ + if (i > cosa->nchannels) { + /* Can be safely ignored */ + printk(KERN_DEBUG "%s: Forcing TX " + "to not-ready channel %d\n", + cosa->name, cosa->txchan); + break; + } + } cosa->txsize = cosa->chan[cosa->txchan].txsize; if (cosa_dma_able(cosa->chan+cosa->txchan, @@ -1788,6 +1810,7 @@ if (is_8bit(cosa)) { if (!test_bit(IRQBIT, &cosa->rxtx)) { set_bit(IRQBIT, &cosa->rxtx); + put_driver_status_nolock(cosa); cosa->rxsize = cosa_getdata8(cosa) <<8; #ifdef DEBUG_IO debug_data_in(cosa, cosa->rxsize >> 8); diff -u --recursive --new-file v2.2.10/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.2.10/linux/drivers/net/cs89x0.c Mon Jun 7 16:19:58 1999 +++ linux/drivers/net/cs89x0.c Mon Aug 9 12:05:05 1999 @@ -30,7 +30,7 @@ */ static char *version = -"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; +"cs89x0.c:v1.03 11/26/96 Russell Nelson \n"; /* ======================= configure the driver here ======================= */ @@ -306,7 +306,7 @@ else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { printk("\ncs89x0: EEPROM read failed, relying on command line.\n"); } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM checksum bad, relyong on command line\n"); + printk("\ncs89x0: EEPROM checksum bad, relying on command line\n"); } else { /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; @@ -843,6 +843,13 @@ lp->send_underrun++; if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + /* transmit cycle is done, although + frame wasn't transmitted - this + avoids having to wait for the upper + layers to timeout on us, in the + event of a tx underrun */ + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ } break; case ISQ_RX_MISS_EVENT: diff -u --recursive --new-file v2.2.10/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h --- v2.2.10/linux/drivers/net/cs89x0.h Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/cs89x0.h Mon Aug 9 12:05:05 1999 @@ -319,8 +319,8 @@ #define TX_FRAME_PORT RX_FRAME_PORT #define TX_CMD_PORT 0x0004 #define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ -#define TX_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */ -#define TX_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */ +#define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ #define TX_LEN_PORT 0x0006 #define ISQ_PORT 0x0008 #define ADD_PORT 0x000A diff -u --recursive --new-file v2.2.10/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.2.10/linux/drivers/net/de4x5.c Sat May 8 19:46:44 1999 +++ linux/drivers/net/de4x5.c Mon Aug 9 12:04:39 1999 @@ -5559,17 +5559,15 @@ switch(ioc->cmd) { case DE4X5_GET_HWADDR: /* Get the hardware address */ ioc->len = ETH_ALEN; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; for (i=0; idev_addr[i]; } - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; case DE4X5_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT; for (i=0; idev_addr[i] = tmp.addr[i]; } @@ -5612,9 +5610,8 @@ case DE4X5_GET_STATS: /* Get the driver statistics */ ioc->len = sizeof(lp->pktStats); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; spin_lock_irqsave(&lp->lock, flags); - copy_to_user(ioc->data, &lp->pktStats, ioc->len); + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) return -EFAULT; spin_unlock_irqrestore(&lp->lock, flags); break; @@ -5627,14 +5624,12 @@ case DE4X5_GET_OMR: /* Get the OMR Register contents */ tmp.addr[0] = inl(DE4X5_OMR); - if (verify_area(VERIFY_WRITE, ioc->data, 1)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, 1); + if (copy_to_user(ioc->data, tmp.addr, 1)) return -EFAULT; break; case DE4X5_SET_OMR: /* Set the OMR Register contents */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, 1)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, 1); + if (copy_from_user(tmp.addr, ioc->data, 1)) return -EFAULT; outl(tmp.addr[0], DE4X5_OMR); break; @@ -5649,8 +5644,7 @@ tmp.lval[6] = inl(DE4X5_STRR); j+=4; tmp.lval[7] = inl(DE4X5_SIGR); j+=4; ioc->len = j; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; #define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ @@ -5739,8 +5733,7 @@ tmp.addr[j++] = dev->tbusy; ioc->len = j; - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.2.10/linux/drivers/net/declance.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/declance.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1259 @@ +/* + * Lance ethernet driver for the MIPS processor based + * DECstation family + * + * + * adopted from sunlance.c by Richard van den Berg + * + * additional sources: + * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, + * Revision 1.2 + * + * History: + * + * v0.001: The kernel accepts the code and it shows the hardware address. + * + * v0.002: Removed most sparc stuff, left only some module and dma stuff. + * + * v0.003: Enhanced base address calculation from proposals by + * Harald Koerfgen and Thomas Riemer. + * + * v0.004: lance-regs is pointing at the right addresses, added prom + * check. First start of address mapping and DMA. + * + * v0.005: started to play around with LANCE-DMA. This driver will not work + * for non IOASIC lances. HK + * + * v0.006: added pointer arrays to lance_private and setup routine for them + * in dec_lance_init. HK + * + * v0.007: Big shit. The LANCE seems to use a different DMA mechanism to access + * the init block. This looks like one (short) word at a time, but the smallest + * amount the IOASIC can transfer is a (long) word. So we have a 2-2 padding here. + * Changed lance_init_block accordingly. The 16-16 padding for the buffers + * seems to be correct. HK + * + * v0.008 - mods to make PMAX_LANCE work. 01/09/1999 triemer + */ + +#undef DEBUG_DRIVER + +static char *version = +"declance.c: v0.008 by Linux Mips DECstation task force\n"; + +static char *lancestr = "LANCE"; + +/* + * card types + */ +#define ASIC_LANCE 1 +#define PMAD_LANCE 2 +#define PMAX_LANCE 3 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_TC +unsigned long system_base = 0; +unsigned long dmaptr; +#endif +static int type; + +#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + +#define LE_CSR0 0 +#define LE_CSR1 1 +#define LE_CSR2 2 +#define LE_CSR3 3 + +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ + +#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ +#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ +#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ +#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ +#define LE_C0_MERR 0x0800 /* ME: Memory error */ +#define LE_C0_RINT 0x0400 /* Received interrupt */ +#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ +#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ +#define LE_C0_INTR 0x0080 /* Interrupt or error */ +#define LE_C0_INEA 0x0040 /* Interrupt enable */ +#define LE_C0_RXON 0x0020 /* Receiver on */ +#define LE_C0_TXON 0x0010 /* Transmitter on */ +#define LE_C0_TDMD 0x0008 /* Transmitter demand */ +#define LE_C0_STOP 0x0004 /* Stop the card */ +#define LE_C0_STRT 0x0002 /* Start the card */ +#define LE_C0_INIT 0x0001 /* Init the card */ + +#define LE_C3_BSWP 0x4 /* SWAP */ +#define LE_C3_ACON 0x2 /* ALE Control */ +#define LE_C3_BCON 0x1 /* Byte control */ + +/* Receive message descriptor 1 */ +#define LE_R1_OWN 0x80 /* Who owns the entry */ +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x20 /* FRA: Frame error */ +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ +#define LE_R1_SOP 0x02 /* Start of packet */ +#define LE_R1_EOP 0x01 /* End of packet */ +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T1_OWN 0x80 /* Lance owns the packet */ +#define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ +#define LE_T1_EONE 0x08 /* Error: one retry needed */ +#define LE_T1_EDEF 0x04 /* Error: deferred */ +#define LE_T1_SOP 0x02 /* Start of packet */ +#define LE_T1_EOP 0x01 /* End of packet */ +#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T3_BUF 0x8000 /* Buffer error */ +#define LE_T3_UFL 0x4000 /* Error underflow */ +#define LE_T3_LCOL 0x1000 /* Error late collision */ +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ +#define LE_T3_RTY 0x0400 /* Error retry */ +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ + +/* Define: 2^4 Tx buffers and 2^4 Rx buffers */ + +#ifndef LANCE_LOG_TX_BUFFERS +#define LANCE_LOG_TX_BUFFERS 4 +#define LANCE_LOG_RX_BUFFERS 4 +#endif + +#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) + +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) + +#define PKT_BUF_SZ 1536 +#define RX_BUFF_SIZE PKT_BUF_SZ +#define TX_BUFF_SIZE PKT_BUF_SZ + +#undef TEST_HITS +#define DEBUG_DRIVER 1 + +#define ZERO 0 + +/* The DS2000/3000 have a linear 64 KB buffer. + + * The PMAD-AA has 128 kb buffer on-board. + * + * The IOASIC LANCE devices use a shared memory region. This region as seen + * from the CPU is (max) 128 KB long and has to be on an 128 KB boundary. + * The LANCE sees this as a 64 KB long continuous memory region. + * + * The LANCE's DMA address is used as an index in this buffer and DMA takes + * place in bursts of eight 16-Bit words which are packed into four 32-Bit words + * by the IOASIC. This leads to a strange padding: 16 bytes of valid data followed + * by a 16 byte gap :-(. + */ + +struct lance_rx_desc { + unsigned short rmd0; /* low address of packet */ + short gap0; + unsigned char rmd1_hadr; /* high address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + short gap1; + short length; /* This length is 2s complement (negative)! + * Buffer length + */ + short gap2; + unsigned short mblength; /* This is the actual number of bytes received */ + short gap3; +}; + +struct lance_tx_desc { + unsigned short tmd0; /* low address of packet */ + short gap0; + unsigned char tmd1_hadr; /* high address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + short gap1; + short length; /* Length is 2s complement (negative)! */ + short gap2; + unsigned short misc; + short gap3; +}; + + +/* First part of the LANCE initialization block, described in databook. */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode (reg. 15) */ + short gap0; + + unsigned char phys_addr[12]; /* Physical ethernet address + * only 0, 1, 4, 5, 8, 9 are valid + * 2, 3, 6, 7, 10, 11 are gaps + */ + unsigned short filter[8]; /* Multicast filter. + * only 0, 2, 4, 6 are valid + * 1, 3, 5, 7 are gaps + */ + + /* Receive and transmit ring base, along with extra bits. */ + unsigned short rx_ptr; /* receive descriptor addr */ + short gap1; + unsigned short rx_len; /* receive len and high addr */ + short gap2; + unsigned short tx_ptr; /* transmit descriptor addr */ + short gap3; + unsigned short tx_len; /* transmit len and high addr */ + short gap4; + char gap5[16]; + + /* The buffer descriptors */ + struct lance_rx_desc brx_ring[RX_RING_SIZE]; + struct lance_tx_desc btx_ring[TX_RING_SIZE]; +}; + +#define BUF_OFFSET_CPU sizeof(struct lance_init_block) +#define BUF_OFFSET_LNC (sizeof(struct lance_init_block)>>1) + +#define libdesc_offset(rt, elem) \ +((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem]))))) + +/* + * This works *only* for the ring descriptors + */ +#define LANCE_ADDR(x) (PHYSADDR(x) >> 1) + +struct lance_private { + char *name; + volatile struct lance_regs *ll; + volatile struct lance_init_block *init_block; + volatile unsigned long *dma_ptr_reg; + + int rx_new, tx_new; + int rx_old, tx_old; + + struct net_device_stats stats; + + unsigned short busmaster_regval; + + struct device *dev; /* Backpointer */ + struct lance_private *next_module; + + /* Pointers to the ring buffers as seen from the CPU */ + char *rx_buf_ptr_cpu[RX_RING_SIZE]; + char *tx_buf_ptr_cpu[TX_RING_SIZE]; + + /* Pointers to the ring buffers as seen from the LANCE */ + char *rx_buf_ptr_lnc[RX_RING_SIZE]; + char *tx_buf_ptr_lnc[TX_RING_SIZE]; +}; + +#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ + lp->tx_old+TX_RING_MOD_MASK-lp->tx_new:\ + lp->tx_old - lp->tx_new-1) + +/* The lance control ports are at an absolute address, machine and tc-slot + * dependant. + * DECstations do only 32-bit access and the LANCE uses 16 bit addresses, + * so we have to give the structure an extra member making rap pointing + * at the right address + */ +struct lance_regs { + volatile unsigned short rdp; /* register data port */ + unsigned short pad; + volatile unsigned short rap; /* register address port */ +}; + +int dec_lance_debug = 2; + +/* + #ifdef MODULE + static struct lance_private *root_lance_dev = NULL; + #endif + */ + +static inline void writereg(volatile unsigned short *regptr, short value) +{ + *regptr = value; +} + +/* Load the CSR registers */ +static void load_csrs(struct lance_private *lp) +{ + volatile struct lance_regs *ll = lp->ll; + int leptr; + + /* The address space as seen from the LANCE + * begins at address 0. HK + */ + leptr = 0; + + writereg(&ll->rap, LE_CSR1); + writereg(&ll->rdp, (leptr & 0xFFFF)); + writereg(&ll->rap, LE_CSR2); + writereg(&ll->rdp, leptr >> 16); + writereg(&ll->rap, LE_CSR3); + writereg(&ll->rdp, lp->busmaster_regval); + + /* Point back to csr0 */ + writereg(&ll->rap, LE_CSR0); +} + +/* + * Our specialized copy routines + * + */ +void cp_to_buf(void *to, const void *from, __kernel_size_t len) +{ + unsigned short *tp, *fp, clen; + unsigned char *rtp, *rfp; + + if (type == PMAX_LANCE) { + clen = len >> 1; + tp = (unsigned short *) to; + fp = (unsigned short *) from; + + while (clen--) { + *tp++ = *fp++; + tp++; + } + + clen = len & 1; + rtp = (unsigned char *) tp; + rfp = (unsigned char *) fp; + while (clen--) { + *rtp++ = *rfp++; + } + } else { + /* + * copy 16 Byte chunks + */ + clen = len >> 4; + tp = (unsigned short *) to; + fp = (unsigned short *) from; + while (clen--) { + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + tp += 8; + } + + /* + * do the rest, if any. + */ + clen = len & 15; + rtp = (unsigned char *) tp; + rfp = (unsigned char *) fp; + while (clen--) { + *rtp++ = *rfp++; + } + } + +} + +void cp_from_buf(void *to, unsigned char *from, int len) +{ + unsigned short *tp, *fp, clen; + unsigned char *rtp, *rfp; + + if (type == PMAX_LANCE) { + clen = len >> 1; + tp = (unsigned short *) to; + fp = (unsigned short *) from; + while (clen--) { + *tp++ = *fp++; + fp++; + } + + clen = len & 1; + + rtp = (unsigned char *) tp; + rfp = (unsigned char *) fp; + + while (clen--) { + *rtp++ = *rfp++; + } + } else { + + /* + * copy 16 Byte chunks + */ + clen = len >> 4; + tp = (unsigned short *) to; + fp = (unsigned short *) from; + while (clen--) { + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + *tp++ = *fp++; + fp += 8; + } + + /* + * do the rest, if any. + */ + clen = len & 15; + rtp = (unsigned char *) tp; + rfp = (unsigned char *) fp; + while (clen--) { + *rtp++ = *rfp++; + } + + + } + +} + +/* Setup the Lance Rx and Tx rings */ +/* Sets dev->tbusy */ +static void lance_init_ring(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib; + int leptr; + int i; + + ib = (struct lance_init_block *) (dev->mem_start); + + /* Lock out other processes while setting up hardware */ + dev->tbusy = 1; + lp->rx_new = lp->tx_new = 0; + lp->rx_old = lp->tx_old = 0; + + ib->mode = 0; + + /* Copy the ethernet address to the lance init block. + * XXX bit 0 of the physical address registers has to be zero + */ + ib->phys_addr[0] = dev->dev_addr[0]; + ib->phys_addr[1] = dev->dev_addr[1]; + ib->phys_addr[4] = dev->dev_addr[2]; + ib->phys_addr[5] = dev->dev_addr[3]; + ib->phys_addr[8] = dev->dev_addr[4]; + ib->phys_addr[9] = dev->dev_addr[5]; + /* Setup the initialization block */ + + /* Setup rx descriptor pointer */ + leptr = LANCE_ADDR(libdesc_offset(brx_ring, 0)); + ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); + ib->rx_ptr = leptr; + if (ZERO) + printk("RX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(brx_ring, 0)); + + /* Setup tx descriptor pointer */ + leptr = LANCE_ADDR(libdesc_offset(btx_ring, 0)); + ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); + ib->tx_ptr = leptr; + if (ZERO) + printk("TX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(btx_ring, 0)); + + /* Clear the multicast filter */ + ib->filter[0] = 0; + ib->filter[2] = 0; + ib->filter[4] = 0; + ib->filter[6] = 0; + if (ZERO) + printk("TX rings:\n"); + + /* Setup the Tx ring entries */ + for (i = 0; i < TX_RING_SIZE; i++) { + leptr = (int) lp->tx_buf_ptr_lnc[i]; + ib->btx_ring[i].tmd0 = leptr; + ib->btx_ring[i].tmd1_hadr = leptr >> 16; + ib->btx_ring[i].tmd1_bits = 0; + ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */ + ib->btx_ring[i].misc = 0; + if (i < 3 && ZERO) + printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->tx_buf_ptr_cpu[i]); + } + + /* Setup the Rx ring entries */ + if (ZERO) + printk("RX rings:\n"); + for (i = 0; i < RX_RING_SIZE; i++) { + leptr = (int) lp->rx_buf_ptr_lnc[i]; + ib->brx_ring[i].rmd0 = leptr; + ib->brx_ring[i].rmd1_hadr = leptr >> 16; + ib->brx_ring[i].rmd1_bits = LE_R1_OWN; + ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000; + ib->brx_ring[i].mblength = 0; + if (i < 3 && ZERO) + printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]); + } +} + +static int init_restart_lance(struct lance_private *lp) +{ + volatile struct lance_regs *ll = lp->ll; + int i; + + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_INIT); + + /* Wait for the lance to complete initialization */ + for (i = 0; (i < 100) && !(ll->rdp & LE_C0_IDON); i++) { + udelay(10); + } + if ((i == 100) || (ll->rdp & LE_C0_ERR)) { + printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + return -1; + } + if ((ll->rdp & LE_C0_ERR)) { + printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + return -1; + } + writereg(&ll->rdp, LE_C0_IDON); + writereg(&ll->rdp, LE_C0_STRT); + writereg(&ll->rdp, LE_C0_INEA); + + return 0; +} + +static int lance_rx(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib; + volatile struct lance_rx_desc *rd = 0; + unsigned char bits; + int len = 0; + struct sk_buff *skb = 0; + ib = (struct lance_init_block *) (dev->mem_start); + +#ifdef TEST_HITS + int i; + + printk("["); + for (i = 0; i < RX_RING_SIZE; i++) { + if (i == lp->rx_new) + printk("%s", + ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X"); + else + printk("%s", + ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1"); + } + printk("]"); +#endif + + for (rd = &ib->brx_ring[lp->rx_new]; + !((bits = rd->rmd1_bits) & LE_R1_OWN); + rd = &ib->brx_ring[lp->rx_new]) { + + /* We got an incomplete frame? */ + if ((bits & LE_R1_POK) != LE_R1_POK) { + lp->stats.rx_over_errors++; + lp->stats.rx_errors++; + } else if (bits & LE_R1_ERR) { + /* Count only the end frame as a rx error, + * not the beginning + */ + if (bits & LE_R1_BUF) + lp->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) + lp->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) + lp->stats.rx_over_errors++; + if (bits & LE_R1_FRA) + lp->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) + lp->stats.rx_errors++; + } else { + len = (rd->mblength & 0xfff) - 4; + skb = dev_alloc_skb(len + 2); + + if (skb == 0) { + printk("%s: Memory squeeze, deferring packet.\n", + dev->name); + lp->stats.rx_dropped++; + rd->mblength = 0; + rd->rmd1_bits = LE_R1_OWN; + lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + return 0; + } + lp->stats.rx_bytes += len; + + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align */ + skb_put(skb, len); /* make room */ + cp_from_buf(skb->data, + (char *) lp->rx_buf_ptr_cpu[lp->rx_new], + len); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + lp->stats.rx_packets++; + } + + /* Return the packet to the pool */ + rd->mblength = 0; + rd->length = -RX_BUFF_SIZE | 0xf000; + rd->rmd1_bits = LE_R1_OWN; + lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + } + return 0; +} + +static int lance_tx(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_tx_desc *td; + int i, j; + int status; + ib = (struct lance_init_block *) (dev->mem_start); + j = lp->tx_old; + + for (i = j; i != lp->tx_new; i = j) { + td = &ib->btx_ring[i]; + /* If we hit a packet not owned by us, stop */ + if (td->tmd1_bits & LE_T1_OWN) + break; + + if (td->tmd1_bits & LE_T1_ERR) { + status = td->misc; + + lp->stats.tx_errors++; + if (status & LE_T3_RTY) + lp->stats.tx_aborted_errors++; + if (status & LE_T3_LCOL) + lp->stats.tx_window_errors++; + + if (status & LE_T3_CLOS) { + lp->stats.tx_carrier_errors++; + printk("%s: Carrier Lost", dev->name); + /* Stop the lance */ + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + lance_init_ring(dev); + load_csrs(lp); + init_restart_lance(lp); + return 0; + } + /* Buffer errors and underflows turn off the + * transmitter, restart the adapter. + */ + if (status & (LE_T3_BUF | LE_T3_UFL)) { + lp->stats.tx_fifo_errors++; + + printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", + dev->name); + /* Stop the lance */ + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + lance_init_ring(dev); + load_csrs(lp); + init_restart_lance(lp); + return 0; + } + } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) { + /* + * So we don't count the packet more than once. + */ + td->tmd1_bits &= ~(LE_T1_POK); + + /* One collision before packet was sent. */ + if (td->tmd1_bits & LE_T1_EONE) + lp->stats.collisions++; + + /* More than one collision, be optimistic. */ + if (td->tmd1_bits & LE_T1_EMORE) + lp->stats.collisions += 2; + + lp->stats.tx_packets++; + } + j = (j + 1) & TX_RING_MOD_MASK; + } + lp->tx_old = j; + return 0; +} + +static void lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + int csr0; + + if (dev->interrupt) + printk("%s: again\n", dev->name); + + dev->interrupt = 1; + + writereg(&ll->rap, LE_CSR0); + csr0 = ll->rdp; + + /* Acknowledge all the interrupt sources ASAP */ + writereg(&ll->rdp, csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT)); + + if ((csr0 & LE_C0_ERR)) { + /* Clear the error condition */ + writereg(&ll->rdp, LE_C0_BABL | LE_C0_ERR | LE_C0_MISS | + LE_C0_CERR | LE_C0_MERR); + } + if (csr0 & LE_C0_RINT) + lance_rx(dev); + + if (csr0 & LE_C0_TINT) + lance_tx(dev); + + if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { + dev->tbusy = 0; + mark_bh(NET_BH); + } + if (csr0 & LE_C0_BABL) + lp->stats.tx_errors++; + + if (csr0 & LE_C0_MISS) + lp->stats.rx_errors++; + + if (csr0 & LE_C0_MERR) { + volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR); + + printk("%s: Memory error, status %04x", dev->name, csr0); + + if (int_stat & LANCE_DMA_MEMRDERR) { + printk("%s: DMA error\n", dev->name); + int_stat |= LANCE_DMA_MEMRDERR; + /* + * re-enable LANCE DMA + */ + *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16); + } + writereg(&ll->rdp, LE_C0_STOP); + + lance_init_ring(dev); + load_csrs(lp); + init_restart_lance(lp); + dev->tbusy = 0; + } + writereg(&ll->rdp, LE_C0_INEA); + writereg(&ll->rdp, LE_C0_INEA); + dev->interrupt = 0; +} + +struct device *last_dev = 0; + +static int lance_open(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status = 0; + + last_dev = dev; + + /* Associate IRQ with lance_interrupt */ + if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) { + printk("Lance: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + /* Stop the Lance */ + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + + lance_init_ring(dev); + load_csrs(lp); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + status = init_restart_lance(lp); + + /* + * if (!status) + * MOD_INC_USE_COUNT; + */ + + return status; +} + +static int lance_close(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + + dev->start = 0; + dev->tbusy = 1; + + /* Stop the card */ + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + + free_irq(dev->irq, (void *) dev); + /* + MOD_DEC_USE_COUNT; + */ + return 0; +} + +static inline int lance_reset(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status; + + /* Stop the lance */ + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + + lance_init_ring(dev); + load_csrs(lp); + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; + dev->tbusy = 0; + status = init_restart_lance(lp); +#ifdef DEBUG_DRIVER + printk("Lance restart=%d\n", status); +#endif + return status; +} + +static int lance_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib; + unsigned long flags; + int entry, skblen, len; + int status = 0; + static int outs; + ib = (struct lance_init_block *) (dev->mem_start); + + /* Transmitter timeout, serious problems */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 100) { + status = -1; + } else { + printk("%s: transmit timed out, status %04x, reset\n", + dev->name, ll->rdp); + lance_reset(dev); + } + return status; + } + /* Block a timer-based transmit from overlapping. */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + printk("Transmitter access conflict.\n"); + return -1; + } + skblen = skb->len; + save_and_cli(flags); + if (!TX_BUFFS_AVAIL) { + restore_flags(flags); + return -1; + } + len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + + lp->stats.tx_bytes += len; + + entry = lp->tx_new & TX_RING_MOD_MASK; + ib->btx_ring[entry].length = (-len); + ib->btx_ring[entry].misc = 0; + + cp_to_buf((char *) lp->tx_buf_ptr_cpu[entry], skb->data, skblen); + + /* Clear the slack of the packet, do I need this? */ + /* For a firewall its a good idea - AC */ +/* + if (len != skblen) + memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1); + */ + + /* Now, give the packet to the lance */ + ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN); + lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK; + + outs++; + /* Kick the lance: transmit now */ + writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD); + dev->trans_start = jiffies; + dev_kfree_skb(skb); + + if (TX_BUFFS_AVAIL) + dev->tbusy = 0; + + restore_flags(flags); + return status; +} + +static struct net_device_stats *lance_get_stats(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + + return &lp->stats; +} + +static void lance_load_multicast(struct device *dev) +{ + volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); + volatile u16 *mcast_table = (u16 *) & ib->filter; + struct dev_mc_list *dmi = dev->mc_list; + char *addrs; + int i, j, bit, byte; + u32 crc, poly = CRC_POLYNOMIAL_BE; + + /* set all multicast bits */ + if (dev->flags & IFF_ALLMULTI) { + ib->filter[0] = 0xffff; + ib->filter[2] = 0xffff; + ib->filter[4] = 0xffff; + ib->filter[6] = 0xffff; + return; + } + /* clear the multicast filter */ + ib->filter[0] = 0; + ib->filter[2] = 0; + ib->filter[4] = 0; + ib->filter[6] = 0; + + /* Add addresses */ + for (i = 0; i < dev->mc_count; i++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + + /* multicast address? */ + if (!(*addrs & 1)) + continue; + + crc = 0xffffffff; + for (byte = 0; byte < 6; byte++) + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + + if (test) { + crc = crc ^ poly; + } + } + + crc = crc >> 26; + mcast_table[crc >> 3] |= 1 << (crc & 0xf); + } + return; +} + +static void lance_set_multicast(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib; + volatile struct lance_regs *ll = lp->ll; + + ib = (struct lance_init_block *) (dev->mem_start); + + while (dev->tbusy) + schedule(); + set_bit(0, (void *) &dev->tbusy); + while (lp->tx_old != lp->tx_new) + schedule(); + + writereg(&ll->rap, LE_CSR0); + writereg(&ll->rdp, LE_C0_STOP); + + lance_init_ring(dev); + + if (dev->flags & IFF_PROMISC) { + ib->mode |= LE_MO_PROM; + } else { + ib->mode &= ~LE_MO_PROM; + lance_load_multicast(dev); + } + load_csrs(lp); + init_restart_lance(lp); + dev->tbusy = 0; +} + +__initfunc(static int dec_lance_init(struct device *dev, const int type)) +{ + static unsigned version_printed = 0; + struct lance_private *lp; + volatile struct lance_regs *ll; + int i; + unsigned long esar_base; + unsigned char *esar; + +#ifndef CONFIG_TC + system_base = KN01_LANCE_BASE; +#else + int slot; +#endif + + if (dec_lance_debug && version_printed++ == 0) + printk(version); + + if (dev == NULL) { + dev = init_etherdev(0, sizeof(struct lance_private) + 8); + } else { + dev->priv = kmalloc(sizeof(struct lance_private) + 8, + GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct lance_private) + 8); + + } + + /* Make certain the data structures used by the LANCE are aligned. */ + dev->priv = (void *) (((unsigned long) dev->priv + 7) & ~7); + lp = (struct lance_private *) dev->priv; + + switch (type) { +#ifdef CONFIG_TC + case ASIC_LANCE: + dev->base_addr = system_base + LANCE; + + /* buffer space for the on-board LANCE shared memory */ + /* + * FIXME: ugly hack! + */ + dev->mem_start = KSEG1ADDR(0x0020000); + dev->mem_end = dev->mem_start + 0x00020000; + dev->irq = ETHER; + esar_base = system_base + ESAR; + + /* + * setup the pointer arrays, this sucks [tm] :-( + */ + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + + 2 * i * RX_BUFF_SIZE); + lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + + i * RX_BUFF_SIZE); + } + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU + + 2 * RX_RING_SIZE * RX_BUFF_SIZE + + 2 * i * TX_BUFF_SIZE); + lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + + RX_RING_SIZE * RX_BUFF_SIZE + + i * TX_BUFF_SIZE); + } + + /* + * setup and enable IOASIC LANCE DMA + */ + lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P); + *(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3; + *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16); + + break; + case PMAD_LANCE: + slot = search_tc_card("PMAD-AA"); + claim_tc_card(slot); + + dev->mem_start = get_tc_base_addr(slot); + dev->base_addr = dev->mem_start + 0x100000; + dev->irq = get_tc_irq_nr(slot); + esar_base = dev->mem_start + 0x1c0002; + break; +#endif + case PMAX_LANCE: + dev->irq = ETHER; + dev->base_addr = KN01_LANCE_BASE; + dev->mem_start = KN01_LANCE_BASE + 0x01000000; + esar_base = KN01_RTC_BASE + 1; + /* + * setup the pointer arrays, this sucks [tm] :-( + */ + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_buf_ptr_cpu[i] = + (char *) (dev->mem_start + BUF_OFFSET_CPU + + 2 * i * RX_BUFF_SIZE); + + lp->rx_buf_ptr_lnc[i] = + (char *) (BUF_OFFSET_LNC + + i * RX_BUFF_SIZE); + + } + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_buf_ptr_cpu[i] = + (char *) (dev->mem_start + BUF_OFFSET_CPU + + 2 * RX_RING_SIZE * RX_BUFF_SIZE + + 2 * i * TX_BUFF_SIZE); + lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC + + RX_RING_SIZE * RX_BUFF_SIZE + + i * TX_BUFF_SIZE); + + } + break; + default: + printk("declance_init called with unknown type\n"); + return -ENODEV; + break; + } + + ll = (struct lance_regs *) dev->base_addr; + esar = (unsigned char *) esar_base; + + /* prom checks */ + /* First, check for test pattern */ + if (esar[0x60] != 0xff && esar[0x64] != 0x00 && + esar[0x68] != 0x55 && esar[0x6c] != 0xaa) { + printk("Ethernet station address prom not found!\n"); + return -ENODEV; + } + /* Check the prom contents */ + for (i = 0; i < 8; i++) { + if (esar[i * 4] != esar[0x3c - i * 4] && + esar[i * 4] != esar[0x40 + i * 4] && + esar[0x3c - i * 4] != esar[0x40 + i * 4]) { + printk("Something is wrong with the ethernet " + "station address prom!\n"); + return -ENODEV; + } + } + + /* Copy the ethernet address to the device structure, later to the + * lance initialization block so the lance gets it every time it's + * (re)initialized. + */ + switch (type) { + case ASIC_LANCE: + printk("%s: IOASIC onboard LANCE, addr = ", dev->name); + break; + case PMAD_LANCE: + printk("%s: PMAD-AA, addr = ", dev->name); + break; + case PMAX_LANCE: + printk("%s: PMAX onboard LANCE, addr = ", dev->name); + break; + } + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = esar[i * 4]; + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':'); + } + + printk(" irq = %d\n", dev->irq); + + /* Fill the dev fields */ + + dev->open = lance_open; + dev->stop = lance_close; + dev->hard_start_xmit = lance_start_xmit; + dev->get_stats = lance_get_stats; + dev->set_multicast_list = lance_set_multicast; + dev->dma = 0; + + /* lp->ll is the location of the registers for lance card */ + lp->ll = ll; + + lp->name = lancestr; + + /* busmaster_regval (CSR3) should be zero according to the PMAD-AA + * specification. + */ + lp->busmaster_regval = 0; + lp->dev = dev; + + ether_setup(dev); +/* + #ifdef MODULE + dev->ifindex = dev_new_index(); + lp->next_module = root_lance_dev; + root_lance_dev = lp; + #endif + */ + return 0; +} + + +/* Find all the lance cards on the system and initialize them */ +__initfunc(int dec_lance_probe(struct device *dev)) +{ + static int called = 0; + +#ifdef CONFIG_TC + int slot = -1; + + if (TURBOCHANNEL) { + if (IOASIC && !called) { + called = 1; + type = ASIC_LANCE; + } else { + if ((slot = search_tc_card("PMAD-AA")) >= 0) { + type = PMAD_LANCE; + } else { + return -ENODEV; + } + } + } else { + if (!called) { + called = 1; + type = PMAX_LANCE; + } else { + return -ENODEV; + } + } +#else + if (!called && !TURBOCHANNEL) { + called = 1; + type = PMAX_LANCE; + } else { + return -ENODEV; + } +#endif + + return dec_lance_init(dev, type); +} + +/* + #ifdef MODULE + + int + init_module(void) + { + root_lance_dev = NULL; + return dec_lance_probe(NULL); + } + + void + cleanup_module(void) + { + struct lance_private *lp; + + while (root_lance_dev) { + lp = root_lance_dev->next_module; + + unregister_netdev(root_lance_dev->dev); + kfree(root_lance_dev->dev); + root_lance_dev = lp; + } + } + + #endif -* MODULE */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.2.10/linux/drivers/net/depca.c Tue Nov 24 09:21:11 1998 +++ linux/drivers/net/depca.c Mon Aug 9 12:04:39 1999 @@ -221,11 +221,13 @@ by 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. 0.5 14-Nov-98 Re-spin for 2.1.x kernels. + 0.51 27-Jun-99 Correct received packet length for CRC from + report by ========================================================================= */ -static const char *version = "depca.c:v0.5 1998/11/14 davies@maniac.ultranet.com\n"; +static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n"; #include #include @@ -947,7 +949,7 @@ if (status & R_CRC) lp->stats.rx_crc_errors++; if (status & R_BUFF) lp->stats.rx_fifo_errors++; } else { - short len, pkt_len = readw(&lp->rx_ring[entry].msg_length); + short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4; struct sk_buff *skb; skb = dev_alloc_skb(pkt_len+2); @@ -1898,14 +1900,12 @@ tmp.addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; - if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; case DEPCA_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT; - copy_from_user(tmp.addr,ioc->data,ETH_ALEN); + if (copy_from_user(tmp.addr,ioc->data,ETH_ALEN)) return -EFAULT; for (i=0; idev_addr[i] = tmp.addr[i]; } @@ -1956,14 +1956,12 @@ case DEPCA_GET_MCA: /* Get the multicast address table */ ioc->len = (HASH_TABLE_LEN >> 3); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); + if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len)) return -EFAULT; break; case DEPCA_SET_MCA: /* Set a multicast address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) return -EFAULT; set_multicast_list(dev); break; @@ -1980,11 +1978,8 @@ case DEPCA_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) { - status = -EFAULT; - } else { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) + status = -EFAULT; sti(); break; @@ -2002,8 +1997,7 @@ tmp.sval[i++] = inw(DEPCA_DATA); memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); ioc->len = i+sizeof(struct depca_init); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; break; default: diff -u --recursive --new-file v2.2.10/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.2.10/linux/drivers/net/eepro100.c Sat Feb 6 12:46:21 1999 +++ linux/drivers/net/eepro100.c Mon Aug 9 12:04:39 1999 @@ -343,7 +343,8 @@ const char *product_name; struct device *next_module; spinlock_t lock; - struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ + struct TxFD tx_ring[TX_RING_SIZE] /* Commands (usually CmdTxPacket). */ + __attribute__ ((aligned (L1_CACHE_BYTES)));; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct descriptor *last_cmd; /* Last command sent. */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.2.10/linux/drivers/net/eql.c Mon May 10 13:00:10 1999 +++ linux/drivers/net/eql.c Mon Aug 9 12:04:39 1999 @@ -411,16 +411,15 @@ slaving_request_t srq; int err; - err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t)); + err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); if (err) { #ifdef EQL_DEBUG if (eql_debug >= 20) - printk ("EQL enslave: error detected by verify_area\n"); + printk ("EQL enslave: error detected by copy_from_user\n"); #endif return err; } - copy_from_user (&srq, srqp, sizeof (slaving_request_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) @@ -473,11 +472,10 @@ slaving_request_t srq; int err; - err = verify_area(VERIFY_READ, (void *)srqp, sizeof (slaving_request_t)); + err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); if (err) return err; - copy_from_user (&srq, srqp, sizeof (slaving_request_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) printk ("%s: emancipate `%s`\n", dev->name, srq.slave_name); @@ -504,11 +502,10 @@ slave_config_t sc; int err; - err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t)); + err = copy_from_user (&sc, scp, sizeof (slave_config_t)); if (err) return err; - copy_from_user (&sc, scp, sizeof (slave_config_t)); #ifdef EQL_DEBUG if (eql_debug >= 20) printk ("%s: get config for slave `%s'\n", dev->name, sc.slave_name); @@ -541,7 +538,7 @@ slave_config_t sc; int err; - err = verify_area(VERIFY_READ, (void *)scp, sizeof (slave_config_t)); + err = copy_from_user (&sc, scp, sizeof (slave_config_t)); if (err) return err; @@ -550,7 +547,6 @@ printk ("%s: set config for slave `%s'\n", dev->name, sc.slave_name); #endif - copy_from_user (&sc, scp, sizeof (slave_config_t)); eql = (equalizer_t *) dev->priv; slave_dev = dev_get (sc.slave_name); @@ -583,13 +579,12 @@ if ( eql_is_master (dev) ) { int err; - err = verify_area(VERIFY_WRITE, (void *)mcp, sizeof (master_config_t)); - if (err) - return err; eql = (equalizer_t *) dev->priv; mc.max_slaves = eql->max_slaves; mc.min_slaves = eql->min_slaves; - copy_to_user (mcp, &mc, sizeof (master_config_t)); + err = copy_to_user (mcp, &mc, sizeof (master_config_t)); + if (err) + return err; return 0; } return -EINVAL; @@ -602,14 +597,13 @@ master_config_t mc; int err; - err = verify_area(VERIFY_READ, (void *)mcp, sizeof (master_config_t)); + err = copy_from_user (&mc, mcp, sizeof (master_config_t)); if (err) return err; #if EQL_DEBUG if (eql_debug >= 20) printk ("%s: set master config\n", dev->name); #endif - copy_from_user (&mc, mcp, sizeof (master_config_t)); if ( eql_is_master (dev) ) { eql = (equalizer_t *) dev->priv; diff -u --recursive --new-file v2.2.10/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.2.10/linux/drivers/net/ewrk3.c Thu May 21 14:24:06 1998 +++ linux/drivers/net/ewrk3.c Mon Aug 9 12:04:39 1999 @@ -1679,18 +1679,20 @@ tmp.addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, (void *) ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) { + status = -EFAULT; + break; } - break; case EWRK3_SET_HWADDR: /* Set the hardware address */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, (void *) ioc->data, ETH_ALEN))) { csr = inb(EWRK3_CSR); csr |= (CSR_TXD | CSR_RXD); outb(csr, EWRK3_CSR); /* Disable the TX and RX */ - copy_from_user(tmp.addr, ioc->data, ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) { + status = -EFAULT; + break; + } for (i = 0; i < ETH_ALEN; i++) { dev->dev_addr[i] = tmp.addr[i]; outb(tmp.addr[i], EWRK3_PAR0 + i); @@ -1698,7 +1700,6 @@ csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */ outb(csr, EWRK3_CSR); - } } else { status = -EPERM; } @@ -1730,7 +1731,6 @@ break; case EWRK3_GET_MCA: /* Get the multicast address table */ - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); @@ -1743,17 +1743,21 @@ memcpy_fromio(tmp.addr, (char *) (lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3)); } ioc->len = (HASH_TABLE_LEN >> 3); - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) { + status = -EFAULT; + break; + } + lp->lock = 0; /* Unlock the page register */ break; case EWRK3_SET_MCA: /* Set a multicast address */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, ETH_ALEN * ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) { + status = -EFAULT; + break; } + set_multicast_list(dev); } else { status = -EPERM; } @@ -1781,9 +1785,8 @@ case EWRK3_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) + status = -EFAULT; sti(); break; @@ -1800,16 +1803,16 @@ case EWRK3_GET_CSR: /* Get the CSR Register contents */ tmp.addr[0] = inb(EWRK3_CSR); ioc->len = 1; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; break; case EWRK3_SET_CSR: /* Set the CSR Register contents */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, 1))) { - copy_from_user(tmp.addr, ioc->data, 1); - outb(tmp.addr[0], EWRK3_CSR); + if (copy_from_user(tmp.addr, ioc->data, 1)) { + status = -EFAULT; + break; } + outb(tmp.addr[0], EWRK3_CSR); } else { status = -EPERM; } @@ -1826,9 +1829,8 @@ tmp.addr[i++] = inb(EWRK3_PAR0 + j); } ioc->len = EEPROM_MAX + 1 + ETH_ALEN; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; } else { status = -EPERM; } @@ -1836,11 +1838,12 @@ break; case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ if (capable(CAP_NET_ADMIN)) { - if (!(status = verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { - copy_from_user(tmp.addr, ioc->data, EEPROM_MAX); - for (i = 0; i < (EEPROM_MAX >> 1); i++) { - Write_EEPROM(tmp.val[i], iobase, i); - } + if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) { + status = -EFAULT; + break; + } + for (i = 0; i < (EEPROM_MAX >> 1); i++) { + Write_EEPROM(tmp.val[i], iobase, i); } } else { status = -EPERM; @@ -1850,9 +1853,8 @@ case EWRK3_GET_CMR: /* Get the CMR Register contents */ tmp.addr[0] = inb(EWRK3_CMR); ioc->len = 1; - if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - copy_to_user(ioc->data, tmp.addr, ioc->len); - } + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + status = -EFAULT; break; case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ if (suser()) { diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.2.10/linux/drivers/net/hamradio/Config.in Tue Dec 29 11:30:56 1998 +++ linux/drivers/net/hamradio/Config.in Mon Aug 9 12:04:39 1999 @@ -28,3 +28,5 @@ bool ' soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800 bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 fi + +tristate 'YAM driver for AX.25' CONFIG_YAM diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.2.10/linux/drivers/net/hamradio/Makefile Sun Jun 7 11:13:45 1998 +++ linux/drivers/net/hamradio/Makefile Mon Aug 9 12:04:39 1999 @@ -53,6 +53,14 @@ endif endif +ifeq ($(CONFIG_YAM),y) +L_OBJS += yam.o +else + ifeq ($(CONFIG_YAM),m) + M_OBJS += yam.o + endif +endif + ifeq ($(CONFIG_PI),y) L_OBJS += pi2.o else diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c --- v2.2.10/linux/drivers/net/hamradio/hdlcdrv.c Tue Dec 29 11:30:56 1998 +++ linux/drivers/net/hamradio/hdlcdrv.c Mon Aug 9 12:04:39 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h --- v2.2.10/linux/drivers/net/hamradio/soundmodem/sm.h Fri Jul 10 14:01:13 1998 +++ linux/drivers/net/hamradio/soundmodem/sm.h Mon Aug 9 12:04:39 1999 @@ -296,8 +296,6 @@ #ifdef __i386__ -#include - #define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC) /* diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c --- v2.2.10/linux/drivers/net/hamradio/yam.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/yam.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,1297 @@ +/*****************************************************************************/ + +/* + * yam.c -- YAM radio modem driver. + * + * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr) + * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * 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. + * + * Please note that the GPL allows you to use the driver, NOT the radio. + * In order to use the radio, you need a license from the communications + * authority of your country. + * + * + * History: + * 0.0 F1OAT 06.06.98 Begin of work with baycom.c source code V 0.3 + * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration + * 0.2 F6FBB 08.06.98 Added delay after FPGA programming + * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 + * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance + * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics + * 0.6 F6FBB 25.08.98 Added 1200Bds format + * 0.7 F6FBB 12.09.98 Added to the kernel configuration + * 0.8 F6FBB 14.10.98 Fixed slottime/persistance timing bug + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) +/* prototypes for ax25_encapsulate and ax25_rebuild_header */ +#include +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + +/* make genksyms happy */ +#include +#include +#include + +#include +#include + +#include +#include "yam9600.h" +#include "yam1200.h" + +/* --------------------------------------------------------------------- */ + +/* + * currently this module is supposed to support both module styles, i.e. + * the old one present up to about 2.1.9, and the new one functioning + * starting with 2.1.21. The reason is I have a kit allowing to compile + * this module also under 2.0.x which was requested by several people. + * This will go in 2.2 + */ +#include + +#if LINUX_VERSION_CODE >= 0x20100 +#include +#else +#include +#include + +#undef put_user +#undef get_user + +#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; }) +#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; }) + +extern inline int copy_from_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_READ, from, n); + if (i) + return i; + memcpy_fromfs(to, from, n); + return 0; +} + +extern inline int copy_to_user(void *to, const void *from, unsigned long n) +{ + int i = verify_area(VERIFY_WRITE, to, n); + if (i) + return i; + memcpy_tofs(to, from, n); + return 0; +} +#endif + +#if LINUX_VERSION_CODE < 0x20115 +extern __inline__ void dev_init_buffers(struct device *dev) +{ + int i; + for (i = 0; i < DEV_NUMBUFFS; i++) { + skb_queue_head_init(&dev->buffs[i]); + } +} +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +/* --------------------------------------------------------------------- */ + +static const char yam_drvname[] = "yam"; +static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n"; + +/* --------------------------------------------------------------------- */ + +#define YAM_9600 1 +#define YAM_1200 2 + +#define NR_PORTS 4 +#define YAM_MAGIC 0xF10A7654 + +/* Transmitter states */ + +#define TX_OFF 0 +#define TX_HEAD 1 +#define TX_DATA 2 +#define TX_CRC1 3 +#define TX_CRC2 4 +#define TX_TAIL 5 + +#define YAM_MAX_FRAME 1024 + +#define DEFAULT_BITRATE 9600 /* bps */ +#define DEFAULT_HOLDD 10 /* sec */ +#define DEFAULT_TXD 300 /* ms */ +#define DEFAULT_TXTAIL 10 /* ms */ +#define DEFAULT_SLOT 100 /* ms */ +#define DEFAULT_PERS 64 /* 0->255 */ + +struct yam_port { + int magic; + int bitrate; + int baudrate; + int iobase; + int irq; + int dupmode; + char name[16]; + + struct device dev; + + /* Stats section */ + +#if LINUX_VERSION_CODE < 0x20119 + struct enet_statistics stats; +#else + struct net_device_stats stats; +#endif + int nb_rxint; + int nb_mdint; + + /* Parameters section */ + + int txd; /* tx delay */ + int holdd; /* duplex ptt delay */ + int txtail; /* txtail delay */ + int slot; /* slottime */ + int pers; /* persistence */ + + /* Tx section */ + + int tx_state; + int tx_count; + int slotcnt; + unsigned char tx_buf[YAM_MAX_FRAME]; + int tx_len; + int tx_crcl, tx_crch; + struct sk_buff_head send_queue; /* Packets awaiting transmission */ + + /* Rx section */ + + int dcd; + unsigned char rx_buf[YAM_MAX_FRAME]; + int rx_len; + int rx_crcl, rx_crch; +}; + +struct yam_mcs { + unsigned char bits[YAM_FPGA_SIZE]; + int bitrate; + struct yam_mcs *next; +}; + +static struct yam_port yam_ports[NR_PORTS]; + +static struct yam_mcs *yam_data = NULL; + +static unsigned irqs[16]; + +static char ax25_bcast[7] = +{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; +static char ax25_test[7] = +{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; + +static struct timer_list yam_timer; + +/* --------------------------------------------------------------------- */ + +#define RBR(iobase) (iobase+0) +#define THR(iobase) (iobase+0) +#define IER(iobase) (iobase+1) +#define IIR(iobase) (iobase+2) +#define FCR(iobase) (iobase+2) +#define LCR(iobase) (iobase+3) +#define MCR(iobase) (iobase+4) +#define LSR(iobase) (iobase+5) +#define MSR(iobase) (iobase+6) +#define SCR(iobase) (iobase+7) +#define DLL(iobase) (iobase+0) +#define DLM(iobase) (iobase+1) + +#define YAM_EXTENT 8 + +/* Interrupt Identification Register Bit Masks */ +#define IIR_NOPEND 1 +#define IIR_MSR 0 +#define IIR_TX 2 +#define IIR_RX 4 +#define IIR_LSR 6 +#define IIR_TIMEOUT 12 /* Fifo mode only */ + +#define IIR_MASK 0x0F + +/* Interrupt Enable Register Bit Masks */ +#define IER_RX 1 /* enable rx interrupt */ +#define IER_TX 2 /* enable tx interrupt */ +#define IER_LSR 4 /* enable line status interrupts */ +#define IER_MSR 8 /* enable modem status interrupts */ + +/* Modem Control Register Bit Masks */ +#define MCR_DTR 0x01 /* DTR output */ +#define MCR_RTS 0x02 /* RTS output */ +#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */ +#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */ +#define MCR_LOOP 0x10 /* Loopback enable */ + +/* Modem Status Register Bit Masks */ +#define MSR_DCTS 0x01 /* Delta CTS input */ +#define MSR_DDSR 0x02 /* Delta DSR */ +#define MSR_DRIN 0x04 /* Delta RI */ +#define MSR_DDCD 0x08 /* Delta DCD */ +#define MSR_CTS 0x10 /* CTS input */ +#define MSR_DSR 0x20 /* DSR input */ +#define MSR_RING 0x40 /* RI input */ +#define MSR_DCD 0x80 /* DCD input */ + +/* line status register bit mask */ +#define LSR_RXC 0x01 +#define LSR_OE 0x02 +#define LSR_PE 0x04 +#define LSR_FE 0x08 +#define LSR_BREAK 0x10 +#define LSR_THRE 0x20 +#define LSR_TSRE 0x40 + +/* Line Control Register Bit Masks */ +#define LCR_DLAB 0x80 +#define LCR_BREAK 0x40 +#define LCR_PZERO 0x28 +#define LCR_PEVEN 0x18 +#define LCR_PODD 0x08 +#define LCR_STOP1 0x00 +#define LCR_STOP2 0x04 +#define LCR_BIT5 0x00 +#define LCR_BIT6 0x02 +#define LCR_BIT7 0x01 +#define LCR_BIT8 0x03 + +/* YAM Modem <-> UART Port mapping */ + +#define TX_RDY MSR_DCTS /* transmitter ready to send */ +#define RX_DCD MSR_DCD /* carrier detect */ +#define RX_FLAG MSR_RING /* hdlc flag received */ +#define FPGA_DONE MSR_DSR /* FPGA is configured */ +#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */ +#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */ + +#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */ +#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */ +#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */ + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/************************************************************************* +* CRC Tables +************************************************************************/ + +static const unsigned char chktabl[256] = +{0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf, 0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e, + 0xf7, 0x81, 0x08, 0x93, 0x1a, 0xa5, 0x2c, 0xb7, 0x3e, 0xc9, 0x40, 0xdb, 0x52, 0xed, 0x64, + 0xff, 0x76, 0x02, 0x8b, 0x10, 0x99, 0x26, 0xaf, 0x34, 0xbd, 0x4a, 0xc3, 0x58, 0xd1, 0x6e, + 0xe7, 0x7c, 0xf5, 0x83, 0x0a, 0x91, 0x18, 0xa7, 0x2e, 0xb5, 0x3c, 0xcb, 0x42, 0xd9, 0x50, + 0xef, 0x66, 0xfd, 0x74, 0x04, 0x8d, 0x16, 0x9f, 0x20, 0xa9, 0x32, 0xbb, 0x4c, 0xc5, 0x5e, + 0xd7, 0x68, 0xe1, 0x7a, 0xf3, 0x85, 0x0c, 0x97, 0x1e, 0xa1, 0x28, 0xb3, 0x3a, 0xcd, 0x44, + 0xdf, 0x56, 0xe9, 0x60, 0xfb, 0x72, 0x06, 0x8f, 0x14, 0x9d, 0x22, 0xab, 0x30, 0xb9, 0x4e, + 0xc7, 0x5c, 0xd5, 0x6a, 0xe3, 0x78, 0xf1, 0x87, 0x0e, 0x95, 0x1c, 0xa3, 0x2a, 0xb1, 0x38, + 0xcf, 0x46, 0xdd, 0x54, 0xeb, 0x62, 0xf9, 0x70, 0x08, 0x81, 0x1a, 0x93, 0x2c, 0xa5, 0x3e, + 0xb7, 0x40, 0xc9, 0x52, 0xdb, 0x64, 0xed, 0x76, 0xff, 0x89, 0x00, 0x9b, 0x12, 0xad, 0x24, + 0xbf, 0x36, 0xc1, 0x48, 0xd3, 0x5a, 0xe5, 0x6c, 0xf7, 0x7e, 0x0a, 0x83, 0x18, 0x91, 0x2e, + 0xa7, 0x3c, 0xb5, 0x42, 0xcb, 0x50, 0xd9, 0x66, 0xef, 0x74, 0xfd, 0x8b, 0x02, 0x99, 0x10, + 0xaf, 0x26, 0xbd, 0x34, 0xc3, 0x4a, 0xd1, 0x58, 0xe7, 0x6e, 0xf5, 0x7c, 0x0c, 0x85, 0x1e, + 0x97, 0x28, 0xa1, 0x3a, 0xb3, 0x44, 0xcd, 0x56, 0xdf, 0x60, 0xe9, 0x72, 0xfb, 0x8d, 0x04, + 0x9f, 0x16, 0xa9, 0x20, 0xbb, 0x32, 0xc5, 0x4c, 0xd7, 0x5e, 0xe1, 0x68, 0xf3, 0x7a, 0x0e, + 0x87, 0x1c, 0x95, 0x2a, 0xa3, 0x38, 0xb1, 0x46, 0xcf, 0x54, 0xdd, 0x62, 0xeb, 0x70, 0xf9, + 0x8f, 0x06, 0x9d, 0x14, 0xab, 0x22, 0xb9, 0x30, 0xc7, 0x4e, 0xd5, 0x5c, 0xe3, 0x6a, 0xf1, + 0x78}; +static const unsigned char chktabh[256] = +{0x00, 0x11, 0x23, 0x32, 0x46, 0x57, 0x65, 0x74, 0x8c, 0x9d, 0xaf, 0xbe, 0xca, 0xdb, 0xe9, + 0xf8, 0x10, 0x01, 0x33, 0x22, 0x56, 0x47, 0x75, 0x64, 0x9c, 0x8d, 0xbf, 0xae, 0xda, 0xcb, + 0xf9, 0xe8, 0x21, 0x30, 0x02, 0x13, 0x67, 0x76, 0x44, 0x55, 0xad, 0xbc, 0x8e, 0x9f, 0xeb, + 0xfa, 0xc8, 0xd9, 0x31, 0x20, 0x12, 0x03, 0x77, 0x66, 0x54, 0x45, 0xbd, 0xac, 0x9e, 0x8f, + 0xfb, 0xea, 0xd8, 0xc9, 0x42, 0x53, 0x61, 0x70, 0x04, 0x15, 0x27, 0x36, 0xce, 0xdf, 0xed, + 0xfc, 0x88, 0x99, 0xab, 0xba, 0x52, 0x43, 0x71, 0x60, 0x14, 0x05, 0x37, 0x26, 0xde, 0xcf, + 0xfd, 0xec, 0x98, 0x89, 0xbb, 0xaa, 0x63, 0x72, 0x40, 0x51, 0x25, 0x34, 0x06, 0x17, 0xef, + 0xfe, 0xcc, 0xdd, 0xa9, 0xb8, 0x8a, 0x9b, 0x73, 0x62, 0x50, 0x41, 0x35, 0x24, 0x16, 0x07, + 0xff, 0xee, 0xdc, 0xcd, 0xb9, 0xa8, 0x9a, 0x8b, 0x84, 0x95, 0xa7, 0xb6, 0xc2, 0xd3, 0xe1, + 0xf0, 0x08, 0x19, 0x2b, 0x3a, 0x4e, 0x5f, 0x6d, 0x7c, 0x94, 0x85, 0xb7, 0xa6, 0xd2, 0xc3, + 0xf1, 0xe0, 0x18, 0x09, 0x3b, 0x2a, 0x5e, 0x4f, 0x7d, 0x6c, 0xa5, 0xb4, 0x86, 0x97, 0xe3, + 0xf2, 0xc0, 0xd1, 0x29, 0x38, 0x0a, 0x1b, 0x6f, 0x7e, 0x4c, 0x5d, 0xb5, 0xa4, 0x96, 0x87, + 0xf3, 0xe2, 0xd0, 0xc1, 0x39, 0x28, 0x1a, 0x0b, 0x7f, 0x6e, 0x5c, 0x4d, 0xc6, 0xd7, 0xe5, + 0xf4, 0x80, 0x91, 0xa3, 0xb2, 0x4a, 0x5b, 0x69, 0x78, 0x0c, 0x1d, 0x2f, 0x3e, 0xd6, 0xc7, + 0xf5, 0xe4, 0x90, 0x81, 0xb3, 0xa2, 0x5a, 0x4b, 0x79, 0x68, 0x1c, 0x0d, 0x3f, 0x2e, 0xe7, + 0xf6, 0xc4, 0xd5, 0xa1, 0xb0, 0x82, 0x93, 0x6b, 0x7a, 0x48, 0x59, 0x2d, 0x3c, 0x0e, 0x1f, + 0xf7, 0xe6, 0xd4, 0xc5, 0xb1, 0xa0, 0x92, 0x83, 0x7b, 0x6a, 0x58, 0x49, 0x3d, 0x2c, 0x1e, + 0x0f}; + +/************************************************************************* +* FPGA functions +************************************************************************/ + +static void delay(int ms) +{ + unsigned long timeout = jiffies + ((ms * HZ) / 1000); + while (jiffies < timeout); +} + +/* + * reset FPGA + */ + +static void fpga_reset(int iobase) +{ + outb(0, IER(iobase)); + outb(LCR_DLAB | LCR_BIT5, LCR(iobase)); + outb(1, DLL(iobase)); + outb(0, DLM(iobase)); + + outb(LCR_BIT5, LCR(iobase)); + inb(LSR(iobase)); + inb(MSR(iobase)); + /* turn off FPGA supply voltage */ + outb(MCR_OUT1 | MCR_OUT2, MCR(iobase)); + delay(100); + /* turn on FPGA supply voltage again */ + outb(MCR_DTR | MCR_RTS | MCR_OUT1 | MCR_OUT2, MCR(iobase)); + delay(100); +} + +/* + * send one byte to FPGA + */ + +static int fpga_write(int iobase, unsigned char wrd) +{ + unsigned char bit; + int k; + unsigned long timeout = jiffies + HZ / 10; + + for (k = 0; k < 8; k++) { + bit = (wrd & 0x80) ? (MCR_RTS | MCR_DTR) : MCR_DTR; + outb(bit | MCR_OUT1 | MCR_OUT2, MCR(iobase)); + wrd <<= 1; + outb(0xfc, THR(iobase)); + while ((inb(LSR(iobase)) & LSR_TSRE) == 0) + if (jiffies > timeout) + return -1; + } + + return 0; +} + +#ifdef MODULE +static void free_mcs(void) +{ + struct yam_mcs *p; + + while (yam_data) { + p = yam_data; + yam_data = yam_data->next; + kfree(p); + } +} +#endif + +static unsigned char * + add_mcs(unsigned char *bits, int bitrate) +{ + struct yam_mcs *p; + + /* If it already exists, replace the bit data */ + p = yam_data; + while (p) { + if (p->bitrate == bitrate) { + memcpy(p->bits, bits, YAM_FPGA_SIZE); + return p->bits; + } + p = p->next; + } + + /* Allocate a new mcs */ + p = kmalloc(sizeof(struct yam_mcs), GFP_ATOMIC); + if (p == NULL) { + printk(KERN_WARNING "YAM: no memory to allocate mcs\n"); + return NULL; + } + memcpy(p->bits, bits, YAM_FPGA_SIZE); + p->bitrate = bitrate; + p->next = yam_data; + yam_data = p; + + return p->bits; +} + +static unsigned char *get_mcs(int bitrate) +{ + struct yam_mcs *p; + + p = yam_data; + while (p) { + if (p->bitrate == bitrate) + return p->bits; + p = p->next; + } + + /* Load predefined mcs data */ + switch (bitrate) { + case 1200: + return add_mcs(bits_1200, bitrate); + default: + return add_mcs(bits_9600, bitrate); + } +} + +/* + * download bitstream to FPGA + * data is contained in bits[] array in fpgaconf.h + */ + +static int fpga_download(int iobase, int bitrate) +{ + int i, rc; + unsigned char *pbits; + + pbits = get_mcs(bitrate); + if (pbits == NULL) + return -1; + + fpga_reset(iobase); + for (i = 0; i < YAM_FPGA_SIZE; i++) { + if (fpga_write(iobase, pbits[i])) { + printk("yam: error in write cycle\n"); + return -1; /* write... */ + } + } + + fpga_write(iobase, 0xFF); + rc = inb(MSR(iobase)); /* check DONE signal */ + + /* Needed for some hardwares */ + delay(50); + + return (rc & MSR_DSR) ? 0 : -1; +} + + +/************************************************************************ +* Serial port init +************************************************************************/ + +static void yam_set_uart(struct device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + int divisor = 115200 / yp->baudrate; + + outb(0, IER(dev->base_addr)); + outb(LCR_DLAB | LCR_BIT8, LCR(dev->base_addr)); + outb(divisor, DLL(dev->base_addr)); + outb(0, DLM(dev->base_addr)); + outb(LCR_BIT8, LCR(dev->base_addr)); + outb(PTT_OFF, MCR(dev->base_addr)); + outb(0x00, FCR(dev->base_addr)); + + /* Flush pending irq */ + + inb(RBR(dev->base_addr)); + inb(MSR(dev->base_addr)); + + /* Enable rx irq */ + + outb(ENABLE_RTXINT, IER(dev->base_addr)); +} + + +/* --------------------------------------------------------------------- */ + +enum uart { + c_uart_unknown, c_uart_8250, + c_uart_16450, c_uart_16550, c_uart_16550A +}; + +static const char *uart_str[] = +{"unknown", "8250", "16450", "16550", "16550A"}; + +static enum uart yam_check_uart(unsigned int iobase) +{ + unsigned char b1, b2, b3; + enum uart u; + enum uart uart_tab[] = + {c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A}; + + b1 = inb(MCR(iobase)); + outb(b1 | 0x10, MCR(iobase)); /* loopback mode */ + b2 = inb(MSR(iobase)); + outb(0x1a, MCR(iobase)); + b3 = inb(MSR(iobase)) & 0xf0; + outb(b1, MCR(iobase)); /* restore old values */ + outb(b2, MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(RBR(iobase)); + inb(RBR(iobase)); + outb(0x01, FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, SCR(iobase)); + b1 = inb(SCR(iobase)); + outb(0xa5, SCR(iobase)); + b2 = inb(SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/****************************************************************************** +* Rx Section +******************************************************************************/ +static void inline + yam_rx_flag(struct device *dev, struct yam_port *yp) +{ + if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) { + int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */ + struct sk_buff *skb; + + if ((yp->rx_crch & yp->rx_crcl) != 0xFF) { + /* Bad crc */ + } else { + if (!(skb = dev_alloc_skb(pkt_len))) { + printk("%s: memory squeeze, dropping packet\n", dev->name); + ++yp->stats.rx_dropped; + } else { + unsigned char *cp; + skb->dev = dev; + cp = skb_put(skb, pkt_len); + *cp++ = 0; /* KISS kludge */ + memcpy(cp, yp->rx_buf, pkt_len - 1); + skb->protocol = htons(ETH_P_AX25); + skb->mac.raw = skb->data; + netif_rx(skb); + ++yp->stats.rx_packets; + } + } + } + yp->rx_len = 0; + yp->rx_crcl = 0x21; + yp->rx_crch = 0xf3; +} + +static void inline + yam_rx_byte(struct device *dev, struct yam_port *yp, unsigned char rxb) +{ + if (yp->rx_len < YAM_MAX_FRAME) { + unsigned char c = yp->rx_crcl; + yp->rx_crcl = (chktabl[c] ^ yp->rx_crch); + yp->rx_crch = (chktabh[c] ^ rxb); + yp->rx_buf[yp->rx_len++] = rxb; + } +} + +/******************************************************************************** +* TX Section +********************************************************************************/ + +static void ptt_on(struct device *dev) +{ + outb(PTT_ON, MCR(dev->base_addr)); +} + +static void ptt_off(struct device *dev) +{ + outb(PTT_OFF, MCR(dev->base_addr)); +} + +static int yam_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct yam_port *yp = dev->priv; + + if (skb == NULL) { + return 0; + } + skb_queue_tail(&yp->send_queue, skb); + dev->trans_start = jiffies; + return 0; +} + +static void yam_start_tx(struct device *dev, struct yam_port *yp) +{ + if ((yp->tx_state == TX_TAIL) || (yp->txd == 0)) + yp->tx_count = 1; + else + yp->tx_count = (yp->bitrate * yp->txd) / 8000; + yp->tx_state = TX_HEAD; + ptt_on(dev); +} + +static unsigned short random_seed; + +static inline unsigned short random_num(void) +{ + random_seed = 28629 * random_seed + 157; + return random_seed; +} + +static void yam_arbitrate(struct device *dev) +{ + struct yam_port *yp = dev->priv; + + if (!yp || yp->magic != YAM_MAGIC + || yp->tx_state != TX_OFF || skb_queue_empty(&yp->send_queue)) { + return; + } + /* tx_state is TX_OFF and there is data to send */ + + if (yp->dupmode) { + /* Full duplex mode, don't wait */ + yam_start_tx(dev, yp); + return; + } + if (yp->dcd) { + /* DCD on, wait slotime ... */ + yp->slotcnt = yp->slot / 10; + return; + } + /* Is slottime passed ? */ + if ((--yp->slotcnt) > 0) + return; + + yp->slotcnt = yp->slot / 10; + + /* is random > persist ? */ + if ((random_num() % 256) > yp->pers) + return; + + yam_start_tx(dev, yp); +} + +static void yam_dotimer(unsigned long dummy) +{ + int i; + + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = &yam_ports[i].dev; + if (dev->start) + yam_arbitrate(dev); + } + yam_timer.expires = jiffies + HZ / 100; + add_timer(&yam_timer); +} + +static void yam_tx_byte(struct device *dev, struct yam_port *yp) +{ + struct sk_buff *skb; + unsigned char b, temp; + + switch (yp->tx_state) { + case TX_OFF: + break; + case TX_HEAD: + if (--yp->tx_count <= 0) { + if (!(skb = skb_dequeue(&yp->send_queue))) { + ptt_off(dev); + yp->tx_state = TX_OFF; + break; + } + yp->tx_state = TX_DATA; + if (skb->data[0] != 0) { +/* do_kiss_params(s, skb->data, skb->len); */ + dev_kfree_skb(skb); + break; + } + yp->tx_len = skb->len - 1; /* strip KISS byte */ + if (yp->tx_len >= YAM_MAX_FRAME || yp->tx_len < 2) { + dev_kfree_skb(skb); + break; + } + memcpy(yp->tx_buf, skb->data + 1, yp->tx_len); + dev_kfree_skb(skb); + yp->tx_count = 0; + yp->tx_crcl = 0x21; + yp->tx_crch = 0xf3; + yp->tx_state = TX_DATA; + } + break; + case TX_DATA: + b = yp->tx_buf[yp->tx_count++]; + outb(b, THR(dev->base_addr)); + temp = yp->tx_crcl; + yp->tx_crcl = chktabl[temp] ^ yp->tx_crch; + yp->tx_crch = chktabh[temp] ^ b; + if (yp->tx_count >= yp->tx_len) { + yp->tx_state = TX_CRC1; + } + break; + case TX_CRC1: + yp->tx_crch = chktabl[yp->tx_crcl] ^ yp->tx_crch; + yp->tx_crcl = chktabh[yp->tx_crcl] ^ chktabl[yp->tx_crch] ^ 0xff; + outb(yp->tx_crcl, THR(dev->base_addr)); + yp->tx_state = TX_CRC2; + break; + case TX_CRC2: + outb(chktabh[yp->tx_crch] ^ 0xFF, THR(dev->base_addr)); + if (skb_queue_empty(&yp->send_queue)) { + yp->tx_count = (yp->bitrate * yp->txtail) / 8000; + if (yp->dupmode == 2) + yp->tx_count += (yp->bitrate * yp->holdd) / 8; + if (yp->tx_count == 0) + yp->tx_count = 1; + yp->tx_state = TX_TAIL; + } else { + yp->tx_count = 1; + yp->tx_state = TX_HEAD; + } + ++yp->stats.tx_packets; + break; + case TX_TAIL: + if (--yp->tx_count <= 0) { + yp->tx_state = TX_OFF; + ptt_off(dev); + } + break; + } +} + +/*********************************************************************************** +* ISR routine +************************************************************************************/ + +static void yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev; + struct yam_port *yp; + unsigned char iir; + int counter = 100; + int i; + + sti(); + + for (i = 0; i < NR_PORTS; i++) { + yp = &yam_ports[i]; + dev = &yp->dev; + + if (!dev->start) + continue; + + while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) { + unsigned char msr = inb(MSR(dev->base_addr)); + unsigned char lsr = inb(LSR(dev->base_addr)); + unsigned char rxb; + + if (lsr & LSR_OE) + ++yp->stats.rx_fifo_errors; + + yp->dcd = (msr & RX_DCD) ? 1 : 0; + + if (--counter <= 0) { + printk("%s: too many irq iir=%d\n", dev->name, iir); + return; + } + if (msr & TX_RDY) { + ++yp->nb_mdint; + yam_tx_byte(dev, yp); + } + if (lsr & LSR_RXC) { + ++yp->nb_rxint; + rxb = inb(RBR(dev->base_addr)); + if (msr & RX_FLAG) + yam_rx_flag(dev, yp); + else + yam_rx_byte(dev, yp, rxb); + } + } + } +} + +static int yam_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +{ + int len = 0; + int i; + off_t pos = 0; + off_t begin = 0; + + cli(); + + for (i = 0; i < NR_PORTS; i++) { + if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0) + continue; + len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name); + len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start); + len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate); + len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase); + len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate); + len += sprintf(buffer + len, " IRQ %u\n", yam_ports[i].irq); + len += sprintf(buffer + len, " TxState %u\n", yam_ports[i].tx_state); + len += sprintf(buffer + len, " Duplex %u\n", yam_ports[i].dupmode); + len += sprintf(buffer + len, " HoldDly %u\n", yam_ports[i].holdd); + len += sprintf(buffer + len, " TxDelay %u\n", yam_ports[i].txd); + len += sprintf(buffer + len, " TxTail %u\n", yam_ports[i].txtail); + len += sprintf(buffer + len, " SlotTime %u\n", yam_ports[i].slot); + len += sprintf(buffer + len, " Persist %u\n", yam_ports[i].pers); + len += sprintf(buffer + len, " TxFrames %lu\n", yam_ports[i].stats.tx_packets); + len += sprintf(buffer + len, " RxFrames %lu\n", yam_ports[i].stats.rx_packets); + len += sprintf(buffer + len, " TxInt %u\n", yam_ports[i].nb_mdint); + len += sprintf(buffer + len, " RxInt %u\n", yam_ports[i].nb_rxint); + len += sprintf(buffer + len, " RxOver %lu\n", yam_ports[i].stats.rx_fifo_errors); + len += sprintf(buffer + len, "\n"); + + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + break; + } + + sti(); + + *start = buffer + (offset - begin); + len -= (offset - begin); + + if (len > length) + len = length; + + return len; +} + +#ifdef CONFIG_INET +#ifndef PROC_NET_YAM +#define PROC_NET_YAM (PROC_NET_LAST+10) /* Sorry again... */ +#endif + +struct proc_dir_entry yam_proc_dir_entry = +{ + PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, yam_net_get_info +}; + +#define yam_net_procfs_init() proc_net_register(&yam_proc_dir_entry); +#define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM); +#else +#define yam_net_procfs_init() +#define yam_net_procfs_remove() +#endif + +/* --------------------------------------------------------------------- */ + +#if LINUX_VERSION_CODE >= 0x20119 +static struct net_device_stats * + yam_get_stats(struct device *dev) +#else +static struct enet_statistics * + yam_get_stats(struct device *dev) +#endif +{ + struct yam_port *yp; + + if (!dev || !dev->priv) + return NULL; + + yp = (struct yam_port *) dev->priv; + if (yp->magic != YAM_MAGIC) + return NULL; + + /* + * Get the current statistics. This may be called with the + * card open or closed. + */ + return &yp->stats; +} + +/* --------------------------------------------------------------------- */ + +static int yam_open(struct device *dev) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + enum uart u; + int i; + + printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); + + if (!dev || !yp || !yp->bitrate) + return -ENXIO; + if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || + dev->irq < 2 || dev->irq > 15) { + return -ENXIO; + } + if (check_region(dev->base_addr, YAM_EXTENT)) { + printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); + return -EACCES; + } + if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) { + printk("%s: cannot find uart type\n", dev->name); + return -EIO; + } + if (fpga_download(dev->base_addr, yp->bitrate)) { + printk("%s: cannot init FPGA\n", dev->name); + return -EIO; + } + outb(0, IER(dev->base_addr)); + if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) { + printk("%s: irq %d busy\n", dev->name, dev->irq); + return -EBUSY; + } + request_region(dev->base_addr, YAM_EXTENT, dev->name); + + yam_set_uart(dev); + dev->start = 1; + yp->slotcnt = yp->slot / 10; + + /* Reset overruns for all ports - FPGA programming makes overruns */ + for (i = 0; i < NR_PORTS; i++) { + inb(LSR(yam_ports[i].dev.base_addr)); + yam_ports[i].stats.rx_fifo_errors = 0; + } + + printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq, + uart_str[u]); + MOD_INC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_close(struct device *dev) +{ + struct sk_buff *skb; + struct yam_port *yp = (struct yam_port *) dev->priv; + + if (!dev || !yp) + return -EINVAL; + /* + * disable interrupts + */ + outb(0, IER(dev->base_addr)); + outb(1, MCR(dev->base_addr)); + /* Remove IRQ handler if last */ + free_irq(dev->irq, NULL); + release_region(dev->base_addr, YAM_EXTENT); + dev->start = 0; + dev->tbusy = 1; + while ((skb = skb_dequeue(&yp->send_queue))) + dev_kfree_skb(skb); + + printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n", + yam_drvname, dev->base_addr, dev->irq); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + struct yam_port *yp = (struct yam_port *) dev->priv; + struct yamdrv_ioctl_cfg yi; + struct yamdrv_ioctl_mcs *ym; + int ioctl_cmd; + + if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int))) + return -EFAULT; + + if (yp == NULL || yp->magic != YAM_MAGIC) + return -EINVAL; + + if (!suser()) + return -EPERM; + + if (cmd != SIOCDEVPRIVATE) + return -EINVAL; + + switch (ioctl_cmd) { + + case SIOCYAMRESERVED: + return -EINVAL; /* unused */ + + case SIOCYAMSMCS: + if (dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC); + ym->bitrate = 9600; + if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) + return -EFAULT; + if (ym->bitrate > YAM_MAXBITRATE) + return -EINVAL; + add_mcs(ym->bits, ym->bitrate); + kfree(ym); + break; + + case SIOCYAMSCFG: + if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg))) + return -EFAULT; + + if ((yi.cfg.mask & YAM_IOBASE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_IRQ) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_BITRATE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start) + return -EINVAL; /* Cannot change this parameter when up */ + + if (yi.cfg.mask & YAM_IOBASE) { + yp->iobase = yi.cfg.iobase; + dev->base_addr = yi.cfg.iobase; + } + if (yi.cfg.mask & YAM_IRQ) { + if (yi.cfg.irq > 15) + return -EINVAL; + yp->irq = yi.cfg.irq; + dev->irq = yi.cfg.irq; + } + if (yi.cfg.mask & YAM_BITRATE) { + if (yi.cfg.bitrate > YAM_MAXBITRATE) + return -EINVAL; + yp->bitrate = yi.cfg.bitrate; + } + if (yi.cfg.mask & YAM_BAUDRATE) { + if (yi.cfg.baudrate > YAM_MAXBAUDRATE) + return -EINVAL; + yp->baudrate = yi.cfg.baudrate; + } + if (yi.cfg.mask & YAM_MODE) { + if (yi.cfg.mode > YAM_MAXMODE) + return -EINVAL; + yp->dupmode = yi.cfg.mode; + } + if (yi.cfg.mask & YAM_HOLDDLY) { + if (yi.cfg.holddly > YAM_MAXHOLDDLY) + return -EINVAL; + yp->holdd = yi.cfg.holddly; + } + if (yi.cfg.mask & YAM_TXDELAY) { + if (yi.cfg.txdelay > YAM_MAXTXDELAY) + return -EINVAL; + yp->txd = yi.cfg.txdelay; + } + if (yi.cfg.mask & YAM_TXTAIL) { + if (yi.cfg.txtail > YAM_MAXTXTAIL) + return -EINVAL; + yp->txtail = yi.cfg.txtail; + } + if (yi.cfg.mask & YAM_PERSIST) { + if (yi.cfg.persist > YAM_MAXPERSIST) + return -EINVAL; + yp->pers = yi.cfg.persist; + } + if (yi.cfg.mask & YAM_SLOTTIME) { + if (yi.cfg.slottime > YAM_MAXSLOTTIME) + return -EINVAL; + yp->slot = yi.cfg.slottime; + yp->slotcnt = yp->slot / 10; + } + break; + + case SIOCYAMGCFG: + yi.cfg.mask = 0xffffffff; + yi.cfg.iobase = yp->iobase; + yi.cfg.irq = yp->irq; + yi.cfg.bitrate = yp->bitrate; + yi.cfg.baudrate = yp->baudrate; + yi.cfg.mode = yp->dupmode; + yi.cfg.txdelay = yp->txd; + yi.cfg.holddly = yp->holdd; + yi.cfg.txtail = yp->txtail; + yi.cfg.persist = yp->pers; + yi.cfg.slottime = yp->slot; + if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg))) + return -EFAULT; + break; + + default: + return -EINVAL; + + } + + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_set_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa = (struct sockaddr *) addr; + + /* addr is an AX.25 shifted ASCII mac address */ + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int yam_probe(struct device *dev) +{ + struct yam_port *yp; + + if (!dev) + return -ENXIO; + + yp = (struct yam_port *) dev->priv; + + dev->open = yam_open; + dev->stop = yam_close; + dev->do_ioctl = yam_ioctl; + dev->hard_start_xmit = yam_send_packet; + dev->get_stats = yam_get_stats; + + dev_init_buffers(dev); + skb_queue_head_init(&yp->send_queue); + +#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) + dev->hard_header = ax25_encapsulate; + dev->rebuild_header = ax25_rebuild_header; +#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + dev->hard_header = NULL; + dev->rebuild_header = NULL; +#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ + + dev->set_mac_address = yam_set_mac_address; + + dev->type = ARPHRD_AX25; /* AF_AX25 device */ + dev->hard_header_len = 73; /* We do digipeaters now */ + dev->mtu = 256; /* AX25 is the default */ + dev->addr_len = 7; /* sizeof an ax.25 address */ + memcpy(dev->broadcast, ax25_bcast, 7); + memcpy(dev->dev_addr, ax25_test, 7); + + /* New style flags */ + dev->flags = 0; + + return 0; +} + +/* --------------------------------------------------------------------- */ + +__initfunc(int yam_init(struct device *dev)) +{ + int i; + + printk(yam_drvinfo); + + /* Clears the IRQ table */ + memset(irqs, 0, sizeof(irqs)); + memset(yam_ports, 0, sizeof(yam_ports)); + + for (i = 0; i < NR_PORTS; i++) { + sprintf(yam_ports[i].name, "yam%d", i); + yam_ports[i].magic = YAM_MAGIC; + yam_ports[i].bitrate = DEFAULT_BITRATE; + yam_ports[i].baudrate = DEFAULT_BITRATE * 2; + yam_ports[i].iobase = 0; + yam_ports[i].irq = 0; + yam_ports[i].dupmode = 0; + yam_ports[i].holdd = DEFAULT_HOLDD; + yam_ports[i].txd = DEFAULT_TXD; + yam_ports[i].txtail = DEFAULT_TXTAIL; + yam_ports[i].slot = DEFAULT_SLOT; + yam_ports[i].pers = DEFAULT_PERS; + + dev = &yam_ports[i].dev; + + dev->priv = &yam_ports[i]; + dev->name = yam_ports[i].name; + dev->base_addr = yam_ports[i].iobase; + dev->irq = yam_ports[i].irq; + dev->init = yam_probe; + dev->if_port = 0; + dev->start = 0; + dev->tbusy = 1; + + if (register_netdev(dev)) { + printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name); + return -ENXIO; + } + } + + yam_timer.function = yam_dotimer; + yam_timer.expires = jiffies + HZ / 100; + add_timer(&yam_timer); + + yam_net_procfs_init(); + + /* do not keep this device */ + return 1; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * command line settable parameters + */ + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); +MODULE_DESCRIPTION("Yam amateur radio modem driver"); + +#endif + +__initfunc(int init_module(void)) +{ + int ret = yam_init(NULL); + + return (ret == 1) ? 0 : ret; +} + +/* --------------------------------------------------------------------- */ + +void cleanup_module(void) +{ + int i; + + del_timer(&yam_timer); + for (i = 0; i < NR_PORTS; i++) { + struct device *dev = &yam_ports[i].dev; + if (!dev->priv) + continue; + if (dev->start) + yam_close(dev); + unregister_netdev(dev); + } + free_mcs(); + yam_net_procfs_remove(); +} + +#endif /* MODULE */ +/* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/yam1200.h linux/drivers/net/hamradio/yam1200.h --- v2.2.10/linux/drivers/net/hamradio/yam1200.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/yam1200.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,343 @@ +/* + * + * File yam1k2b5.mcs converted to h format by mcs2h + * + * (C) F6FBB 1998 + * + * Tue Aug 25 20:24:08 1998 + * + */ + +static unsigned char bits_1200[]= { +0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2, +0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf, +0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff, +0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf, +0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0, +0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f, +0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff, +0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, +0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb, +0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb, +0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe, +0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed, +0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef, +0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f, +0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff, +0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0, +0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f, +0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0, +0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f, +0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff, +0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e, +0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1, +0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea, +0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff, +0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff, +0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02, +0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, +0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff, +0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff, +0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf, +0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff, +0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff, +0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0, +0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08, +0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01, +0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f, +0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe, +0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33, +0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd, +0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff, +0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad, +0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc, +0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff, +0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff, +0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b, +0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf, +0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e, +0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f, +0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff, +0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff, +0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff, +0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40, +0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, +0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10, +0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00, +0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff, +0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7, +0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f, +0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff, +0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1, +0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd, +0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00, +0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00, +0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00, +0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff, +0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff, +0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef, +0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf, +0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7, +0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc, +0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff, +0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0, +0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7, +0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59, +0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f, +0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff, +0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5, +0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f, +0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc, +0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff, +0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab, +0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d, +0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff, +0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00, +0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00, +0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe, +0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff, +0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0, +0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff, +0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f, +0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34, +0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00, +0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03, +0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde, +0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef, +0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd, +0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1, +0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b, +0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, +0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd, +0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab, +0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff, +0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff, +0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff, +0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff, +0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff, +0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff, +0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1, +0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff, +0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff, +0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d, +0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7, +0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0, +0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, +0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20, +0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f, +0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf, +0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7, +0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff, +0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff, +0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d, +0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff, +0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02, +0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01, +0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe, +0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee, +0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f, +0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, +0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff, +0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2, +0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f, +0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff, +0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32, +0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4, +0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3, +0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97, +0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78, +0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1, +0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3, +0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff, +0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff, +0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe, +0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff, +0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed, +0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00, +0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00, +0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f, +0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff, +0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3, +0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff, +0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf, +0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0, +0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00, +0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10, +0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f, +0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd, +0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe, +0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a, +0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5, +0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff, +0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff, +0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb, +0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe, +0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf, +0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd, +0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8, +0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57, +0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73, +0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff, +0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, +0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b, +0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95, +0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00, +0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08, +0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81, +0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff, +0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe, +0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff, +0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed, +0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7, +0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01, +0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14, +0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10, +0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3, +0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf, +0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf, +0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73, +0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee, +0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0, +0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7, +0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f, +0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f, +0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0, +0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff, +0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff, +0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef, +0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff, +0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff, +0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff, +0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d, +0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8, +0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe, +0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00, +0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00, +0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd, +0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff, +0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff, +0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff, +0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54, +0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff, +0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00, +0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24, +0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24, +0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff, +0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf, +0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff, +0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb, +0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf, +0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6, +0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3, +0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe, +0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff, +0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe, +0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff, +0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b, +0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff, +0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff, +0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f, +0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9, +0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f, +0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff, +0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f, +0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, +0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00, +0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff, +0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff, +0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff, +0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff, +0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff, +0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff, +0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02, +0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00, +0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf, +0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe, +0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff, +0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff, +0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd, +0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1, +0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff, +0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff, +0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, +0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc, +0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, +0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff }; diff -u --recursive --new-file v2.2.10/linux/drivers/net/hamradio/yam9600.h linux/drivers/net/hamradio/yam9600.h --- v2.2.10/linux/drivers/net/hamradio/yam9600.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/yam9600.h Mon Aug 9 12:04:39 1999 @@ -0,0 +1,343 @@ +/* + * + * File yam111.mcs converted to h format by mcs2h + * + * (C) F6FBB 1998 + * + * Tue Aug 25 20:23:03 1998 + * + */ + +static unsigned char bits_9600[]= { +0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2, +0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf, +0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, +0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff, +0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf, +0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0, +0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7, +0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff, +0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, +0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef, +0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6, +0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef, +0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef, +0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f, +0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff, +0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff, +0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f, +0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff, +0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff, +0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1, +0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f, +0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff, +0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, +0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff, +0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2, +0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, +0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00, +0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0, +0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a, +0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad, +0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff, +0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5, +0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb, +0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff, +0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe, +0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3, +0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86, +0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff, +0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9, +0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd, +0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff, +0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc, +0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33, +0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04, +0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00, +0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd, +0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb, +0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff, +0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1, +0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff, +0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22, +0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00, +0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, +0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff, +0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff, +0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f, +0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7, +0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe, +0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5, +0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69, +0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0, +0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a, +0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3, +0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f, +0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5, +0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4, +0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14, +0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, +0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff, +0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf, +0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff, +0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00, +0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00, +0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe, +0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff, +0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0, +0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7, +0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf, +0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30, +0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06, +0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20, +0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f, +0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe, +0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5, +0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1, +0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba, +0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, +0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd, +0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf, +0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff, +0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff, +0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb, +0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd, +0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff, +0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, +0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1, +0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff, +0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff, +0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79, +0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed, +0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0, +0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, +0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20, +0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f, +0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff, +0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, +0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff, +0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff, +0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe, +0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff, +0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10, +0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, +0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff, +0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf, +0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff, +0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff, +0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2, +0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f, +0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, +0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff, +0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2, +0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5, +0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff, +0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf, +0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30, +0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1, +0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0, +0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff, +0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff, +0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f, +0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff, +0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef, +0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff, +0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90, +0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01, +0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3, +0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff, +0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff, +0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0, +0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03, +0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00, +0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f, +0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc, +0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f, +0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff, +0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc, +0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5, +0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff, +0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef, +0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb, +0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff, +0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff, +0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3, +0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7, +0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff, +0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, +0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb, +0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff, +0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00, +0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, +0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff, +0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1, +0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, +0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f, +0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff, +0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff, +0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00, +0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00, +0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00, +0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff, +0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79, +0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff, +0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77, +0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe, +0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0, +0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf, +0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff, +0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f, +0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff, +0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf, +0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff, +0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5, +0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff, +0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff, +0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef, +0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, +0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef, +0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9, +0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe, +0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00, +0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00, +0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff, +0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff, +0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff, +0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, +0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11, +0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00, +0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00, +0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6, +0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff, +0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf, +0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda, +0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda, +0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6, +0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd, +0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe, +0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff, +0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff, +0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff, +0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0, +0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff, +0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff, +0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f, +0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff, +0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, +0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf, +0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f, +0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf, +0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff, +0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff, +0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff, +0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb, +0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff, +0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff, +0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80, +0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe, +0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff, +0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7, +0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, +0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf, +0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, +0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff, +0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff, +0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, +0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff, +0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd, +0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef, +0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff, +0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, +0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd, +0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, +0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff }; diff -u --recursive --new-file v2.2.10/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c --- v2.2.10/linux/drivers/net/hostess_sv11.c Thu Feb 18 16:28:49 1999 +++ linux/drivers/net/hostess_sv11.c Mon Aug 9 12:04:39 1999 @@ -389,7 +389,8 @@ free_irq(dev->sync.irq, dev); if(dma) { - free_dma(dev->sync.chanA.rxdma); + if(dma==1) + free_dma(dev->sync.chanA.rxdma); free_dma(dev->sync.chanA.txdma); } release_region(dev->sync.chanA.ctrlio-1, 8); diff -u --recursive --new-file v2.2.10/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.2.10/linux/drivers/net/irda/toshoboe.c Sun May 30 10:17:03 1999 +++ linux/drivers/net/irda/toshoboe.c Mon Aug 9 12:04:39 1999 @@ -568,11 +568,11 @@ self->rxs = inb_p (OBOE_RCVT); self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET; -#ifdef 0 +#if 0 self->rxs = 0; self->txs = 0; #endif -#ifdef 0 +#if 0 self->rxs = RX_SLOTS - 1; self->txs = 0; #endif diff -u --recursive --new-file v2.2.10/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c --- v2.2.10/linux/drivers/net/jazzsonic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/jazzsonic.c Mon Aug 9 12:04:39 1999 @@ -0,0 +1,266 @@ +/* + * sonic.c + * + * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * This driver is based on work from Andreas Busse, but most of + * the code is rewritten. + * + * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) + * + * A driver for the onboard Sonic ethernet controller on Mips Jazz + * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and + * perhaps others, too) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SREGS_PAD(n) u16 n; + +#include "sonic.h" + +/* + * Macros to access SONIC registers + */ +#define SONIC_READ(reg) \ + *((volatile unsigned int *)base_addr+reg) + +#define SONIC_WRITE(reg,val) \ + *((volatile unsigned int *)base_addr+reg) = val + + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifdef SONIC_DEBUG +static unsigned int sonic_debug = SONIC_DEBUG; +#else +static unsigned int sonic_debug = 1; +#endif + +/* + * Base address and interupt of the SONIC controller on JAZZ boards + */ +static struct { + unsigned int port; + unsigned int irq; +} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}}; + +/* + * We cannot use station (ethernet) address prefixes to detect the + * sonic controller since these are board manufacturer depended. + * So we check for known Silicon Revision IDs instead. + */ +static unsigned short known_revisions[] = +{ + 0x04, /* Mips Magnum 4000 */ + 0xffff /* end of list */ +}; + +/* Index to functions, as function prototypes. */ + +extern int sonic_probe(struct device *dev); +static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq); + + +/* + * Probe for a SONIC ethernet controller on a Mips Jazz board. + * Actually probing is superfluous but we're paranoid. + */ +__initfunc(int sonic_probe(struct device *dev)) +{ + unsigned int base_addr = dev ? dev->base_addr : 0; + int i; + + /* + * Don't probe if we're not running on a Jazz board. + */ + if (mips_machgroup != MACH_GROUP_JAZZ) + return -ENODEV; + if (base_addr >= KSEG0) /* Check a single specified location. */ + return sonic_probe1(dev, base_addr, dev->irq); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + + for (i = 0; sonic_portlist[i].port; i++) { + int base_addr = sonic_portlist[i].port; + if (check_region(base_addr, 0x100)) + continue; + if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0) + return 0; + } + return -ENODEV; +} + +__initfunc(static int sonic_probe1(struct device *dev, + unsigned int base_addr, unsigned int irq)) +{ + static unsigned version_printed = 0; + unsigned int silicon_revision; + unsigned int val; + struct sonic_local *lp; + int i; + + /* + * get the Silicon Revision ID. If this is one of the known + * one assume that we found a SONIC ethernet controller at + * the expected location. + */ + silicon_revision = SONIC_READ(SONIC_SR); + if (sonic_debug > 1) + printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); + + i = 0; + while ((known_revisions[i] != 0xffff) && + (known_revisions[i] != silicon_revision)) + i++; + + if (known_revisions[i] == 0xffff) { + printk("SONIC ethernet controller not found (0x%4x)\n", + silicon_revision); + return -ENODEV; + } + + request_region(base_addr, 0x100, "SONIC"); + + /* Allocate a new 'dev' if needed. */ + if (dev == NULL) + dev = init_etherdev(0, sizeof(struct sonic_local)); + + if (sonic_debug && version_printed++ == 0) + printk(version); + + printk("%s: %s found at 0x%08x, ", + dev->name, "SONIC ethernet", base_addr); + + /* Fill in the 'dev' fields. */ + dev->base_addr = base_addr; + dev->irq = irq; + + /* + * Put the sonic into software reset, then + * retrieve and print the ethernet address. + */ + SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); + SONIC_WRITE(SONIC_CEP,0); + for (i=0; i<3; i++) { + val = SONIC_READ(SONIC_CAP0-i); + dev->dev_addr[i*2] = val; + dev->dev_addr[i*2+1] = val >> 8; + } + + printk("HW Address "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i<5) + printk(":"); + } + + printk(" IRQ %d\n", irq); + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + /* + * the memory be located in the same 64kb segment + */ + lp = NULL; + i = 0; + do { + lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL); + if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) { + /* FIXME, free the memory later */ + kfree (lp); + lp = NULL; + } + } while (lp == NULL && i++ < 20); + + if (lp == NULL) { + printk ("%s: couldn't allocate memory for descriptors\n", + dev->name); + return -ENOMEM; + } + + memset(lp, 0, sizeof(struct sonic_local)); + + /* get the virtual dma address */ + lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp)); + if (lp->cda_laddr == ~0UL) { + printk ("%s: couldn't get DMA page entry for descriptors\n", + dev->name); + return -ENOMEM; + } + + lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); + lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); + lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); + + /* allocate receive buffer area */ + /* FIXME, maybe we should use skbs */ + if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) { + printk ("%s: couldn't allocate receive buffers\n",dev->name); + return -ENOMEM; + } + + /* get virtual dma address */ + if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) { + printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name); + return -ENOMEM; + } + + /* now convert pointer to KSEG1 pointer */ + lp->rba = (char *)KSEG1ADDR(lp->rba); + flush_cache_all(); + dev->priv = (struct sonic_local *)KSEG1ADDR(lp); + } + + lp = (struct sonic_local *)dev->priv; + dev->open = sonic_open; + dev->stop = sonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; + + /* + * clear tally counter + */ + SONIC_WRITE(SONIC_CRCT,0xffff); + SONIC_WRITE(SONIC_FAET,0xffff); + SONIC_WRITE(SONIC_MPT,0xffff); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; +} + +/* + * SONIC uses a normal IRQ + */ +#define sonic_request_irq request_irq +#define sonic_free_irq free_irq + +#define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x)) + +#include "sonic.c" diff -u --recursive --new-file v2.2.10/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.2.10/linux/drivers/net/lance.c Mon Dec 28 11:05:14 1998 +++ linux/drivers/net/lance.c Mon Aug 9 12:04:39 1999 @@ -499,6 +499,8 @@ lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, GFP_DMA | GFP_KERNEL)+7) & ~7); + if(lp==NULL) + return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); memset(lp, 0, sizeof(*lp)); dev->priv = lp; diff -u --recursive --new-file v2.2.10/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.2.10/linux/drivers/net/mace.c Wed Mar 10 21:48:46 1999 +++ linux/drivers/net/mace.c Mon Aug 9 12:04:57 1999 @@ -682,8 +682,10 @@ ++mp->stats.tx_carrier_errors; if (fs & (UFLO|LCOL|RTRY)) ++mp->stats.tx_aborted_errors; - } else + } else { + mp->stats.tx_bytes += mp->tx_bufs[i]->len; ++mp->stats.tx_packets; + } dev_kfree_skb(mp->tx_bufs[i]); --mp->tx_active; if (++i >= N_TX_RING) @@ -848,6 +850,7 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); mp->rx_bufs[i] = 0; + mp->stats.rx_bytes += skb->len; ++mp->stats.rx_packets; } } else { diff -u --recursive --new-file v2.2.10/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.2.10/linux/drivers/net/ne2k-pci.c Sun Jan 24 22:04:02 1999 +++ linux/drivers/net/ne2k-pci.c Mon Aug 9 12:04:39 1999 @@ -24,11 +24,8 @@ /* Our copyright info must remain in the binary. */ static const char *version = -"ne2k-pci.c:v0.99L 2/7/98 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n"; +"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n"; -#ifdef MODVERSIONS -#include -#endif #include #include #include @@ -44,6 +41,13 @@ #include #include "8390.h" +#if defined(__powerpc__) +#define inl_le(addr) le32_to_cpu(inl(addr)) +#define inw_le(addr) le16_to_cpu(inw(addr)) +#define insl insl_ns +#define outsl outsl_ns +#endif + /* Set statically or when loading the driver module. */ static int debug = 1; @@ -58,19 +62,34 @@ /* Do we have a non std. amount of memory? (in units of 256 byte pages) */ /* #define PACKETBUF_MEMSIZE 0x40 */ +#define ne2k_flags reg0 /* Rename an existing field to store flags! */ + +/* Only the low 8 bits are usable for non-init-time flags! */ +enum { + HOLTEK_FDX=1, /* Full duplex -> set 0x80 at offset 0x20. */ + ONLY_16BIT_IO=2, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */ + STOP_PG_0x60=0x100, +}; + +/* This will eventually be converted to the standard PCI probe table. */ + static struct { unsigned short vendor, dev_id; char *name; + int flags; } pci_clone_list[] __initdata = { - {0x10ec, 0x8029, "RealTek RTL-8029"}, - {0x1050, 0x0940, "Winbond 89C940"}, - {0x11f6, 0x1401, "Compex RL2000"}, - {0x8e2e, 0x3000, "KTI ET32P2"}, - {0x4a14, 0x5000, "NetVin NV5000SC"}, - {0x1106, 0x0926, "Via 82C926"}, - {0x10bd, 0x0e34, "SureCom NE34"}, - {0x1050, 0x5a5a, "Winbond"}, + {0x10ec, 0x8029, "RealTek RTL-8029", 0}, + {0x1050, 0x0940, "Winbond 89C940", 0}, + {0x11f6, 0x1401, "Compex RL2000", 0}, + {0x8e2e, 0x3000, "KTI ET32P2", 0}, + {0x4a14, 0x5000, "NetVin NV5000SC", 0}, + {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO}, + {0x10bd, 0x0e34, "SureCom NE34", 0}, + {0x1050, 0x5a5a, "Winbond", 0}, + {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, + {0x12c3, 0x5598, "Holtek HT80229", + ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, {0,} }; @@ -86,7 +105,8 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ int ne2k_pci_probe(struct device *dev); -static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq); +static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, + int chip_idx); static int ne2k_pci_open(struct device *dev); static int ne2k_pci_close(struct device *dev); @@ -115,17 +135,13 @@ int init_module(void) { - int retval; - /* We must emit version information. */ if (debug) printk(KERN_INFO "%s", version); - retval = ne2k_pci_probe(0); - - if (retval) { - printk(KERN_NOTICE "ne2k-pci.c: no (useable) cards found, driver NOT installed.\n"); - return retval; + if (ne2k_pci_probe(0)) { + printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n"); + return -ENODEV; } lock_8390_module(); return 0; @@ -225,7 +241,7 @@ printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n", pci_clone_list[i].name, pci_ioaddr, pci_irq_line); - dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line); + dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i); if (dev == 0) { /* Should not happen. */ printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n", @@ -247,11 +263,11 @@ return cards_found ? 0 : -ENODEV; } -__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq)) +__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, int ioaddr, int irq, + int chip_idx)) { int i; unsigned char SA_prom[32]; - const char *name = NULL; int start_page, stop_page; int reg0 = inb(ioaddr); @@ -273,6 +289,8 @@ } } + dev = init_etherdev(dev, 0); + /* Reset card. Who knows what dain-bramaged state it was left in. */ { unsigned long reset_start_time = jiffies; @@ -321,59 +339,47 @@ } -#ifdef notdef - /* Some broken PCI cards don't respect the byte-wide - request in program_seq above, and hence don't have doubled up values. - */ - for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { - SA_prom[i] = inb(ioaddr + NE_DATAPORT); - SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); - if (SA_prom[i] != SA_prom[i+1]) - sa_prom_doubled = 0; - } - - if (sa_prom_doubled) - for (i = 0; i < 16; i++) - SA_prom[i] = SA_prom[i+i]; -#else - for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++) - SA_prom[i] = inb(ioaddr + NE_DATAPORT); + /* Note: all PCI cards have at least 16 bit access, so we don't have + to check for 8 bit cards. Most cards permit 32 bit access. */ -#endif + if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) { + for (i = 0; i < 4 ; i++) + ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT)); + } else + for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++) + SA_prom[i] = inb(ioaddr + NE_DATAPORT); /* We always set the 8390 registers for word mode. */ outb(0x49, ioaddr + EN0_DCFG); start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; - /* Set up the rest of the parameters. */ - name = "PCI NE2000"; - - dev = init_etherdev(dev, 0); + stop_page = + pci_clone_list[chip_idx].flags&STOP_PG_0x60 ? 0x60 : NESM_STOP_PG; + /* Set up the rest of the parameters. */ dev->irq = irq; dev->base_addr = ioaddr; /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { printk ("%s: unable to get memory for dev->priv.\n", dev->name); - kfree(dev); return 0; } request_region(ioaddr, NE_IO_EXTENT, dev->name); printk("%s: %s found at %#x, IRQ %d, ", - dev->name, name, ioaddr, dev->irq); + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); for(i = 0; i < 6; i++) { printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); dev->dev_addr[i] = SA_prom[i]; } - ei_status.name = name; + ei_status.name = pci_clone_list[chip_idx].name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; ei_status.word16 = 1; + ei_status.ne2k_flags = pci_clone_list[chip_idx].flags; ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE @@ -447,9 +453,9 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + "[DMAstat:%d][irqlock:%d][intr:%d].\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } @@ -461,11 +467,12 @@ outb(ring_page, nic_base + EN0_RSARHI); outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - *(u32*)hdr = inl(NE_BASE + NE_DATAPORT); -#else - insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); -#endif + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); + } else { + *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT)); + le16_to_cpus(&hdr->count); + } outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; @@ -485,12 +492,14 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_input " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + "[DMAstat:%d][irqlock:%d][intr:%d].\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } ei_status.dmaing |= 0x01; + if (ei_status.ne2k_flags & ONLY_32BIT_IO) + count = (count + 3) & 0xFFFC; outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); outb(count & 0xff, nic_base + EN0_RCNTLO); outb(count >> 8, nic_base + EN0_RCNTHI); @@ -498,21 +507,21 @@ outb(ring_offset >> 8, nic_base + EN0_RSARHI); outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - insl(NE_BASE + NE_DATAPORT, buf, count>>2); - if (count & 3) { - buf += count & ~3; - if (count & 2) - *((u16*)buf)++ = inw(NE_BASE + NE_DATAPORT); - if (count & 1) - *buf = inb(NE_BASE + NE_DATAPORT); - } -#else - insw(NE_BASE + NE_DATAPORT,buf,count>>1); - if (count & 0x01) { - buf[count-1] = inb(NE_BASE + NE_DATAPORT); + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + insw(NE_BASE + NE_DATAPORT,buf,count>>1); + if (count & 0x01) { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); + } + } else { + insl(NE_BASE + NE_DATAPORT, buf, count>>2); + if (count & 3) { + buf += count & ~3; + if (count & 2) + *((u16*)buf)++ = le16_to_cpu(inw(NE_BASE + NE_DATAPORT)); + if (count & 1) + *buf = inb(NE_BASE + NE_DATAPORT); + } } -#endif outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; @@ -527,15 +536,18 @@ /* On little-endian it's always safe to round the count up for word writes. */ - if (count & 0x01) - count++; + if (ei_status.ne2k_flags & ONLY_32BIT_IO) + count = (count + 3) & 0xFFFC; + else + if (count & 0x01) + count++; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_output." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", + "[DMAstat:%d][irqlock:%d][intr:%d]\n", dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + (int)dev->interrupt); return; } ei_status.dmaing |= 0x01; @@ -561,16 +573,16 @@ outb(0x00, nic_base + EN0_RSARLO); outb(start_page, nic_base + EN0_RSARHI); outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD); -#if defined(USE_LONGIO) - outsl(NE_BASE + NE_DATAPORT, buf, count>>2); - if (count & 3) { - buf += count & ~3; - if (count & 2) - outw(*((u16*)buf)++, NE_BASE + NE_DATAPORT); + if (ei_status.ne2k_flags & ONLY_16BIT_IO) { + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); + } else { + outsl(NE_BASE + NE_DATAPORT, buf, count>>2); + if (count & 3) { + buf += count & ~3; + if (count & 2) + outw(cpu_to_le16(*((u16*)buf)++), NE_BASE + NE_DATAPORT); + } } -#else - outsw(NE_BASE + NE_DATAPORT, buf, count>>1); -#endif dma_start = jiffies; diff -u --recursive --new-file v2.2.10/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.2.10/linux/drivers/net/net_init.c Sat Apr 24 17:51:48 1999 +++ linux/drivers/net/net_init.c Mon Aug 9 12:04:39 1999 @@ -107,6 +107,8 @@ alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); @@ -225,6 +227,8 @@ alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); @@ -551,6 +555,8 @@ alloc_size &= ~3; /* Round to dword boundary. */ dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + if(dev==NULL) + return NULL; memset(dev, 0, alloc_size); if (sizeof_priv) dev->priv = (void *) (dev + 1); diff -u --recursive --new-file v2.2.10/linux/drivers/net/olympic.c linux/drivers/net/olympic.c --- v2.2.10/linux/drivers/net/olympic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/olympic.c Mon Aug 9 12:04:39 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 --recursive --new-file v2.2.10/linux/drivers/net/olympic.h linux/drivers/net/olympic.h --- v2.2.10/linux/drivers/net/olympic.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/olympic.h Mon Aug 9 12:04:39 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 --recursive --new-file v2.2.10/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.2.10/linux/drivers/net/pcnet32.c Sat Apr 24 17:51:48 1999 +++ linux/drivers/net/pcnet32.c Mon Aug 9 12:05:02 1999 @@ -13,7 +13,7 @@ * This driver is for PCnet32 and PCnetPCI based ethercards */ -static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n"; +static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n"; #include #include @@ -149,6 +149,13 @@ * rewritten PCI card detection * added dwio mode to get driver working on some PPC machines * v1.21: added mii selection and mii ioctl + * v1.22: changed pci scanning code to make PPC people happy + * fixed switching to 32bit mode in pcnet32_open() (thanks + * to Michael Richard for noticing this one) + * added sub vendor/device id matching (thanks again to + * Michael Richard ) + * added chip id for 79c973/975 (thanks to Zach Brown ) + * v1.23 fixed small bug, when manual selecting MII speed/duplex */ @@ -185,6 +192,16 @@ #define PCNET32_TOTAL_SIZE 0x20 +/* some PCI ids */ +#ifndef PCI_DEVICE_ID_AMD_LANCE +#define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#endif +#ifndef PCI_DEVICE_ID_AMD_PCNETHOME +#define PCI_DEVICE_ID_AMD_PCNETHOME 0x2001 +#endif + + #define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ /* The PCNET32 Rx and Tx ring descriptors. */ @@ -272,14 +289,19 @@ struct pcnet32_pci_id_info { const char *name; - u16 vendor_id, device_id, device_id_mask, flags; + u16 vendor_id, device_id, svid, sdid, flags; int io_size; int (*probe1) (struct device *, unsigned long, unsigned char, int, int); }; static struct pcnet32_pci_id_info pcnet32_tbl[] = { { "AMD PCnetPCI series", - 0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0, + PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + pcnet32_probe1}, + { "AMD PCnetHome series", + PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0, + PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, pcnet32_probe1}, {0,} }; @@ -418,30 +440,27 @@ #if defined(CONFIG_PCI) if (pci_present()) { - struct pci_dev *pdev; - unsigned char pci_bus, pci_device_fn; - int pci_index; + struct pci_dev *pdev = NULL; printk("pcnet32.c: PCI bios is present, checking for devices...\n"); - for (pci_index = 0; pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command; + while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) { + u16 pci_command; int chip_idx; + u16 sdid,svid; - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, - pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) - break; - - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); - + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid); for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pcnet32_tbl[chip_idx].vendor_id && - (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id) + if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) && + (pdev->device == pcnet32_tbl[chip_idx].device_id) && + (pcnet32_tbl[chip_idx].svid == 0 || + (svid == pcnet32_tbl[chip_idx].svid)) && + (pcnet32_tbl[chip_idx].sdid == 0 || + (sdid == pcnet32_tbl[chip_idx].sdid))) break; if (pcnet32_tbl[chip_idx].vendor_id == 0) continue; - pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; #if defined(ADDR_64BITS) && defined(__alpha__) ioaddr |= ((long)pdev->base_address[1]) << 32; @@ -541,6 +560,10 @@ chipname = "PCnet/FAST+ 79C972"; fdx = 1; mii = 1; break; + case 0x2625: + chipname = "PCnet/FAST III 79C973"; + fdx = 1; mii = 1; + break; case 0x2626: chipname = "PCnet/Home 79C978"; fdx = 1; @@ -561,6 +584,9 @@ printk("pcnet32: pcnet32 media reset to %#x.\n", media); a->write_bcr (ioaddr, 49, media); break; + case 0x2627: + chipname = "PCnet/FAST III 79C975"; + fdx = 1; mii = 1; default: printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); return ENODEV; @@ -693,7 +719,7 @@ lp->a.reset (ioaddr); /* switch pcnet32 to 32bit mode */ - lp->a.write_csr (ioaddr, 20, 2); + lp->a.write_bcr (ioaddr, 20, 2); if (pcnet32_debug > 1) printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", @@ -725,7 +751,7 @@ val |= 0x10; lp->a.write_csr (ioaddr, 124, val); - if (lp->mii & (lp->options & PORT_ASEL)) { + if (lp->mii & !(lp->options & PORT_ASEL)) { val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */ if (lp->options & PORT_FD) val |= 0x10; @@ -952,7 +978,7 @@ struct device *dev = (struct device *)dev_id; struct pcnet32_private *lp; unsigned long ioaddr; - u16 csr0; + u16 csr0,rap; int boguscnt = max_interrupt_work; int must_restart; @@ -968,6 +994,7 @@ dev->interrupt = 1; + rap = lp->a.read_rap(ioaddr); while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP. */ lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); @@ -1069,6 +1096,7 @@ /* Clear any other interrupt, and set interrupt enable. */ lp->a.write_csr (ioaddr, 0, 0x7940); + lp->a.write_rap(ioaddr,rap); if (pcnet32_debug > 4) printk("%s: exiting interrupt, csr0=%#4.4x.\n", diff -u --recursive --new-file v2.2.10/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.2.10/linux/drivers/net/rtl8139.c Sun Nov 22 09:47:52 1998 +++ linux/drivers/net/rtl8139.c Mon Aug 9 12:04:39 1999 @@ -1,6 +1,6 @@ /* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */ /* - Written 1997-1998 by Donald Becker. + Written 1997-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -16,11 +16,11 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html - Twister-tuning code contributed by Kinston . + Twister-tuning table provided by Kinston . */ static const char *version = -"rtl8139.c:v1.04 9/22/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; +"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; /* A few user-configurable values. */ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ @@ -178,7 +178,9 @@ 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, { "RealTek RTL8139 Fast Ethernet", 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "RealTek RTL8139 Fast Ethernet (mislabeled)", + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", + 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, + { "Accton MPX5030 (RealTek RTL8139)", 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, {0,}, /* 0 terminated list. */ }; @@ -235,13 +237,13 @@ RxBadAlign=0x0002, RxStatusOK=0x0001, }; +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links. */ enum CSCRBits { CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, CSCR_LinkDownCmd=0x0f3c0, -}; - -/* Twister tuning parameters from RealTek. Completely undocumented. */ +}; unsigned long param[4][4]={ {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, @@ -270,9 +272,10 @@ unsigned char *rx_ring; unsigned char *tx_bufs; /* Tx bounce buffer region. */ char phys[4]; /* MII device addresses. */ + char twistie, twist_cnt; /* Twister tune state. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ @@ -325,7 +328,7 @@ if ( ! pcibios_present()) return -ENODEV; - for (;pci_index < 0xff; pci_index++) { + for (; pci_index < 0xff; pci_index++) { u16 vendor, device, pci_command, new_command; int chip_idx, irq; long ioaddr; @@ -402,9 +405,9 @@ return cards_found ? 0 : -ENODEV; } -static struct device * rtl8129_probe1(int pci_bus, int pci_devfn, - struct device *dev, long ioaddr, - int irq, int chip_idx, int found_cnt) +static struct device *rtl8129_probe1(int pci_bus, int pci_devfn, + struct device *dev, long ioaddr, + int irq, int chip_idx, int found_cnt) { static int did_version = 0; /* Already printed version info. */ struct rtl8129_private *tp; @@ -470,9 +473,8 @@ dev->name); tp->phys[0] = -1; } - } else { - tp->phys[0] = 32; - } + } else + tp->phys[0] = 32; /* Put the chip into low-power mode. */ outb(0xC0, ioaddr + Cfg9346); @@ -601,7 +603,7 @@ int retval = 0; int i; - if ((phy_id & 0x1f) == 0) { /* Really a 8139. Use internal registers. */ + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ return location < 8 && mii_2_8139_map[location] ? inw(dev->base_addr + mii_2_8139_map[location]) : 0; } @@ -633,7 +635,7 @@ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; - if (phy_id == 32) { /* Really a 8139. Use internal registers. */ + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ if (location < 8 && mii_2_8139_map[location]) outw(value, dev->base_addr + mii_2_8139_map[location]); return; @@ -678,6 +680,7 @@ tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { + free_irq(dev->irq, dev); if (tp->tx_bufs) kfree(tp->tx_bufs); if (rtl8129_debug > 0) @@ -736,7 +739,7 @@ /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); + | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); if (rtl8129_debug > 1) printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" @@ -749,7 +752,7 @@ init_timer(&tp->timer); tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ tp->timer.data = (unsigned long)dev; - tp->timer.function = &rtl8129_timer; /* timer handler */ + tp->timer.function = &rtl8129_timer; add_timer(&tp->timer); return 0; @@ -760,7 +763,7 @@ struct device *dev = (struct device *)data; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - int next_tick = 0; + int next_tick = 60*HZ; int mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (! tp->duplex_lock && mii_reg5 != 0xffff) { @@ -774,8 +777,65 @@ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, ioaddr + Cfg9346); } - next_tick = 60*HZ; } + /* Check for bogusness. */ + if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { + int status = inw(ioaddr + IntrStatus); + if (status & (TxOK | RxOK)) { /* Double check */ + printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n", + dev->name, status); + rtl8129_interrupt(dev->irq, dev, 0); + } + } + if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT) + rtl8129_tx_timeout(dev); + +#if 0 + if (tp->twistie) { + unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ + if (tp->twistie == 1) { + if (CSCRval & CSCR_LinkOKBit) { + outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); + tp->twistie = 2; + next_tick = HZ/10; + } else { + outw(CSCR_LinkDownCmd, ioaddr + CSCR); + outl(FIFOTMS_default,ioaddr + FIFOTMS); + outl(PARA78_default ,ioaddr + PARA78); + outl(PARA7c_default ,ioaddr + PARA7c); + tp->twistie = 0; + } + } else if (tp->twistie == 2) { + int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; + int row; + if (linkcase >= 0x7000) row = 3; + else if (linkcase >= 0x3000) row = 2; + else if (linkcase >= 0x1000) row = 1; + else row = 0; + tp->twistie == row + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[row][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } else { + outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); + if (++tp->twist_cnt < 4) { + next_tick = HZ/10; + } else if (tp->twistie-3 == 3) { + if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { + outl(PARA7c_xxx, ioaddr+PARA7c); + next_tick = HZ/10; /* 100ms. */ + outl(FIFOTMS_default, ioaddr+FIFOTMS); + outl(PARA78_default, ioaddr+PARA78); + outl(PARA7c_default, ioaddr+PARA7c); + tp->twistie == 3 + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[3][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } + } + } + } +#endif if (rtl8129_debug > 2) { if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) @@ -792,10 +852,8 @@ dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); } static void rtl8129_tx_timeout(struct device *dev) @@ -861,7 +919,7 @@ } tp->cur_tx = i; while (i < NUM_TX_DESC) - tp->tx_skbuff[i] = 0; + tp->tx_skbuff[i++] = 0; if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ dev->tbusy = 0; tp->tx_full = 0; @@ -906,9 +964,8 @@ /* 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) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - rtl8129_tx_timeout(dev); + if (jiffies - dev->trans_start >= TX_TIMEOUT) + rtl8129_tx_timeout(dev); return 1; } @@ -925,7 +982,7 @@ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + entry*4); - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ clear_bit(0, (void*)&dev->tbusy); } else { tp->tx_full = 1; @@ -946,7 +1003,7 @@ struct device *dev = (struct device *)dev_instance; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int boguscnt = max_interrupt_work; - int status; + int status, link_changed = 0; long ioaddr = dev->base_addr; #if defined(__i386__) @@ -967,7 +1024,10 @@ do { status = inw(ioaddr + IntrStatus); - /* Acknowledge all of the current interrupt sources ASAP. */ + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) + link_changed = 1; outw(status, ioaddr + IntrStatus); if (rtl8129_debug > 4) @@ -982,9 +1042,9 @@ rtl8129_rx(dev); if (status & (TxOK | TxErr)) { - unsigned int dirty_tx; + unsigned int dirty_tx = tp->dirty_tx; - for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) { + while (tp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus = inl(ioaddr + TxStatus0 + entry*4); @@ -994,11 +1054,9 @@ /* Note: TxCarrierLost is always asserted at 100mbps. */ if (txstatus & (TxOutOfWindow | TxAborted)) { /* There was an major error, log it. */ -#ifndef final_version if (rtl8129_debug > 1) printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); -#endif tp->stats.tx_errors++; if (txstatus&TxAborted) { tp->stats.tx_aborted_errors++; @@ -1011,9 +1069,6 @@ tp->stats.collisions16++; #endif } else { -#ifdef ETHER_STATS - /* No count for tp->stats.tx_deferred */ -#endif if (txstatus & TxUnderrun) { /* Add 64 to the Tx FIFO threshold. */ if (tp->tx_flag < 0x00300000) @@ -1030,6 +1085,13 @@ /* Free the original skb. */ dev_free_skb(tp->tx_skbuff[entry]); tp->tx_skbuff[entry] = 0; + if (tp->tx_full) { + /* The ring is no longer full, clear tbusy. */ + tp->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } + dirty_tx++; } #ifndef final_version @@ -1039,14 +1101,6 @@ dirty_tx += NUM_TX_DESC; } #endif - - if (tp->tx_full && dirty_tx > tp->cur_tx - NUM_TX_DESC) { - /* The ring is no longer full, clear tbusy. */ - tp->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - } - tp->dirty_tx = dirty_tx; } @@ -1063,7 +1117,7 @@ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); - if ((status & RxUnderrun) && + if ((status & RxUnderrun) && link_changed && (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { /* Really link-change on new chips. */ int lpar = inw(ioaddr + NWayLPAR); @@ -1284,12 +1338,12 @@ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0], data[1] & 0x1f); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; @@ -1318,7 +1372,7 @@ { int crc = -1; - while(--length >= 0) { + while (--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) diff -u --recursive --new-file v2.2.10/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c --- v2.2.10/linux/drivers/net/sb1000.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sb1000.c Mon Aug 9 12:05:10 1999 @@ -0,0 +1,1294 @@ +/* sb1000.c: A General Instruments SB1000 driver for linux. */ +/* + Written 1998 by Franco Venturi. + + Copyright 1998 by Franco Venturi. + Copyright 1994,1995 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This driver is for the General Instruments SB1000 (internal SURFboard) + + The author may be reached as fventuri@mediaone.net + + 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. + + Changes: + + 981115 Steven Hirsch + + Linus changed the timer interface. Should work on all recent + development kernels. + + 980608 Steven Hirsch + + Small changes to make it work with 2.1.x kernels. Hopefully, + nothing major will change before official release of Linux 2.2. + + Merged with 2.2 - Alan Cox +*/ + +static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for udelay() */ +#include + +#include +#include +#include +#include + +/* for SIOGCM/SIOSCM stuff */ +#include + +#ifdef SB1000_DEBUG +int sb1000_debug = SB1000_DEBUG; +#else +int sb1000_debug = 1; +#endif + +static const int SB1000_IO_EXTENT = 8; +/* SB1000 Maximum Receive Unit */ +static const int SB1000_MRU = 1500; /* octects */ + +#define NPIDS 4 +struct sb1000_private { + struct sk_buff *rx_skb[NPIDS]; + short rx_dlen[NPIDS]; + unsigned int rx_bytes; + unsigned int rx_frames; + short rx_error_count; + short rx_error_dpc_count; + unsigned char rx_session_id[NPIDS]; + unsigned char rx_frame_id[NPIDS]; + unsigned char rx_pkt_type[NPIDS]; + struct net_device_stats stats; +}; + +/* prototypes for Linux interface */ +extern int sb1000_probe(struct device *dev); +static int sb1000_open(struct device *dev); +static int sb1000_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd); +static int sb1000_start_xmit(struct sk_buff *skb, struct device *dev); +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct enet_statistics *sb1000_stats(struct device *dev); +static int sb1000_close(struct device *dev); + +/* Plug-n-Play routine */ +static inline unsigned char read_resource_data(void); + +/* SB1000 hardware routines to be used during open/configuration phases */ +static inline void nicedelay(unsigned long usecs); +static inline int card_wait_for_busy_clear(const int ioaddr[], + const char* name); +static inline int card_wait_for_ready(const int ioaddr[], const char* name, + unsigned char in[]); +static inline int card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]); + +/* SB1000 hardware routines to be used during frame rx interrupt */ +static inline int sb1000_wait_for_ready(const int ioaddr[], const char* name); +static inline int sb1000_wait_for_ready_clear(const int ioaddr[], + const char* name); +static inline void sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]); +static inline void sb1000_read_status(const int ioaddr[], unsigned char in[]); +static inline void sb1000_issue_read_command(const int ioaddr[], + const char* name); + +/* SB1000 commands for open/configuration */ +static inline int sb1000_reset(const int ioaddr[], const char* name); +static inline int sb1000_check_CRC(const int ioaddr[], const char* name); +static inline int sb1000_start_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_end_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_activate(const int ioaddr[], const char* name); +static inline int sb1000_get_firmware_version(const int ioaddr[], + const char* name, unsigned char version[], int do_end); +static inline int sb1000_get_frequency(const int ioaddr[], const char* name, + int* frequency); +static inline int sb1000_set_frequency(const int ioaddr[], const char* name, + int frequency); +static inline int sb1000_get_PIDs(const int ioaddr[], const char* name, + short PID[]); +static inline int sb1000_set_PIDs(const int ioaddr[], const char* name, + const short PID[]); + +/* SB1000 commands for frame rx interrupt */ +static inline int sb1000_rx(struct device *dev); +static inline void sb1000_error_dpc(struct device *dev); + + +/* Plug-n-Play constants */ +static const int READ_DATA_PORT = 0x203; /* This port number may change!!! */ +static const int ADDRESS_PORT = 0x279; +static const int WRITE_DATA_PORT = 0xa79; + +/* Plug-n-Play read resource mechanism */ +static inline unsigned char +read_resource_data(void) { + /* poll */ + outb(0x05, ADDRESS_PORT); /* Select PnP status register. */ + while (!(inb(READ_DATA_PORT) & 0x1)) ; + /* read resource data */ + outb(0x04, ADDRESS_PORT); /* Select PnP resource data register. */ + return inb(READ_DATA_PORT); +} + +/* probe for SB1000 using Plug-n-Play mechanism */ +int +sb1000_probe(struct device *dev) +{ + + unsigned short ioaddr[2], irq; + short i, csn; + unsigned int serial_number; + + const unsigned char initiation_key[] = { 0x00, 0x00, 0x6a, 0xb5, 0xda, + 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, + 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, + 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; + const unsigned char sb1000_vendor_ID[] = { + 0x1d, 0x23, 0x10, 0x00 }; /* "GIC1000" */ + + /* Reset the ISA PnP mechanism */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* send initiation key */ + for (i = 0; i < sizeof(initiation_key) / sizeof(initiation_key[0]); i++) { + outb(initiation_key[i], ADDRESS_PORT); + } + + /* set card CSN into configuration mode */ + for (csn = 1; csn <= 255; csn++) { + outb(0x03, ADDRESS_PORT); /* Select PnP wake[CSN] register. */ + outb(csn, WRITE_DATA_PORT); /* Wake[CSN] */ + /* check card ID */ + for (i = 0; i < 4; i++) { + if (read_resource_data() != sb1000_vendor_ID[i]) break; + } + if (i == 4) break; + } + + /* SB1000 not found */ + if (csn > 255) { + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT);/* Return to WaitForKey state. */ + return -ENODEV; + } + + /* found: get serial number and skip checksum */ + serial_number = 0; + for (i = 0; i < 4; i++) { + serial_number |= read_resource_data() << (8 * i); + } + read_resource_data(); + + /* get I/O port base address */ + outb(0x60, ADDRESS_PORT); /* Select PnP I/O port base address 0. */ + ioaddr[0] = inb(READ_DATA_PORT) << 8; + outb(0x61, ADDRESS_PORT); + ioaddr[0] |= inb(READ_DATA_PORT); + outb(0x62, ADDRESS_PORT); /* Select PnP I/O port base address 1. */ + ioaddr[1] = inb(READ_DATA_PORT) << 8; + outb(0x63, ADDRESS_PORT); + ioaddr[1] |= inb(READ_DATA_PORT); + + /* get IRQ */ + outb(0x70, ADDRESS_PORT); /* Select PnP IRQ level select 0. */ + irq = inb(READ_DATA_PORT); + + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* check I/O base and IRQ */ + if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) { + return -ENODEV; + } + if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) { + return -ENODEV; + } + if (dev->irq != 0 && dev->irq != irq) { + return -ENODEV; + } + + dev->base_addr = ioaddr[0]; + /* rmem_end holds the second I/O address - fv */ + dev->rmem_end = ioaddr[1]; + dev->irq = irq; + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), csn %d, " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->rmem_end, csn, serial_number, dev->irq); + + dev = init_etherdev(dev, 0); + + /* Make up a SB1000-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct sb1000_private)); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* Fill in the generic fields of the device structure. */ + dev->change_mtu = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->header_cache_update= NULL; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = 0; + dev->mtu = 0; + dev->addr_len = ETH_ALEN; + /* hardware address is 0:0:serial_number */ + dev->dev_addr[0] = 0; + dev->dev_addr[1] = 0; + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + dev->tx_queue_len = 0; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; + return 0; +} + + +/* + * SB1000 hardware routines to be used during open/configuration phases + */ +const int TimeOutJiffies = (int)(8.75 * HZ); + +static inline void nicedelay(unsigned long usecs) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + return; +} + +/* Card Wait For Busy Clear (cannot be used during an interrupt) */ +static inline int +card_wait_for_busy_clear(const int ioaddr[], const char* name) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[0] + 7); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || a & 0x40) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[0] + 7); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_busy_clear timeout\n", + name); + return -ETIME; + } + } + + return 0; +} + +/* Card Wait For Ready (cannot be used during an interrupt) */ +static inline int +card_wait_for_ready(const int ioaddr[], const char* name, unsigned char in[]) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[1] + 6); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || !(a & 0x40)) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[1] + 6); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + in[6] = inb(ioaddr[0] + 6); + in[5] = inb(ioaddr[1] + 6); + return 0; +} + +/* Card Send Command (cannot be used during an interrupt) */ +static inline int +card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]) +{ + int status, x; + + if ((status = card_wait_for_busy_clear(ioaddr, name))) + return status; + outb(0xa0, ioaddr[0] + 6); + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(0xa0, ioaddr[0] + 6); + outb(out[0], ioaddr[0] + 7); + if (out[0] != 0x20 && out[0] != 0x30) { + if ((status = card_wait_for_ready(ioaddr, name, in))) + return status; + inb(ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x " + "in: %02x%02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5], + in[0], in[1], in[2], in[3], in[4], in[5], in[6]); + } else { + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5]); + } + + if (out[1] == 0x1b) { + x = (out[2] == 0x02); + } else { + if (out[0] >= 0x80 && in[0] != (out[1] | 0x80)) + return -EIO; + } + return 0; +} + + +/* + * SB1000 hardware routines to be used during frame rx interrupt + */ +const int Sb1000TimeOutJiffies = 7 * HZ; + +/* Card Wait For Ready (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (!(inb(ioaddr[1] + 6) & 0x40)) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + inb(ioaddr[0] + 7); + return 0; +} + +/* Card Wait For Ready Clear (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready_clear(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x40) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + return 0; +} + +/* Card Send Command (to be used during frame rx) */ +static inline void +sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]) +{ + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(out[0], ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: sb1000_send_command out: %02x%02x%02x%02x" + "%02x%02x\n", name, out[0], out[1], out[2], out[3], out[4], out[5]); + return; +} + +/* Card Read Status (to be used during frame rx) */ +static inline void +sb1000_read_status(const int ioaddr[], unsigned char in[]) +{ + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + return; +} + +/* Issue Read Command (to be used during frame rx) */ +static inline void +sb1000_issue_read_command(const int ioaddr[], const char* name) +{ + const unsigned char Command0[6] = {0x20, 0x00, 0x00, 0x01, 0x00, 0x00}; + + sb1000_wait_for_ready_clear(ioaddr, name); + outb(0xa0, ioaddr[0] + 6); + sb1000_send_command(ioaddr, name, Command0); + return; +} + + +/* + * SB1000 commands for open/configuration + */ +/* reset SB1000 card */ +static inline int +sb1000_reset(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int port, status; + const unsigned char Command0[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + port = ioaddr[1] + 6; + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + nicedelay(60000); + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + udelay(0); + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[3] != 0xf0) + return -EIO; + return 0; +} + +/* check SB1000 firmware CRC */ +static inline int +sb1000_check_CRC(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int crc, status; + const unsigned char Command0[6] = {0x80, 0x1f, 0x00, 0x00, 0x00, 0x00}; + + /* check CRC */ + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[1] != st[3] || st[2] != st[4]) + return -EIO; + crc = st[1] << 8 | st[2]; + return 0; +} + +static inline int +sb1000_start_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + const unsigned char Command0[6] = {0x80, 0x1b, 0x00, 0x00, 0x00, 0x00}; + + return card_send_command(ioaddr, name, Command0, st); +} + +static inline int +sb1000_end_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x1b, 0x02, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + return card_send_command(ioaddr, name, Command1, st); +} + +static inline int +sb1000_activate(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + nicedelay(50000); + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + if (st[3] != 0xf1) { + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + return -EIO; + } + udelay(1000); + return sb1000_start_get_set_command(ioaddr, name); +} + +/* get SB1000 firmware version */ +static inline int +sb1000_get_firmware_version(const int ioaddr[], const char* name, + unsigned char version[], int do_end) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x23, 0x00, 0x00, 0x00, 0x00}; + + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[0] != 0xa3) + return -EIO; + version[0] = st[1]; + version[1] = st[2]; + if (do_end) + return sb1000_end_get_set_command(ioaddr, name); + else + return 0; +} + +/* get SB1000 frequency */ +static inline int +sb1000_get_frequency(const int ioaddr[], const char* name, int* frequency) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x44, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + *frequency = ((st[1] << 8 | st[2]) << 8 | st[3]) << 8 | st[4]; + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 frequency */ +static inline int +sb1000_set_frequency(const int ioaddr[], const char* name, int frequency) +{ + unsigned char st[7]; + int status; + unsigned char Command0[6] = {0x80, 0x29, 0x00, 0x00, 0x00, 0x00}; + + const int FrequencyLowerLimit = 57000; + const int FrequencyUpperLimit = 804000; + + if (frequency < FrequencyLowerLimit || frequency > FrequencyUpperLimit) { + printk(KERN_ERR "%s: frequency chosen (%d kHz) is not in the range " + "[%d,%d] kHz\n", name, frequency, FrequencyLowerLimit, + FrequencyUpperLimit); + return -EINVAL; + } + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + Command0[5] = frequency & 0xff; + frequency >>= 8; + Command0[4] = frequency & 0xff; + frequency >>= 8; + Command0[3] = frequency & 0xff; + frequency >>= 8; + Command0[2] = frequency & 0xff; + return card_send_command(ioaddr, name, Command0, st); +} + +/* get SB1000 PIDs */ +static inline int +sb1000_get_PIDs(const int ioaddr[], const char* name, short PID[]) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x40, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x41, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command2[6] = {0x80, 0x42, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command3[6] = {0x80, 0x43, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + PID[0] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + PID[1] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + PID[2] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + PID[3] = st[1] << 8 | st[2]; + + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 PIDs */ +static inline int +sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[]) +{ + unsigned char st[7]; + short p; + int status; + unsigned char Command0[6] = {0x80, 0x31, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command1[6] = {0x80, 0x32, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command2[6] = {0x80, 0x33, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command3[6] = {0x80, 0x34, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command4[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + p = PID[0]; + Command0[3] = p & 0xff; + p >>= 8; + Command0[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + + p = PID[1]; + Command1[3] = p & 0xff; + p >>= 8; + Command1[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + + p = PID[2]; + Command2[3] = p & 0xff; + p >>= 8; + Command2[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + + p = PID[3]; + Command3[3] = p & 0xff; + p >>= 8; + Command3[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + + if ((status = card_send_command(ioaddr, name, Command4, st))) + return status; + return sb1000_end_get_set_command(ioaddr, name); +} + + +static inline void +sb1000_print_status_buffer(const char* name, unsigned char st[], + unsigned char buffer[], int size) +{ + int i, j, k; + + printk(KERN_DEBUG "%s: status: %02x %02x\n", name, st[0], st[1]); + if (buffer[24] == 0x08 && buffer[25] == 0x00 && buffer[26] == 0x45) { + printk(KERN_DEBUG "%s: length: %d protocol: %d from: %d.%d.%d.%d:%d " + "to %d.%d.%d.%d:%d\n", name, buffer[28] << 8 | buffer[29], + buffer[35], buffer[38], buffer[39], buffer[40], buffer[41], + buffer[46] << 8 | buffer[47], + buffer[42], buffer[43], buffer[44], buffer[45], + buffer[48] << 8 | buffer[49]); + } else { + for (i = 0, k = 0; i < (size + 7) / 8; i++) { + printk(KERN_DEBUG "%s: %s", name, i ? " " : "buffer:"); + for (j = 0; j < 8 && k < size; j++, k++) + printk(" %02x", buffer[k]); + printk("\n"); + } + } + return; +} + +/* + * SB1000 commands for frame rx interrupt + */ +/* receive a single frame and assemble datagram + * (this is the heart of the interrupt routine) + */ +static inline int +sb1000_rx(struct device *dev) +{ + +#define FRAMESIZE 184 + unsigned char st[2], buffer[FRAMESIZE], session_id, frame_id; + short dlen; + int ioaddr, ns; + unsigned int skbsize; + struct sk_buff *skb; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct enet_statistics *stats = &lp->stats; + + /* SB1000 frame constants */ + const int FrameSize = FRAMESIZE; + const int NewDatagramHeaderSkip = 8; + const int NewDatagramHeaderSize = NewDatagramHeaderSkip + 18; + const int NewDatagramDataSize = FrameSize - NewDatagramHeaderSize; + const int ContDatagramHeaderSkip = 7; + const int ContDatagramHeaderSize = ContDatagramHeaderSkip + 1; + const int ContDatagramDataSize = FrameSize - ContDatagramHeaderSize; + const int TrailerSize = 4; + + ioaddr = dev->base_addr; + + insw(ioaddr, (unsigned short*) st, 1); +#ifdef XXXDEBUG +printk("cm0: received: %02x %02x\n", st[0], st[1]); +#endif /* XXXDEBUG */ + lp->rx_frames++; + + /* decide if it is a good or bad frame */ + for (ns = 0; ns < NPIDS; ns++) { + session_id = lp->rx_session_id[ns]; + frame_id = lp->rx_frame_id[ns]; + if (st[0] == session_id) { + if (st[1] == frame_id || (!frame_id && (st[1] & 0xf0) == 0x30)) { + goto good_frame; + } else if ((st[1] & 0xf0) == 0x30 && (st[0] & 0x40)) { + goto skipped_frame; + } else { + goto bad_frame; + } + } else if (st[0] == (session_id | 0x40)) { + if ((st[1] & 0xf0) == 0x30) { + goto skipped_frame; + } else { + goto bad_frame; + } + } + } + goto bad_frame; + +skipped_frame: + stats->rx_frame_errors++; + skb = lp->rx_skb[ns]; + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: missing frame(s): got %02x %02x " + "expecting %02x %02x\n", dev->name, st[0], st[1], + skb ? session_id : session_id | 0x40, frame_id); + if (skb) { + dev_kfree_skb(skb); + skb = 0; + } + +good_frame: + lp->rx_frame_id[ns] = 0x30 | ((st[1] + 1) & 0x0f); + /* new datagram */ + if (st[0] & 0x40) { + /* get data length */ + insw(ioaddr, buffer, NewDatagramHeaderSize / 2); +#ifdef XXXDEBUG +printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[30], buffer[31], buffer[32], buffer[33]); +#endif /* XXXDEBUG */ + if (buffer[0] != NewDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: new datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + NewDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + dlen = ((buffer[NewDatagramHeaderSkip + 3] & 0x0f) << 8 | + buffer[NewDatagramHeaderSkip + 4]) - 17; + if (dlen > SB1000_MRU) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: datagram length (%d) greater " + "than MRU (%d)\n", dev->name, dlen, SB1000_MRU); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + lp->rx_dlen[ns] = dlen; + /* compute size to allocate for datagram */ + skbsize = dlen + FrameSize; + if ((skb = alloc_skb(skbsize, GFP_ATOMIC)) == NULL) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: can't allocate %d bytes long " + "skbuff\n", dev->name, skbsize); + stats->rx_dropped++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto dropped_frame; + } + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16]; + insw(ioaddr, skb_put(skb, NewDatagramDataSize), + NewDatagramDataSize / 2); + lp->rx_skb[ns] = skb; + } else { + /* continuation of previous datagram */ + insw(ioaddr, buffer, ContDatagramHeaderSize / 2); + if (buffer[0] != ContDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: cont datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + ContDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, ContDatagramDataSize / 2); + goto bad_frame_next; + } + skb = lp->rx_skb[ns]; + insw(ioaddr, skb_put(skb, ContDatagramDataSize), + ContDatagramDataSize / 2); + dlen = lp->rx_dlen[ns]; + } + if (skb->len < dlen + TrailerSize) { + lp->rx_session_id[ns] &= ~0x40; + return 0; + } + + /* datagram completed: send to upper level */ + skb_trim(skb, dlen); + netif_rx(skb); + stats->rx_packets++; + lp->rx_bytes += dlen; + lp->rx_skb[ns] = 0; + lp->rx_session_id[ns] |= 0x40; + return 0; + +bad_frame: + insw(ioaddr, buffer, FrameSize / 2); + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: frame error: got %02x %02x\n", + dev->name, st[0], st[1]); + stats->rx_frame_errors++; +bad_frame_next: + if (sb1000_debug > 2) + sb1000_print_status_buffer(dev->name, st, buffer, FrameSize); +dropped_frame: + stats->rx_errors++; + if (ns < NPIDS) { + if ((skb = lp->rx_skb[ns])) { + dev_kfree_skb(skb); + lp->rx_skb[ns] = 0; + } + lp->rx_session_id[ns] |= 0x40; + } + return -1; +} + +static inline void +sb1000_error_dpc(struct device *dev) +{ + char *name; + unsigned char st[5]; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00}; + const int ErrorDpcCounterInitialize = 200; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_read_status(ioaddr, st); + if (st[1] & 0x10) + lp->rx_error_dpc_count = ErrorDpcCounterInitialize; + return; +} + + +/* + * Linux interface functions + */ +static int +sb1000_open(struct device *dev) +{ + char *name; + int ioaddr[2], status; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned short FirmwareVersion[] = {0x01, 0x01}; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + request_region(ioaddr[0], SB1000_IO_EXTENT, "sb1000"); + request_region(ioaddr[1], SB1000_IO_EXTENT, "sb1000"); + + /* initialize sb1000 */ + if ((status = sb1000_reset(ioaddr, name))) + return status; + nicedelay(200000); + if ((status = sb1000_check_CRC(ioaddr, name))) + return status; + + /* initialize private data before board can catch interrupts */ + lp->rx_skb[0] = NULL; + lp->rx_skb[1] = NULL; + lp->rx_skb[2] = NULL; + lp->rx_skb[3] = NULL; + lp->rx_dlen[0] = 0; + lp->rx_dlen[1] = 0; + lp->rx_dlen[2] = 0; + lp->rx_dlen[3] = 0; + lp->rx_bytes = 0; + lp->rx_frames = 0; + lp->rx_error_count = 0; + lp->rx_error_dpc_count = 0; + lp->rx_session_id[0] = 0x50; + lp->rx_session_id[0] = 0x48; + lp->rx_session_id[0] = 0x44; + lp->rx_session_id[0] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + if (request_irq(dev->irq, &sb1000_interrupt, 0, "sb1000", dev)) { + return -EAGAIN; + } + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Opening, IRQ %d\n", name, dev->irq); + + /* Activate board and check firmware version */ + udelay(1000); + if ((status = sb1000_activate(ioaddr, name))) + return status; + udelay(0); + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 0))) + return status; + if (version[0] != FirmwareVersion[0] || version[1] != FirmwareVersion[1]) + printk(KERN_WARNING "%s: found firmware version %x.%02x " + "(should be %x.%02x)\n", name, version[0], version[1], + FirmwareVersion[0], FirmwareVersion[1]); + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + return 0; /* Always succeed */ +} + +static int sb1000_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + char* name; + unsigned char version[2]; + short PID[4]; + int ioaddr[2], status, frequency; + unsigned int stats[5]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (!(dev && dev->flags & IFF_UP)) + return -ENODEV; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + switch (cmd) { + case SIOCGCMSTATS: /* get statistics */ + stats[0] = lp->rx_bytes; + stats[1] = lp->rx_frames; + stats[2] = lp->stats.rx_packets; + stats[3] = lp->stats.rx_errors; + stats[4] = lp->stats.rx_dropped; + if(copy_to_user(ifr->ifr_data, stats, sizeof(stats))) + return -EFAULT; + status = 0; + break; + + case SIOCGCMFIRMWARE: /* get firmware version */ + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 1))) + return status; + if(copy_to_user(ifr->ifr_data, version, sizeof(version))) + return -EFAULT; + break; + + case SIOCGCMFREQUENCY: /* get frequency */ + if ((status = sb1000_get_frequency(ioaddr, name, &frequency))) + return status; + if(put_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + break; + + case SIOCSCMFREQUENCY: /* set frequency */ + if (!suser()) + return -EPERM; + if(get_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + if ((status = sb1000_set_frequency(ioaddr, name, frequency))) + return status; + break; + + case SIOCGCMPIDS: /* get PIDs */ + if ((status = sb1000_get_PIDs(ioaddr, name, PID))) + return status; + if(copy_to_user(ifr->ifr_data, PID, sizeof(PID))) + return -EFAULT; + break; + + case SIOCSCMPIDS: /* set PIDs */ + if (!suser()) + return -EPERM; + if(copy_from_user(PID, ifr->ifr_data, sizeof(PID))) + return -EFAULT; + if ((status = sb1000_set_PIDs(ioaddr, name, PID))) + return status; + /* set session_id, frame_id and pkt_type too */ + lp->rx_session_id[0] = 0x50 | (PID[0] & 0x0f); + lp->rx_session_id[1] = 0x48; + lp->rx_session_id[2] = 0x44; + lp->rx_session_id[3] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + break; + + default: + status = -EINVAL; + break; + } + return status; +} + +/* transmit function: do nothing since SB1000 can't send anything out */ +static int +sb1000_start_xmit(struct sk_buff *skb, struct device *dev) +{ + printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); + /* sb1000 can't xmit datagrams */ + dev_kfree_skb(skb); + return 0; +} + +/* SB1000 interrupt handler. */ +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char *name; + unsigned char st; + int ioaddr[2]; + struct device *dev = (struct device *) dev_id; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + const int MaxRxErrorCount = 6; + + if (dev == NULL) { + printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n", + irq); + return; + } + if (dev->interrupt) + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", + dev->name); + dev->interrupt = 1; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + /* is it a good interrupt? */ + st = inb(ioaddr[1] + 6); + if (!(st & 0x08 && st & 0x20)) { + dev->interrupt = 0; + return; + } + + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: entering interrupt\n", dev->name); + + st = inb(ioaddr[0] + 7); + if (sb1000_rx(dev)) + lp->rx_error_count++; +#ifdef SB1000_DELAY + udelay(SB1000_DELAY); +#endif /* SB1000_DELAY */ + sb1000_issue_read_command(ioaddr, name); + if (st & 0x01) { + sb1000_error_dpc(dev); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_dpc_count && !(--lp->rx_error_dpc_count)) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_count >= MaxRxErrorCount) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command1); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + lp->rx_error_count = 0; + } + + dev->interrupt = 0; + return; +} + +static struct net_device_stats *sb1000_stats(struct device *dev) +{ + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + return &lp->stats; +} + +static int sb1000_close(struct device *dev) +{ + int i; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name); + + dev->tbusy = 1; + dev->start = 0; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + + free_irq(dev->irq, dev); + /* If we don't do this, we can't re-insmod it later. */ + release_region(ioaddr[1], SB1000_IO_EXTENT); + release_region(ioaddr[0], SB1000_IO_EXTENT); + + /* free rx_skb's if needed */ + for (i=0; i<4; i++) { + if (lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i]); + } + } + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE +MODULE_AUTHOR("Franco Venturi "); +MODULE_DESCRIPTION("General Instruments SB1000 driver"); +MODULE_PARM(io, "1-2i"); +MODULE_PARM(irq, "i"); + +static char devname[8] = {0, }; +static struct device dev_sb1000 = { + devname, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, sb1000_probe }; + +static int io[2] = {0, 0}; +static int irq = 0; + +int +init_module(void) +{ + int i; + for (i = 0; i < 100; i++) { + sprintf(devname, "cm%d", i); + if (dev_get(devname) == NULL) break; + } + if (i == 100) { + printk(KERN_ERR "sb1000: can't register any device cm\n"); + return -ENFILE; + } + dev_sb1000.base_addr = io[0]; + /* rmem_end holds the second I/O address - fv */ + dev_sb1000.rmem_end = io[1]; + dev_sb1000.irq = irq; + if (register_netdev(&dev_sb1000) != 0) { + printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x " + "irq: %d)\n", io[0], io[1], irq); + return -EIO; + } + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_sb1000); + kfree_s(dev_sb1000.priv, sizeof(struct sb1000_private)); + dev_sb1000.priv = NULL; +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O -m486 -c sb1000.c" + * version-control: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/sealevel.c linux/drivers/net/sealevel.c --- v2.2.10/linux/drivers/net/sealevel.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sealevel.c Mon Aug 9 12:04: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 --recursive --new-file v2.2.10/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.2.10/linux/drivers/net/seeq8005.c Tue Dec 29 11:32:06 1998 +++ linux/drivers/net/seeq8005.c Mon Aug 9 12:04:39 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 --recursive --new-file v2.2.10/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.2.10/linux/drivers/net/sgiseeq.c Mon Nov 16 10:39:27 1998 +++ linux/drivers/net/sgiseeq.c Mon Aug 9 12:04:39 1999 @@ -1,11 +1,9 @@ -/* +/* $Id: sgiseeq.c,v 1.9 1998/10/14 23:40:46 ralf Exp $ + * * sgiseeq.c: Seeq8003 ethernet driver for SGI machines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: sgiseeq.c,v 1.6 1998/10/14 17:29:44 ralf Exp $ */ - #include #include #include @@ -695,6 +693,7 @@ dev->irq = irq; dev->dma = 0; ether_setup(dev); + return 0; } @@ -724,15 +723,20 @@ int sgiseeq_probe(struct device *dev) { + static int initialized; char *ep; + if (initialized) /* Already initialized? */ + return 0; + initialized++; + /* First get the ethernet address of the onboard * interface from ARCS. + * (This is fragile; PROM doesn't like running from cache.) */ ep = romvec->get_evar("eaddr"); str2eaddr(onboard_eth_addr, ep); return sgiseeq_init(dev, (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), &hpc3c0->ethregs, 3); - } diff -u --recursive --new-file v2.2.10/linux/drivers/net/sgiseeq.h linux/drivers/net/sgiseeq.h --- v2.2.10/linux/drivers/net/sgiseeq.h Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/sgiseeq.h Mon Aug 9 12:04:39 1999 @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.h,v 1.1 1997/06/09 08:34:32 ralf Exp $ +/* $Id: sgiseeq.h,v 1.3 1998/08/25 09:17:45 ralf Exp $ * sgiseeq.h: Defines for the Seeq8003 ethernet controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --recursive --new-file v2.2.10/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.2.10/linux/drivers/net/shaper.c Wed Jun 2 11:29:28 1999 +++ linux/drivers/net/shaper.c Mon Aug 9 12:04:39 1999 @@ -51,14 +51,19 @@ * will render your machine defunct. Don't for now shape over * PPP or SLIP therefore! * This will be fixed in BETA4 - */ - -/* - * bh_atomic() SMP races fixes and rewritten the locking code to be SMP safe - * and irq-mask friendly. NOTE: we can't use start_bh_atomic() in kick_shaper() - * because it's going to be recalled from an irq handler, and synchronize_bh() - * is a nono if called from irq context. + * + * Update History : + * + * bh_atomic() SMP races fixes and rewritten the locking code to + * be SMP safe and irq-mask friendly. + * NOTE: we can't use start_bh_atomic() in kick_shaper() + * because it's going to be recalled from an irq handler, + * and synchronize_bh() is a nono if called from irq context. * 1999 Andrea Arcangeli + * + * Device statistics (tx_pakets, tx_bytes, + * tx_drops: queue_over_time and collisions: max_queue_exceded) + * 1999/06/18 Jordi Murgo */ #include @@ -228,18 +233,20 @@ /* * Queue over time. Spill packet. */ - if(skb->shapeclock-jiffies > SHAPER_LATENCY) + if(skb->shapeclock-jiffies > SHAPER_LATENCY) { dev_kfree_skb(skb); - else + shaper->stats.tx_dropped++; + } else skb_queue_tail(&shaper->sendq, skb); } #endif - if(sh_debug) + if(sh_debug) printk("Frame queued.\n"); if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) { ptr=skb_dequeue(&shaper->sendq); - dev_kfree_skb(ptr); + dev_kfree_skb(ptr); + shaper->stats.collisions++; } shaper_unlock(shaper); return 0; @@ -262,7 +269,11 @@ printk("Kick new frame to %s, %d\n", shaper->dev->name,newskb->priority); dev_queue_xmit(newskb); - if(sh_debug) + + shaper->stats.tx_bytes+=newskb->len; + shaper->stats.tx_packets++; + + if(sh_debug) printk("Kicked new frame out.\n"); dev_kfree_skb(skb); } @@ -415,7 +426,8 @@ static struct net_device_stats *shaper_get_stats(struct device *dev) { - return NULL; + struct shaper *sh=dev->priv; + return &sh->stats; } static int shaper_header(struct sk_buff *skb, struct device *dev, @@ -581,7 +593,7 @@ skb_queue_head_init(&sh->sendq); init_timer(&sh->timer); sh->timer.function=shaper_timer; - sh->timer.data=(unsigned long)sh; + sh->timer.data=(unsigned long)sh; return sh; } @@ -664,7 +676,9 @@ void cleanup_module(void) { - /* + struct shaper *sh=dev_shape.priv; + + /* * No need to check MOD_IN_USE, as sys_delete_module() checks. * To be unloadable we must be closed and detached so we don't * need to flush things. @@ -673,10 +687,9 @@ unregister_netdev(&dev_shape); /* - * Free up the private structure, or leak memory :-) + * Free up the private structure, or leak memory :-) */ - - kfree(dev_shape.priv); + kfree(sh); dev_shape.priv = NULL; } diff -u --recursive --new-file v2.2.10/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.2.10/linux/drivers/net/sis900.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sis900.c Mon Aug 9 12:05:13 1999 @@ -0,0 +1,1925 @@ +/*****************************************************************************/ +/* sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux. */ +/* */ +/* Silicon Integrated System Corporation */ +/* Revision: 1.05 Aug 7 1999 */ +/* */ +/*****************************************************************************/ + +/* + Modified from the driver which is originally written by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + The author may be reached as becker@tidalwave.net, or + Donald Becker + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Support and updates [to the original skeleton] available at + http://www.tidalwave.net/~becker/pci-skeleton.html +*/ + +static const char *version = +"sis900.c:v1.05 8/07/99\n"; + +static int max_interrupt_work = 20; +#define sis900_debug debug +static int sis900_debug = 0; + +static int multicast_filter_limit = 128; + +#define MAX_UNITS 8 /* More are supported, limit only on options */ + +#define TX_BUF_SIZE 1536 +#define RX_BUF_SIZE 1536 + +#define TX_DMA_BURST 0 +#define RX_DMA_BURST 0 +#define TX_FIFO_THRESH 16 +#define TxDRNT_100 (1536>>5) +#define TxDRNT_10 16 //(1536>>5) +#define RxDRNT_100 8 +#define RxDRNT_10 8 //(1536>>5) +#define TRUE 1 +#define FALSE 0 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +#define RUN_AT(x) (jiffies + (x)) + +#include + +#if LINUX_VERSION_CODE < 0x20123 +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif +#if LINUX_VERSION_CODE <= 0x20139 +#define net_device_stats enet_statistics +#else +#define NETSTATS_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) +/* Grrrr, the PCI code changed, but did not consider CardBus... */ +#include +#define PCI_SUPPORT_VER1 +#else +#define PCI_SUPPORT_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20159 +#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); +#else +#define dev_free_skb(skb) dev_kfree_skb(skb); +#endif + +/* The I/O extent. */ +#define SIS900_TOTAL_SIZE 0x100 + +/* This table drives the PCI probe routines. It's mostly boilerplate in all + of the drivers, and will likely be provided by some future kernel. + Note the matching code -- the first table entry matchs all 56** cards but + second only the 1234 card. +*/ + +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, +}; + +struct pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt); +}; + +static struct device * sis900_probe1(int pci_bus, int pci_devfn, + struct device *dev, long ioaddr, + int irq, int chp_idx, int fnd_cnt); + +static struct pci_id_info pci_tbl[] = +{{ "SiS 900 PCI Fast Ethernet", + 0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, + { "SiS 7016 PCI Fast Ethernet", + 0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1}, + {0,}, /* 0 terminated list. */ +}; + +/* The capability table matches the chip table above. */ +enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; +static int sis_cap_tbl[] = { + HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, + HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG, +}; + +/* The rest of these values should never change. */ +#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ +#define NUM_RX_DESC 8 /* Number of Rx descriptor registers. */ + +/* Symbolic offsets to registers. */ +enum SIS900_registers { + cr=0x0, //Command Register + cfg=0x4, //Configuration Register + mear=0x8, //EEPROM Access Register + ptscr=0xc, //PCI Test Control Register + isr=0x10, //Interrupt Status Register + imr=0x14, //Interrupt Mask Register + ier=0x18, //Interrupt Enable Register + epar=0x18, //Enhanced PHY Access Register + txdp=0x20, //Transmit Descriptor Pointer Register + txcfg=0x24, //Transmit Configuration Register + rxdp=0x30, //Receive Descriptor Pointer Register + rxcfg=0x34, //Receive Configuration Register + flctrl=0x38, //Flow Control Register + rxlen=0x3c, //Receive Packet Length Register + rfcr=0x48, //Receive Filter Control Register + rfdr=0x4C, //Receive Filter Data Register + pmctrl=0xB0, //Power Management Control Register + pmer=0xB4 //Power Management Wake-up Event Register +}; + +#define RESET 0x00000100 +#define SWI 0x00000080 +#define RxRESET 0x00000020 +#define TxRESET 0x00000010 +#define RxDIS 0x00000008 +#define RxENA 0x00000004 +#define TxDIS 0x00000002 +#define TxENA 0x00000001 + +#define BISE 0x80000000 +#define EUPHCOM 0x00000100 +#define REQALG 0x00000080 +#define SB 0x00000040 +#define POW 0x00000020 +#define EXD 0x00000010 +#define PESEL 0x00000008 +#define LPM 0x00000004 +#define BEM 0x00000001 + +/* Interrupt register bits, using my own meaningful names. */ +#define WKEVT 0x10000000 +#define TxPAUSEEND 0x08000000 +#define TxPAUSE 0x04000000 +#define TxRCMP 0x02000000 +#define RxRCMP 0x01000000 +#define DPERR 0x00800000 +#define SSERR 0x00400000 +#define RMABT 0x00200000 +#define RTABT 0x00100000 +#define RxSOVR 0x00010000 +#define HIBERR 0x00008000 +#define SWINT 0x00001000 +#define MIBINT 0x00000800 +#define TxURN 0x00000400 +#define TxIDLE 0x00000200 +#define TxERR 0x00000100 +#define TxDESC 0x00000080 +#define TxOK 0x00000040 +#define RxORN 0x00000020 +#define RxIDLE 0x00000010 +#define RxEARLY 0x00000008 +#define RxERR 0x00000004 +#define RxDESC 0x00000002 +#define RxOK 0x00000001 + +#define IE 0x00000001 + +#define TxCSI 0x80000000 +#define TxHBI 0x40000000 +#define TxMLB 0x20000000 +#define TxATP 0x10000000 +#define TxIFG 0x0C000000 +#define TxMXF 0x03800000 +#define TxMXF_shift 0x23 +#define TxMXDMA 0x00700000 +#define TxMXDMA_shift 20 +#define TxRTCNT 0x000F0000 +#define TxRTCNT_shift 16 +#define TxFILLT 0x00007F00 +#define TxFILLT_shift 8 +#define TxDRNT 0x0000007F + +#define RxAEP 0x80000000 +#define RxARP 0x40000000 +#define RxATP 0x10000000 +#define RxAJAB 0x08000000 +#define RxMXF 0x03800000 +#define RxMXF_shift 23 +#define RxMXDMA 0x00700000 +#define RxMXDMA_shift 20 +#define RxDRNT 0x0000007F + +#define RFEN 0x80000000 +#define RFAAB 0x40000000 +#define RFAAM 0x20000000 +#define RFAAP 0x10000000 +#define RFPromiscuous (RFAAB|RFAAM|RFAAP) +#define RFAA_shift 28 +#define RFEP 0x00070000 +#define RFEP_shift 16 + +#define RFDAT 0x0000FFFF + +#define OWN 0x80000000 +#define MORE 0x40000000 +#define INTR 0x20000000 +#define OK 0x08000000 +#define DSIZE 0x00000FFF + +#define SUPCRC 0x10000000 +#define ABORT 0x04000000 +#define UNDERRUN 0x02000000 +#define NOCARRIER 0x01000000 +#define DEFERD 0x00800000 +#define EXCDEFER 0x00400000 +#define OWCOLL 0x00200000 +#define EXCCOLL 0x00100000 +#define COLCNT 0x000F0000 + +#define INCCRC 0x10000000 +// ABORT 0x04000000 +#define OVERRUN 0x02000000 +#define DEST 0x01800000 +#define BCAST 0x01800000 +#define MCAST 0x01000000 +#define UNIMATCH 0x00800000 +#define TOOLONG 0x00400000 +#define RUNT 0x00200000 +#define RXISERR 0x00100000 +#define CRCERR 0x00080000 +#define FAERR 0x00040000 +#define LOOPBK 0x00020000 +#define RXCOL 0x00010000 + +#define EuphLiteEEMACAddr 0x08 +#define EuphLiteEEVendorID 0x02 +#define EuphLiteEEDeviceID 0x03 +#define EuphLiteEECardTypeRev 0x0b +#define EuphLiteEEPlexusRev 0x0c +#define EuphLiteEEChecksum 0x0f + +#define RXSTS_shift 18 +#define OWN 0x80000000 +#define MORE 0x40000000 +#define INTR 0x20000000 +#define OK 0x08000000 +#define DSIZE 0x00000FFF +/* MII register offsets */ +#define MII_CONTROL 0x0000 +#define MII_STATUS 0x0001 +#define MII_PHY_ID0 0x0002 +#define MII_PHY_ID1 0x0003 +#define MII_ANAR 0x0004 +#define MII_ANLPAR 0x0005 +#define MII_ANER 0x0006 +/* MII Control register bit definitions. */ +#define MIICNTL_FDX 0x0100 +#define MIICNTL_RST_AUTO 0x0200 +#define MIICNTL_ISOLATE 0x0400 +#define MIICNTL_PWRDWN 0x0800 +#define MIICNTL_AUTO 0x1000 +#define MIICNTL_SPEED 0x2000 +#define MIICNTL_LPBK 0x4000 +#define MIICNTL_RESET 0x8000 +/* MII Status register bit significance. */ +#define MIISTAT_EXT 0x0001 +#define MIISTAT_JAB 0x0002 +#define MIISTAT_LINK 0x0004 +#define MIISTAT_CAN_AUTO 0x0008 +#define MIISTAT_FAULT 0x0010 +#define MIISTAT_AUTO_DONE 0x0020 +#define MIISTAT_CAN_T 0x0800 +#define MIISTAT_CAN_T_FDX 0x1000 +#define MIISTAT_CAN_TX 0x2000 +#define MIISTAT_CAN_TX_FDX 0x4000 +#define MIISTAT_CAN_T4 0x8000 +/* MII NWAY Register Bits ... +** valid for the ANAR (Auto-Negotiation Advertisement) and +** ANLPAR (Auto-Negotiation Link Partner) registers */ +#define MII_NWAY_NODE_SEL 0x001f +#define MII_NWAY_CSMA_CD 0x0001 +#define MII_NWAY_T 0x0020 +#define MII_NWAY_T_FDX 0x0040 +#define MII_NWAY_TX 0x0080 +#define MII_NWAY_TX_FDX 0x0100 +#define MII_NWAY_T4 0x0200 +#define MII_NWAY_RF 0x2000 +#define MII_NWAY_ACK 0x4000 +#define MII_NWAY_NP 0x8000 + +/* MII Auto-Negotiation Expansion Register Bits */ +#define MII_ANER_PDF 0x0010 +#define MII_ANER_LP_NP_ABLE 0x0008 +#define MII_ANER_NP_ABLE 0x0004 +#define MII_ANER_RX_PAGE 0x0002 +#define MII_ANER_LP_AN_ABLE 0x0001 +#define HALF_DUPLEX 1 +#define FDX_CAPABLE_DUPLEX_UNKNOWN 2 +#define FDX_CAPABLE_HALF_SELECTED 3 +#define FDX_CAPABLE_FULL_SELECTED 4 +#define HW_SPEED_UNCONFIG 0 +#define HW_SPEED_10_MBPS 10 +#define HW_SPEED_100_MBPS 100 +#define HW_SPEED_DEFAULT (HW_SPEED_10_MBPS) + +#define ACCEPT_ALL_PHYS 0x01 +#define ACCEPT_ALL_MCASTS 0x02 +#define ACCEPT_ALL_BCASTS 0x04 +#define ACCEPT_ALL_ERRORS 0x08 +#define ACCEPT_CAM_QUALIFIED 0x10 +#define MAC_LOOPBACK 0x20 +//#define FDX_CAPABLE_FULL_SELECTED 4 +#define CRC_SIZE 4 +#define MAC_HEADER_SIZE 14 + +typedef struct _EuphLiteDesc { + u32 llink; + unsigned char* buf; + u32 physAddr; + /* Hardware sees the physical address of descriptor */ + u32 plink; + u32 cmdsts; + u32 bufPhys; +} EuphLiteDesc; + +struct sis900_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct device *next_module; + int chip_id; + int chip_revision; + unsigned char pci_bus, pci_devfn; +#if LINUX_VERSION_CODE > 0x20139 + struct net_device_stats stats; +#else + struct enet_statistics stats; +#endif + struct timer_list timer; /* Media selection timer. */ + unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ + unsigned int cur_tx, dirty_tx, tx_flag; + + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[NUM_TX_DESC]; + EuphLiteDesc tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + EuphLiteDesc rx_buf[NUM_RX_DESC]; + unsigned char *rx_bufs; + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + char phys[4]; /* MII device addresses. */ + int phy_idx; + u16 pmd_status; + unsigned int tx_full; /* The Tx queue is full. */ + u16 full_duplex; /* FullHalf-duplex. */ + u16 hunmbps; /* 10010 Mbps. */ + u16 LinkOn; + u16 LinkChange; +}; + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Silicon Integrated Systems Corporation"); +MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(multicast_filter_limit, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(debug, "i"); +#endif +#endif + +static int sis900_open(struct device *dev); +static u16 read_eeprom(long ioaddr, int location); +static int mdio_read(struct device *dev, int phy_id, int location); +static void mdio_write(struct device *dev, int phy_id, int location, int val); +static void sis900_timer(unsigned long data); +static void sis900_tx_timeout(struct device *dev); +static void sis900_init_ring(struct device *dev); +static int sis900_start_xmit(struct sk_buff *skb, struct device *dev); +static int sis900_rx(struct device *dev); +static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sis900_close(struct device *dev); +static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static struct enet_statistics *sis900_get_stats(struct device *dev); +static void set_rx_mode(struct device *dev); +static void sis900_reset(struct device *dev); +static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed); +static u16 elPMDreadMode(struct device *dev, int phy_id, int *speed, int *duplex); +static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value); +static void elSetMediaType(struct device *dev, int speed, int duplex); + +/* A list of all installed SiS900 devices, for removing the driver module. */ +static struct device *root_sis900_dev = NULL; + +/* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well when dynamically adding drivers. So instead we detect just the + SiS 900 cards in slot order. */ + +int sis900_probe(struct device *dev) +{ + int cards_found = 0; + int pci_index = 0; + unsigned char pci_bus, pci_device_fn; + + if ( ! pcibios_present()) + return -ENODEV; + + for (;pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command, new_command; + int chip_idx, irq; + long ioaddr; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) { + break; + } + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, + &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, + &device); + + for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pci_tbl[chip_idx].vendor_id && + (device & pci_tbl[chip_idx].device_id_mask) == + pci_tbl[chip_idx].device_id) + break; + if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ + continue; + + { +#if defined(PCI_SUPPORT_VER2) + struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->base_address[0] & ~3; + irq = pdev->irq; +#else + u32 pci_ioaddr; + u8 pci_irq_line; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + ioaddr = pci_ioaddr & ~3; + irq = pci_irq_line; +#endif + } + + if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && + check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + + /* Activate the card: fix for brain-damaged Win98 BIOSes. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_tbl[chip_idx].flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d!" + "Updating PCI command %4.4x->%4.4x.\n", + pci_bus, pci_device_fn, + pci_command, new_command); + + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + + dev = pci_tbl[chip_idx].probe1(pci_bus, + pci_device_fn, + dev, + ioaddr, + irq, + chip_idx, + cards_found); + + if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { + u8 pci_latency; + + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 32) { + printk(KERN_NOTICE " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to 64 clocks.\n", + pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 64); + } + } + dev = 0; + cards_found++; + } + return cards_found ? 0 : -ENODEV; +} + +static struct device * sis900_probe1( int pci_bus, + int pci_devfn, + struct device *dev, + long ioaddr, + int irq, + int chip_idx, + int found_cnt) +{ + static int did_version = 0; /* Already printed version info. */ + struct sis900_private *tp; + int duplex=0; + int speed=0; + int i; + + if (did_version++ == 0) + printk(KERN_INFO "%s", version); + + dev = init_etherdev(dev, 0); + + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, pci_tbl[chip_idx].name, ioaddr, irq); + + if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) { + for (i = 0; i < 3; i++) + ((u16 *)(dev->dev_addr))[i] = + read_eeprom(ioaddr,i+EuphLiteEEMACAddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + } else + printk(KERN_INFO "Error EEPROM read\n"); + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Some data structures must be quadword aligned. */ + tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + + tp->next_module = root_sis900_dev; + root_sis900_dev = dev; + + tp->chip_id = chip_idx; + tp->pci_bus = pci_bus; + tp->pci_devfn = pci_devfn; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) { + int phy, phy_idx; + for (phy = 0, phy_idx = 0; + phy < 32 && phy_idx < sizeof(tp->phys); phy++) + { + int mii_status = mdio_read(dev, phy, MII_STATUS); + /* + { + int p; + int l; + for (p = 0 ; p < 4 ; p ++) { + for (l=0 ; l<16 ; l++) { + int status = mdio_read(dev, phy, l); + status = mdio_read(dev, phy, l); + printk(KERN_INFO "MII info addr[%d][%d]=%x\n", + p, l, status); + } + } + } + */ + + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phy_idx = phy_idx; + tp->phys[phy_idx++] = phy; + tp->pmd_status=mdio_read(dev, phy, MII_STATUS); + printk(KERN_INFO "%s: MII transceiver found " + "at address %d.\n", + dev->name, phy); + break; + } + } + + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found!", + dev->name); + printk(KERN_INFO "Assuming SYM transceiver.\n"); + tp->phys[0] = -1; + } + } else { + tp->phys[0] = 32; + } + + if (tp->pmd_status > 0) { + tp->pmd_status= + elAutoNegotiate(dev, tp->phys[tp->phy_idx], &duplex, &speed); + if (tp->pmd_status & MIISTAT_LINK) { + if (duplex == FDX_CAPABLE_FULL_SELECTED) + tp->full_duplex=1; + if (speed == HW_SPEED_100_MBPS) + tp->hunmbps=1; + tp->LinkOn = TRUE; + } else { + tp->LinkOn = FALSE; + } + tp->LinkChange = FALSE; + } + + /* + if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) + tp->full_duplex = full_duplex[found_cnt]; + + if (tp->full_duplex) { + printk(KERN_INFO "%s: Media type is Full Duplex.\n", dev->name); + } else { + printk(KERN_INFO "%s: Media type is Half Duplex.\n", dev->name); + } + if (tp->hunmbps) { + printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name); + } else { + printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name); + } + */ + + /* The SiS900-specific entries in the device structure. */ + dev->open = &sis900_open; + dev->hard_start_xmit = &sis900_start_xmit; + dev->stop = &sis900_close; + dev->get_stats = &sis900_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + return dev; +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EECLK 0x00000004 /* EEPROM shift clock. */ +#define EECS 0x00000008 /* EEPROM chip select. */ +#define EEDO 0x00000002 /* EEPROM chip data out. */ +#define EEDI 0x00000001 /* EEPROM chip data in. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. + */ + +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EEread 0x0180 +#define EEwrite 0x0140 +#define EEerase 0x01C0 +#define EEwriteEnable 0x0130 +#define EEwriteDisable 0x0100 +#define EEeraseAll 0x0120 +#define EEwriteAll 0x0110 +#define EEaddrMask 0x013F +#define EEcmdShift 16 + +static u16 read_eeprom(long ioaddr, int location) +{ + int i; + u16 retval = 0; + long ee_addr = ioaddr + mear; + u32 read_cmd = location | EEread; + + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + eeprom_delay(); + + /* Shift the read command bits out. */ + for (i = 8; i >= 0; i--) { + u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; + outl(dataval, ee_addr); + eeprom_delay(); + outl(dataval | EECLK, ee_addr); + eeprom_delay(); + } + outb(EECS, ee_addr); + eeprom_delay(); + + for (i = 16; i > 0; i--) { + outl(EECS, ee_addr); + eeprom_delay(); + outl(EECS | EECLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + return (retval); +} + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ + +#define mdio_delay() inl(mdio_addr) + +#define MIIread 0x6000 +#define MIIwrite 0x6002 +#define MIIpmdMask 0x0F80 +#define MIIpmdShift 7 +#define MIIregMask 0x007C +#define MIIregShift 2 +#define MIIturnaroundBits 2 +#define MIIcmdLen 16 +#define MIIcmdShift 16 +#define MIIreset 0xFFFFFFFF +#define MIIwrLen 32 + +#define MDC 0x00000040 +#define MDDIR 0x00000020 +#define MDIO 0x00000010 + +static void mdio_idle(long mdio_addr) +{ + outl(MDIO | MDDIR, mdio_addr); + mdio_delay(); + outl(MDIO | MDDIR | MDC, mdio_addr); +} + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_reset(long mdio_addr) +{ + int i; + + for (i = 31; i >= 0; i--) { + outl(MDDIR | MDIO, mdio_addr); + mdio_delay(); + outl(MDDIR | MDIO | MDC, mdio_addr); + mdio_delay(); + } + return; +} + +static int mdio_read(struct device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + mear; + int mii_cmd = MIIread|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); + outl(dataval | MDC, mdio_addr); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 16; i > 0; i--) { + outl(0, mdio_addr); + //mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); + outl(MDC, mdio_addr); + mdio_delay(); + } + return retval; +} + +static void mdio_write(struct device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + mear; + int mii_cmd = MIIwrite|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outb(dataval, mdio_addr); + mdio_delay(); + outb(dataval | MDC, mdio_addr); + mdio_delay(); + } + mdio_delay(); + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + outb(MDC, mdio_addr); + mdio_delay(); + } + return; +} + +static int +sis900_open(struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (sis900_debug > 0) + printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n", + dev->name, (unsigned int)ioaddr, dev->irq); + + /* Soft reset the chip. */ + outl(0, ioaddr + imr); + outl(0, ioaddr + ier); + outl(0, ioaddr + rfcr); + outl(RESET | RxRESET | TxRESET, ioaddr + cr); + + if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev)) + { + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); + tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); + if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) { + if (tp->tx_bufs) + kfree(tp->tx_bufs); + if (sis900_debug > 0) + printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", + dev->name, TX_BUF_SIZE * NUM_TX_DESC); + return -ENOMEM; + } + + { + u32 rfcrSave; + u32 w; + u32 i; + + rfcrSave = inl(rfcr); + outl(rfcrSave & ~RFEN, rfcr); + for (i=0 ; i<3 ; i++) { + w = (u16)*((u16*)(dev->dev_addr)+i); + outl((((u32) i) << RFEP_shift), ioaddr + rfcr); + outl((u32)w, ioaddr + rfdr); + if (sis900_debug > 4) { + printk(KERN_INFO "Filter Addr[%d]=%x\n", + i, inl(ioaddr + rfdr)); + } + } + /* + for (i=0 ; i<3 ; i++) { + outl((((u32) i) << RFEP_shift), ioaddr + rfcr); + if (sis900_debug > 4) { + printk(KERN_INFO "Read Filter Addr[%d]=%x\n", + i, inl(ioaddr + rfdr)); + } + } + */ + outl(rfcrSave, rfcr); + } + + sis900_init_ring(dev); + outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp); + outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp); + + if (sis900_debug > 4) + printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp)); + + /* Check that the chip has finished the reset. */ + { + u32 status; + int j=0; + status = TxRCMP | RxRCMP; + while (status && (j++ < 30000)) { + status ^= (inl(isr) & status); + } + } + + outl(PESEL, ioaddr + cfg); + + /* Must enable Tx/Rx before setting transfer thresholds! */ + /* + #define TX_DMA_BURST 0 + #define RX_DMA_BURST 0 + #define TX_FIFO_THRESH 16 + #define TxDRNT_100 (1536>>5) + #define TxDRNT_10 (1536>>5) + #define RxDRNT_100 (1536>>5) + #define RxDRNT_10 (1536>>5) + */ + //outl(RxENA | TxENA, ioaddr + cr); + outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg); + outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10, + ioaddr + txcfg); + //tp->full_duplex = tp->duplex_lock; + if (tp->phys[tp->phy_idx] >= 0 || + (sis_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) { + if (sis900_debug > 1) + if (tp->LinkOn) { + printk(KERN_INFO"%s: Setting %s%s-duplex.\n", + dev->name, + tp->hunmbps ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half"); + } else { + printk(KERN_INFO"%s: Media Link Off\n", dev->name); + } + } + set_rx_mode(dev); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); + outl(RxENA, ioaddr + cr); + outl(IE, ioaddr + ier); + + if (sis900_debug > 1) + printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n", + dev->name, ioaddr, dev->irq); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &sis900_timer; /* timer handler */ + add_timer(&tp->timer); + + return 0; +} + +static void sis900_timer(unsigned long data) +{ + struct device *dev = (struct device *)data; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 0; + int duplex, full_duplex=0; + int speed, hunmbps=0; + u16 status; + +// printk(KERN_INFO "%s: SiS900 timer\n", dev->name); + elMIIpollBit(dev, tp->phys[tp->phy_idx], MII_STATUS, MIISTAT_LINK, TRUE, &status); + if (status & MIISTAT_LINK) { +// printk(KERN_INFO "%s: SiS900 timer link\n", dev->name); + /* + if (!tp->LinkOn) { + printk(KERN_INFO "%s: AutoNegotiate ...\n", dev->name); + tp->LinkChange=TRUE; + tp->pmd_status= + elAutoNegotiate(dev, tp->phys[tp->phy_idx], + &duplex, &speed); + } + else { + printk(KERN_INFO "%s: Link Still On.\n", dev->name); + elPMDreadMode(dev, tp->phys[tp->phy_idx], + &speed, &duplex); + } + */ + elPMDreadMode(dev, tp->phys[tp->phy_idx], + &speed, &duplex); + + + if (duplex == FDX_CAPABLE_FULL_SELECTED) full_duplex=1; + if (speed == HW_SPEED_100_MBPS) hunmbps=1; + if (full_duplex != tp->full_duplex || hunmbps != tp->hunmbps) + tp->LinkChange = TRUE; + if (tp->LinkChange) { + tp->full_duplex=full_duplex; + tp->hunmbps=hunmbps; + //elSetMediaType(dev, speed, duplex); + printk(KERN_INFO "%s: Setting %s%s-duplex based on MII " + "#%d link partner ability.\n", + dev->name, + tp->hunmbps ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half", + tp->phys[0]); + } + tp->LinkOn=TRUE; + tp->LinkChange = FALSE; + } else { + if (tp->LinkOn) { + tp->LinkChange = TRUE; + tp->pmd_status= + elAutoNegotiate(dev, tp->phys[tp->phy_idx], + &duplex, &speed); + if (tp->pmd_status & MIISTAT_LINK) { + if (duplex == FDX_CAPABLE_FULL_SELECTED) + tp->full_duplex=1; + if (speed == HW_SPEED_100_MBPS) + tp->hunmbps=1; + } else { + tp->LinkOn = FALSE; + printk(KERN_INFO "%s: Link Off\n", dev->name); + } + } +// printk(KERN_INFO "%s: Link Off\n", dev->name); + } + next_tick = 2*HZ; + + if (sis900_debug > 3) { + printk(KERN_INFO "%s: Other registers are IntMask " + "%4.4x IntStatus %4.4x" + " RxStatus %4.4x.\n", + dev->name, + inw(ioaddr + imr), + inw(ioaddr + isr), + inl(ioaddr + rxcfg)); + } + + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void sis900_tx_timeout(struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + if (sis900_debug > 0) + printk(KERN_INFO "%s: Transmit timeout, status %2.2x %4.4x \n", + dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); + /* Emit info to figure out what went wrong. */ + printk(KERN_INFO "%s: Tx queue start entry %d dirty entry %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + for (i = 0; i < NUM_TX_DESC; i++) + printk(KERN_INFO "%s: Tx descriptor %d is %8.8x.%s\n", + dev->name, i, (unsigned int)&tp->tx_buf[i], + i == tp->dirty_tx % NUM_TX_DESC ? + " (queue head)" : ""); + /* + printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]); + for (mii_reg = 0; mii_reg < 8; mii_reg++) + printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); + printk(".\n"); + */ + + /* Soft reset the chip. */ + + tp->cur_rx = 0; //?????? + /* Must enable Tx/Rx before setting transfer thresholds! */ + /* + set_rx_mode(dev); + */ + { /* Save the unsent Tx packets. */ + struct sk_buff *saved_skb[NUM_TX_DESC], *skb; + int j; + for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) + saved_skb[j]=tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC]; + tp->dirty_tx = tp->cur_tx = 0; + + for (i = 0; i < j; i++) { + skb = tp->tx_skbuff[i] = saved_skb[i]; + /* Always alignment */ + memcpy((unsigned char*)(tp->tx_buf[i].buf), + skb->data, skb->len); + tp->tx_buf[i].cmdsts = OWN | skb->len; + /* Note: the chip doesn't have auto-pad! */ + /* + outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN), + ioaddr + TxStatus0 + i*4); + */ + } + outl(TxENA, ioaddr + cr); + tp->cur_tx = i; + while (i < NUM_TX_DESC) + tp->tx_skbuff[i++] = 0; + if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + dev->tbusy = 0; + tp->tx_full = 0; + } else { + tp->tx_full = 1; + } + } + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + /* Enable all known interrupts by setting the interrupt mask. */ + outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr); + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +sis900_init_ring(struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = 0; + tp->dirty_tx = tp->cur_tx = 0; + + /* Tx Buffer */ + for (i = 0; i < NUM_TX_DESC; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE]; + tp->tx_buf[i].bufPhys = + virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]); + /* + printk(KERN_INFO "tp->tx_buf[%d].bufPhys=%8.8x\n", + i, tp->tx_buf[i].bufPhys); + */ + } + + /* Tx Descriptor */ + for (i = 0; i< NUM_TX_DESC; i++) { + tp->tx_buf[i].llink = (u32) + &(tp->tx_buf[((i+1) < NUM_TX_DESC) ? (i+1) : 0]); + tp->tx_buf[i].plink = (u32) + virt_to_bus(&(tp->tx_buf[((i+1) < NUM_TX_DESC) ? + (i+1) : 0].plink)); + tp->tx_buf[i].physAddr= + virt_to_bus(&(tp->tx_buf[i].plink)); + tp->tx_buf[i].cmdsts=0; + + /* + printk(KERN_INFO "tp->tx_buf[%d].PhysAddr=%8.8x\n", + i, tp->tx_buf[i].physAddr); + */ + } + + /* Rx Buffer */ + for (i = 0; i < NUM_RX_DESC; i++) { + tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE]; + tp->rx_buf[i].bufPhys = + virt_to_bus(&tp->rx_bufs[i*RX_BUF_SIZE]); + /* + printk(KERN_INFO "tp->rx_buf[%d].bufPhys=%8.8x\n", + i, tp->rx_buf[i].bufPhys); + */ + } + + /* Rx Descriptor */ + for (i = 0; i< NUM_RX_DESC; i++) { + tp->rx_buf[i].llink = (u32) + &(tp->rx_buf[((i+1) < NUM_RX_DESC) ? (i+1) : 0]); + tp->rx_buf[i].plink = (u32) + virt_to_bus(&(tp->rx_buf[((i+1) < NUM_RX_DESC) ? + (i+1) : 0].plink)); + tp->rx_buf[i].physAddr= + virt_to_bus(&(tp->rx_buf[i].plink)); + tp->rx_buf[i].cmdsts=RX_BUF_SIZE; + /* + printk(KERN_INFO "tp->tx_buf[%d].PhysAddr=%8.8x\n", + i, tp->tx_buf[i].physAddr); + */ + } +} + +static int +sis900_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + int entry; + + /* 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) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + sis900_tx_timeout(dev); + return 1; + } + + /* Calculate the next Tx descriptor entry. ????? */ + entry = tp->cur_tx % NUM_TX_DESC; + + tp->tx_skbuff[entry] = skb; + + if (sis900_debug > 5) { + int i; + printk(KERN_INFO "%s: SKB Tx Frame contents:(len=%d)", + dev->name,skb->len); + + for (i = 0; i < skb->len; i++) { + printk("%2.2x ", + (u8)skb->data[i]); + } + printk(".\n"); + } + + memcpy(tp->tx_buf[entry].buf, + skb->data, skb->len); + + tp->tx_buf[entry].cmdsts=(OWN | skb->len); + + outl(TxENA, ioaddr + cr); + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + clear_bit(0, (void*)&dev->tbusy); + } else { + tp->tx_full = 1; + } + + /* Note: the chip doesn't have auto-pad! */ + + dev->trans_start = jiffies; + if (sis900_debug > 4) + printk(KERN_INFO "%s: Queued Tx packet at " + "%p size %d to slot %d.\n", + dev->name, skb->data, (int)skb->len, entry); + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_instance; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int boguscnt = max_interrupt_work; + int status; + long ioaddr = dev->base_addr; + +#if defined(__i386__) + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_INFO "%s: SMP simultaneous entry of " + "an interrupt handler.\n", dev->name); + dev->interrupt = 0; /* Avoid halting machine. */ + return; + } +#else + if (dev->interrupt) { + printk(KERN_INFO "%s: Re-entering the " + "interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; +#endif + + do { + status = inl(ioaddr + isr); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status, ioaddr + isr); // ????? + + if (sis900_debug > 4) + printk(KERN_INFO "%s: interrupt status=%#4.4x " + "new intstat=%#4.4x.\n", + dev->name, status, inl(ioaddr + isr)); + + if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) { + break; + } + + if (status & (RxOK|RxORN|RxERR)) /* Rx interrupt */ + sis900_rx(dev); + + if (status & (TxOK | TxERR)) { + unsigned int dirty_tx; + + if (sis900_debug > 5) { + printk(KERN_INFO "TxOK:tp->cur_tx:%d," + "tp->dirty_tx:%x\n", + tp->cur_tx, tp->dirty_tx); + } + for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; + dirty_tx++) + { + int i; + int entry = dirty_tx % NUM_TX_DESC; + int txstatus = tp->tx_buf[entry].cmdsts; + + if (sis900_debug > 4) { + printk(KERN_INFO "%s: Tx Frame contents:" + "(len=%d)", + dev->name, (txstatus & DSIZE)); + + for (i = 0; i < (txstatus & DSIZE) ; + i++) { + printk("%2.2x ", + (u8)(tp->tx_buf[entry].buf[i])); + } + printk(".\n"); + } + if ( ! (txstatus & (OK | UNDERRUN))) + { + if (sis900_debug > 1) + printk(KERN_INFO "Tx NOT (OK," + "UnderRun)\n"); + break; /* It still hasn't been Txed */ + } + + /* Note: TxCarrierLost is always asserted + at 100mbps. */ + if (txstatus & (OWCOLL | ABORT)) { + /* There was an major error, log it. */ + if (sis900_debug > 1) + printk(KERN_INFO "Tx Out of " + " Window,Abort\n"); +#ifndef final_version + if (sis900_debug > 1) + printk(KERN_INFO "%s: Transmit " + "error, Tx status %8.8x.\n", + dev->name, txstatus); +#endif + tp->stats.tx_errors++; + if (txstatus & ABORT) { + tp->stats.tx_aborted_errors++; + /* + outl((TX_DMA_BURST<<8)| + 0x03000001, + ioaddr + TxConfig); + */ + } + if (txstatus & NOCARRIER) + tp->stats.tx_carrier_errors++; + if (txstatus & OWCOLL) + tp->stats.tx_window_errors++; +#ifdef ETHER_STATS + if ((txstatus & COLCNT)==COLCNT) + tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + /* No count for tp->stats.tx_deferred */ +#endif + if (txstatus & UNDERRUN) { + if (sis900_debug > 1) + printk(KERN_INFO "Tx UnderRun\n"); + /* Add 64 to the Tx FIFO threshold. */ + /* + if (tp->tx_flag < 0x00300000) + tp->tx_flag+=0x00020000; + tp->stats.tx_fifo_errors++; + */ + } + tp->stats.collisions += + (txstatus >> 16) & 0xF; +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.tx_bytes += txstatus & DSIZE; +#endif + if (sis900_debug > 1) + printk(KERN_INFO "Tx Transmit OK\n"); + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + if (sis900_debug > 1) + printk(KERN_INFO "Free original skb\n"); + dev_free_skb(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + } // for dirty + +#ifndef final_version + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { + printk(KERN_INFO"%s: Out-of-sync dirty pointer," + " %d vs. %d, full=%d.\n", + dev->name, dirty_tx, + tp->cur_tx, tp->tx_full); + dirty_tx += NUM_TX_DESC; + } +#endif + + if (tp->tx_full && dirty_tx > tp->cur_tx-NUM_TX_DESC) { + /* The ring is no longer full, clear tbusy. */ + //printk(KERN_INFO "Tx Ring NO LONGER Full\n"); + tp->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + tp->dirty_tx = dirty_tx; + if (sis900_debug > 1) + printk(KERN_INFO "TxOK release, tp->cur_tx:%d, tp->dirty:%d\n", + tp->cur_tx, tp->dirty_tx); + } // if (TxOK | TxERR) + + /* Check uncommon events with one test. */ + if (status & (RxORN | TxERR | RxERR)) { + if (sis900_debug > 2) + printk(KERN_INFO "%s: Abnormal interrupt," + "status %8.8x.\n", dev->name, status); + + if (status == 0xffffffff) + break; + + if (status & (RxORN | RxERR)) + tp->stats.rx_errors++; + + if (status & RxORN) { + tp->stats.rx_over_errors++; + /* + tp->cur_rx = + inw(ioaddr + RxBufAddr) % RX_BUF_LEN; + outw(tp->cur_rx - 16, ioaddr + RxBufPtr); + */ + } + } + if (--boguscnt < 0) { + printk(KERN_INFO "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + //outw(0xffff, ioaddr + IntrStatus); + break; + } + } while (1); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, inl(ioaddr + isr)); + +#if defined(__i386__) + clear_bit(0, (void*)&dev->interrupt); +#else + dev->interrupt = 0; +#endif + return; +} + +/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the + field alignments and semantics. */ +static int sis900_rx(struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 cur_rx = tp->cur_rx % NUM_RX_DESC; + int rx_status=tp->rx_buf[cur_rx].cmdsts; + + if (sis900_debug > 4) + printk(KERN_INFO "%s: sis900_rx, current %4.4x," + " rx status=%8.8x\n", + dev->name, cur_rx, + rx_status); + + while (rx_status & OWN) { + int rx_size = rx_status & DSIZE; + rx_size -= CRC_SIZE; + + //printk(KERN_INFO "Rx OWN\n"); + if (sis900_debug > 4) { + int i; + printk(KERN_INFO "%s: sis900_rx, rx status %8.8x," + " size %4.4x, cur %4.4x.\n", + dev->name, rx_status, rx_size, cur_rx); + printk(KERN_INFO "%s: Rx Frame contents:", dev->name); + + for (i = 0; i < rx_size; i++) { + printk("%2.2x ", + (u8)(tp->rx_buf[cur_rx].buf[i])); + } + + printk(".\n"); + } + if (rx_status & TOOLONG) { + if (sis900_debug > 1) + printk(KERN_INFO "%s: Oversized Ethernet frame," + " status %4.4x!\n", + dev->name, rx_status); + tp->stats.rx_length_errors++; + } else if (rx_status & (RXISERR | RUNT | CRCERR | FAERR)) { + if (sis900_debug > 1) + printk(KERN_INFO"%s: Ethernet frame had errors," + " status %4.4x.\n", + dev->name, rx_status); + tp->stats.rx_errors++; + if (rx_status & (RXISERR | FAERR)) + tp->stats.rx_frame_errors++; + if (rx_status & (RUNT | TOOLONG)) + tp->stats.rx_length_errors++; + if (rx_status & CRCERR) tp->stats.rx_crc_errors++; + /* Reset the receiver, + based on RealTek recommendation. (Bug?) */ + /* + tp->cur_rx = 0; + outl(TxENA, ioaddr + cr); + outl(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | + (RX_DMA_BURST<<8), ioaddr + RxConfig); + */ + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + struct sk_buff *skb; + + //printk(KERN_INFO "Rx OK\n"); + skb = dev_alloc_skb(rx_size + 2); + if (skb == NULL) { + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + dev->name); + /* We should check that some rx space is free. + If not, + free one and mark stats->rx_dropped++. */ + tp->stats.rx_dropped++; + tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; + break; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP fields. */ + if (rx_size+CRC_SIZE > RX_BUF_SIZE) { + /* + int semi_count = RX_BUF_LEN - ring_offset - 4; + memcpy(skb_put(skb, semi_count), + &rx_bufs[ring_offset + 4], semi_count); + memcpy(skb_put(skb, rx_size-semi_count), + rx_bufs, rx_size - semi_count); + if (sis900_debug > 4) { + int i; + printk(KERN_DEBUG"%s: Frame wrap @%d", + dev->name, semi_count); + for (i = 0; i < 16; i++) + printk(" %2.2x", rx_bufs[i]); + printk(".\n"); + memset(rx_bufs, 0xcc, 16); + } + */ + //printk(KERN_INFO "Frame Wrap....\n"); + } else { +#if 0 /* USE_IP_COPYSUM */ + eth_copy_and_sum(skb, + tp->rx_buf[cur_rx].buf, rx_size, 0); + skb_put(skb, rx_size); +#else + memcpy(skb_put(skb, rx_size), + tp->rx_buf[cur_rx].buf, rx_size); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.rx_bytes += rx_size; +#endif + tp->stats.rx_packets++; + } + tp->rx_buf[cur_rx].cmdsts = RX_BUF_SIZE; + + cur_rx = ((cur_rx+1) % NUM_RX_DESC); + rx_status = tp->rx_buf[cur_rx].cmdsts; + //outw(cur_rx - 16, ioaddr + RxBufPtr); + } // while + if (sis900_debug > 4) + printk(KERN_INFO "%s: Done sis900_rx(), current %4.4x " + "Cmd %2.2x.\n", + dev->name, cur_rx, + inb(ioaddr + cr)); + tp->cur_rx = cur_rx; + return 0; +} + +static int +sis900_close(struct device *dev) +{ + long ioaddr = dev->base_addr; + struct sis900_private *tp = (struct sis900_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (sis900_debug > 1) + printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, inl(ioaddr + isr)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); + + /* Stop the chip's Tx and Rx DMA processes. */ + outl(0x00, ioaddr + cr); + + del_timer(&tp->timer); + + free_irq(dev->irq, dev); + + for (i = 0; i < NUM_TX_DESC; i++) { + if (tp->tx_skbuff[i]) + dev_free_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + kfree(tp->rx_bufs); + kfree(tp->tx_bufs); + + /* Green! Put the chip in low-power mode. */ + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = tp->phys[0] & 0x3f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static struct enet_statistics * +sis900_get_stats(struct device *dev) +{ + struct sis900_private *tp = (struct sis900_private *)dev->priv; + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ + +static u16 elComputeHashTableIndex(u8 *addr) +{ +#define POLYNOMIAL 0x04C11DB6L + u32 crc = 0xffffffff, msb; + int i, j; + u8 byte; + + for( i=0; i<6; i++ ) { + byte = *addr++; + for( j=0; j<8; j++ ) { + msb = crc >> 31; + crc <<= 1; + if( msb ^ ( byte & 1 )) { + crc ^= POLYNOMIAL; + crc |= 1; + } + byte >>= 1; + } + } + // 7 bit crc for 128 bit hash table + return( (int)(crc >> 25) ); +} + +static u16 elMIIpollBit(struct device *dev, + int phy_id, + int location, + u16 mask, + u16 polarity, + u16 *value) +{ + u32 i; + i=0; + while (1) { + *value = mdio_read(dev, phy_id, location); + if (polarity) { + if (mask & *value) return(TRUE); + } else { + if (mask & ~(*value)) return(TRUE); + } + if (++i == 1200) break; + } + return(FALSE); +} + +static u16 elPMDreadMode(struct device *dev, + int phy_id, + int *speed, + int *duplex) +{ + u16 status; + + *speed = HW_SPEED_10_MBPS; + *duplex = FDX_CAPABLE_HALF_SELECTED; + + status = mdio_read(dev, phy_id, MII_ANLPAR); + + if ( !( status & + (MII_NWAY_T|MII_NWAY_T_FDX | MII_NWAY_TX | MII_NWAY_TX_FDX ))) { +// printk(KERN_INFO "%s: Link Partner not detected.\n", dev->name); + while (( status = mdio_read(dev, phy_id, 18)) & 0x4000) ; + while (( status = mdio_read(dev, phy_id, 18)) & 0x0020) ; + if (status & 0x80) + *speed = HW_SPEED_100_MBPS; + if (status & 0x40) + *duplex = FDX_CAPABLE_FULL_SELECTED; + if (sis900_debug > 3) { + printk(KERN_INFO"%s: Setting %s%s-duplex.\n", + dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + } else { +// printk(KERN_INFO "%s: Link Partner detected\n", dev->name); + if (status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) { + *duplex = FDX_CAPABLE_FULL_SELECTED; + } + if (status & (MII_NWAY_TX_FDX | MII_NWAY_TX)) { + *speed = HW_SPEED_100_MBPS; + } + if (sis900_debug > 3) { + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability.\n", + dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps " : "10mbps ", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + } + } + return (status); +} + +static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed) +{ + u16 status; + + mdio_write(dev, phy_id, MII_CONTROL, 0); + mdio_write(dev, phy_id, MII_CONTROL, MIICNTL_AUTO | + MIICNTL_RST_AUTO); + elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO, FALSE,&status); + elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE, TRUE, &status); + elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK, TRUE, &status); + if (status & MIISTAT_LINK) { + elPMDreadMode(dev, phy_id, speed, duplex); + elSetMediaType(dev, *speed, *duplex); + } + return(status); +} + +static void elSetMediaType(struct device *dev, int speed, int duplex) +{ + long ioaddr = dev->base_addr; + u32 txCfgOn = 0, txCfgOff = TxDRNT; + u32 rxCfgOn = 0, rxCfgOff = 0; + + if (speed == HW_SPEED_100_MBPS) { + txCfgOn |= (TxDRNT_100 | TxHBI); + } else { + txCfgOn |= TxDRNT_10; + } + + if (duplex == FDX_CAPABLE_FULL_SELECTED) { + txCfgOn |= (TxCSI | TxHBI); + rxCfgOn |= RxATP; + } else { + txCfgOff |= (TxCSI | TxHBI); + rxCfgOff |= RxATP; + } + outl( (inl(ioaddr + txcfg) & ~txCfgOff) | txCfgOn, ioaddr + txcfg); + outl( (inl(ioaddr + rxcfg) & ~rxCfgOff) | rxCfgOn, ioaddr + rxcfg); +} + +static void set_rx_mode(struct device *dev) +{ + long ioaddr = dev->base_addr; + u16 mc_filter[8]; + int i; + int rx_mode; + u32 rxCfgOn = 0, rxCfgOff = 0; + u32 txCfgOn = 0, txCfgOff = 0; + + if (sis900_debug > 3) + printk(KERN_INFO "%s: set_rx_mode (%4.4x) done--" + "RxCfg %8.8x.\n", + dev->name, dev->flags, inl(ioaddr + rxcfg)); + + /* Note: do not reorder, GCC is clever about common statements. */ + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_PHYS; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0xffff; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0xffff; + } else { + struct dev_mc_list *mclist; + rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | + ACCEPT_CAM_QUALIFIED; + for (i=0 ; i<8 ; i++) + mc_filter[i]=0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(elComputeHashTableIndex(mclist->dmi_addr), + mc_filter); + } + + for (i=0 ; i<8 ; i++) { + outl((u32)(0x00000004+i) << 16, ioaddr + rfcr); + outl(mc_filter[i], ioaddr + rfdr); + } + /* We can safely update without stopping the chip. */ + //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS | ACCEPT_ALL_PHYS; + //rx_mode = ACCEPT_CAM_QUALIFIED | ACCEPT_ALL_BCASTS; + outl(RFEN | ((rx_mode & (ACCEPT_ALL_MCASTS | ACCEPT_ALL_BCASTS | + ACCEPT_ALL_PHYS)) << RFAA_shift), ioaddr + rfcr); + + if (rx_mode & ACCEPT_ALL_ERRORS) { + rxCfgOn = RxAEP | RxARP | RxAJAB; + } else { + rxCfgOff = RxAEP | RxARP | RxAJAB; + } + if (rx_mode & MAC_LOOPBACK) { + rxCfgOn |= RxATP; + txCfgOn |= TxMLB; + } else { + if (!(( (struct sis900_private *)(dev->priv) )->full_duplex)) + rxCfgOff |= RxATP; + txCfgOff |= TxMLB; + } + + if (sis900_debug > 2) { + printk(KERN_INFO "Before Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); + printk(KERN_INFO "Before Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); + } + + outl((inl(ioaddr + rxcfg) | rxCfgOn) & ~rxCfgOff, ioaddr + rxcfg); + outl((inl(ioaddr + txcfg) | txCfgOn) & ~txCfgOff, ioaddr + txcfg); + + if (sis900_debug > 2) { + printk(KERN_INFO "After Set TxCfg=%8.8x\n",inl(ioaddr+txcfg)); + printk(KERN_INFO "After Set RxCfg=%8.8x\n",inl(ioaddr+rxcfg)); + printk(KERN_INFO "Receive Filter Register:%8.8x\n", + inl(ioaddr + rfcr)); + } + return; +} + +static void sis900_reset(struct device *dev) +{ + long ioaddr = dev->base_addr; + + outl(0, ioaddr + ier); + outl(0, ioaddr + imr); + outl(0, ioaddr + rfcr); + + outl(RxRESET | TxRESET | RESET, ioaddr + cr); + outl(PESEL, ioaddr + cfg); + + set_rx_mode(dev); +} + +#ifdef MODULE +int init_module(void) +{ + return sis900_probe(0); +} + +void +cleanup_module(void) +{ + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_sis900_dev) { + struct sis900_private *tp = + (struct sis900_private *)root_sis900_dev->priv; + next_dev = tp->next_module; + unregister_netdev(root_sis900_dev); + release_region(root_sis900_dev->base_addr, + pci_tbl[tp->chip_id].io_size); + kfree(tp); + kfree(root_sis900_dev); + root_sis900_dev = next_dev; + } +} + +#endif /* MODULE */ +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c --- v2.2.10/linux/drivers/net/sk_mca.c Mon Jun 7 14:34:54 1999 +++ linux/drivers/net/sk_mca.c Mon Aug 9 12:05:05 1999 @@ -62,10 +62,16 @@ implemented LANCE multicast filter Jun 6th, 1999 additions for Linux 2.2 + Aug 2nd, 1999 + small fixes (David Weinehall) *************************************************************************/ +#include +#include + #include +#include #include #include #include @@ -79,11 +85,6 @@ #include #include -#ifdef MODULE -#include -#include -#endif - #include #include #include @@ -871,7 +872,7 @@ return &(priv->stat); } -/* we don't support runtime reconfiguration, since am MCA card can +/* we don't support runtime reconfiguration, since an MCA card can be unambigously identified by its POS registers. */ static int skmca_config(struct device *dev, struct ifmap *map) @@ -962,9 +963,6 @@ getaddrs(slot, junior, &base, &irq, &medium); -#if 0 - /* this should work, but it doesn't with 2.2.9 :-( - somehow 'mca_is_adapter_used()' is missing in kernel syms... */ #if LINUX_VERSION_CODE >= 0x020200 /* slot already in use ? */ @@ -973,7 +971,6 @@ slot = dofind(&junior, slot + 1); continue; } -#endif #endif /* were we looking for something different ? */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/sonic.c linux/drivers/net/sonic.c --- v2.2.10/linux/drivers/net/sonic.c Thu Jan 7 08:46:59 1999 +++ linux/drivers/net/sonic.c Mon Aug 9 12:04:39 1999 @@ -1,290 +1,23 @@ /* * sonic.c * - * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de) + * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * This driver is based on work from Andreas Busse, but most of * the code is rewritten. * * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) * - * A driver for the onboard Sonic ethernet controller on Mips Jazz - * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and - * perhaps others, too) + * Core code included by system sonic drivers */ -static const char *version = - "sonic.c:v0.10 6.7.96 tsbogend@bigbug.franken.de\n"; - /* * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook, * National Semiconductors data sheet for the DP83932B Sonic Ethernet * controller, and the files "8390.c" and "skeleton.c" in this directory. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sonic.h" - -/* use 0 for production, 1 for verification, >2 for debug */ -#ifdef SONIC_DEBUG -static unsigned int sonic_debug = SONIC_DEBUG; -#else -static unsigned int sonic_debug = 2; -#endif - -/* - * Some tunables for the buffer areas. Power of 2 is required - * the current driver uses one receive buffer for each descriptor. - */ -#define SONIC_NUM_RRS 16 /* number of receive resources */ -#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ -#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#define SONIC_RBSIZE 1520 /* size of one resource buffer */ - -#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) -/* - * Base address and interupt of the SONIC controller on JAZZ boards - */ -static struct { - unsigned int port; - unsigned int irq; - } sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}}; - - -/* Information that need to be kept for each board. */ -struct sonic_local { - sonic_cda_t cda; /* virtual CPU address of CDA */ - sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ - sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource arrea */ - sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ - struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ - unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ - unsigned char *rba; /* start of receive buffer areas */ - unsigned int cda_laddr; /* logical DMA address of CDA */ - unsigned int tda_laddr; /* logical DMA address of TDA */ - unsigned int rra_laddr; /* logical DMA address of RRA */ - unsigned int rda_laddr; /* logical DMA address of RDA */ - unsigned int rba_laddr; /* logical DMA address of RBA */ - unsigned int cur_tx, cur_rx; /* current indexes to resource areas */ - unsigned int dirty_tx,cur_rra; /* last unacked transmit packet */ - char tx_full; - struct enet_statistics stats; -}; - -/* - * We cannot use station (ethernet) address prefixes to detect the - * sonic controller since these are board manufacturer depended. - * So we check for known Silicon Revision IDs instead. - */ -static unsigned short known_revisions[] = -{ - 0x04, /* Mips Magnum 4000 */ - 0xffff /* end of list */ -}; - -/* Index to functions, as function prototypes. */ - -extern int sonic_probe(struct device *dev); -static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq); -static int sonic_open(struct device *dev); -static int sonic_send_packet(struct sk_buff *skb, struct device *dev); -static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void sonic_rx(struct device *dev); -static int sonic_close(struct device *dev); -static struct enet_statistics *sonic_get_stats(struct device *dev); -static void sonic_multicast_list(struct device *dev); -static int sonic_init(struct device *dev); - - -/* - * Probe for a SONIC ethernet controller on a Mips Jazz board. - * Actually probing is superfluous but we're paranoid. - */ -__initfunc(int sonic_probe(struct device *dev)) -{ - unsigned int base_addr = dev ? dev->base_addr : 0; - int i; - - /* - * Don't probe if we're not running on a Jazz board. - */ - if (mips_machgroup != MACH_GROUP_JAZZ) - return -ENODEV; - if (base_addr > 0x1ff) /* Check a single specified location. */ - return sonic_probe1(dev, base_addr, dev->irq); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; sonic_portlist[i].port; i++) { - int base_addr = sonic_portlist[i].port; - if (check_region(base_addr, 0x100)) - continue; - if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0) - return 0; - } - return -ENODEV; -} - -__initfunc(static int sonic_probe1(struct device *dev, - unsigned int base_addr, unsigned int irq)) -{ - static unsigned version_printed = 0; - unsigned int silicon_revision; - unsigned int val; - struct sonic_local *lp; - int i; - - /* - * get the Silicon Revision ID. If this is one of the known - * one assume that we found a SONIC ethernet controller at - * the expected location. - */ - silicon_revision = SONIC_READ(SONIC_SR); - if (sonic_debug > 1) - printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); - - i = 0; - while ((known_revisions[i] != 0xffff) && - (known_revisions[i] != silicon_revision)) - i++; - - if (known_revisions[i] == 0xffff) { - printk("SONIC ethernet controller not found (0x%4x)\n", - silicon_revision); - return -ENODEV; - } - - request_region(base_addr, 0x100, "SONIC"); - - /* Allocate a new 'dev' if needed. */ - if (dev == NULL) - dev = init_etherdev(0, sizeof(struct sonic_local)); - - if (sonic_debug && version_printed++ == 0) - printk(version); - - printk("%s: %s found at 0x%08x, ", - dev->name, "SONIC ethernet", base_addr); - - /* Fill in the 'dev' fields. */ - dev->base_addr = base_addr; - dev->irq = irq; - - /* - * Put the sonic into software reset, then - * retrieve and print the ethernet address. - */ - SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); - SONIC_WRITE(SONIC_CEP,0); - for (i=0; i<3; i++) { - val = SONIC_READ(SONIC_CAP0-i); - dev->dev_addr[i*2] = val; - dev->dev_addr[i*2+1] = val >> 8; - } - - printk("HW Address "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i<5) - printk(":"); - } - - printk(" IRQ %d\n", irq); - - /* Initialize the device structure. */ - if (dev->priv == NULL) { - /* - * the memory be located in the same 64kb segment - */ - lp = NULL; - i = 0; - do { - lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL); - if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) { - /* FIXME, free the memory later */ - kfree (lp); - lp = NULL; - } - } while (lp == NULL && i++ < 20); - - if (lp == NULL) { - printk ("%s: couldn't allocate memory for descriptors\n", - dev->name); - return -ENOMEM; - } - - memset(lp, 0, sizeof(struct sonic_local)); - - /* get the virtual dma address */ - lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp)); - if (lp->cda_laddr == ~0UL) { - printk ("%s: couldn't get DMA page entry for descriptors\n", - dev->name); - return -ENOMEM; - } - - lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); - lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); - lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); - - /* allocate receive buffer area */ - /* FIXME, maybe we should use skbs */ - if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) { - printk ("%s: couldn't allocate receive buffers\n",dev->name); - return -ENOMEM; - } - - /* get virtual dma address */ - if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) { - printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name); - return -ENOMEM; - } - - /* now convert pointer to KSEG1 pointer */ - lp->rba = (char *)KSEG1ADDR(lp->rba); - flush_cache_all(); - dev->priv = (struct sonic_local *)KSEG1ADDR(lp); - } - - lp = (struct sonic_local *)dev->priv; - dev->open = sonic_open; - dev->stop = sonic_close; - dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; - dev->set_multicast_list = &sonic_multicast_list; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - return 0; -} /* * Open/initialize the SONIC controller. @@ -308,8 +41,8 @@ * covering another bug otherwise corrupting data. This doesn't mean * this glue works ok under all situations. */ -// if (request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) { - if (request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) { +// if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) { + if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) { printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); return EAGAIN; } @@ -351,7 +84,7 @@ SONIC_WRITE(SONIC_IMR,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); - free_irq(dev->irq, dev); /* release the IRQ */ + sonic_free_irq(dev->irq, dev); /* release the IRQ */ return 0; } @@ -424,11 +157,6 @@ lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff; lp->tda[entry].tx_frag_ptr_h = laddr >> 16; lp->tda[entry].tx_frag_size = length; - - /* if there are already packets queued, allow sending several packets at once */ - if (lp->dirty_tx != lp->cur_tx) - lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS; - lp->cur_tx++; lp->stats.tx_bytes += length; @@ -479,20 +207,23 @@ if (status & SONIC_INT_TXDN) { int dirty_tx = lp->dirty_tx; - + while (dirty_tx < lp->cur_tx) { int entry = dirty_tx & SONIC_TDS_MASK; int status = lp->tda[entry].tx_status; - + if (sonic_debug > 3) printk ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n", status,lp->cur_tx,lp->dirty_tx); - - if (status == 0) - break; /* It still hasn't been Txed */ + + if (status == 0) { + /* It still hasn't been Txed, kick the sonic again */ + SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP); + break; + } /* put back EOL and free descriptor */ - lp->tda[entry].link |= SONIC_END_OF_LINKS; + lp->tda[entry].tx_frag_count = 0; lp->tda[entry].tx_status = 0; if (status & 0x0001) @@ -574,27 +305,25 @@ { unsigned int base_addr = dev->base_addr; struct sonic_local *lp = (struct sonic_local *)dev->priv; - int entry = lp->cur_rx & SONIC_RDS_MASK; + sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK]; int status; - while(lp->rda[entry].in_use == 0) - { + while (rd->in_use == 0) { struct sk_buff *skb; int pkt_len; unsigned char *pkt_ptr; - status = lp->rda[entry].rx_status; + status = rd->rx_status; if (sonic_debug > 3) - printk ("status %x, cur_rx %d, cur_rra %d\n",status,lp->cur_rx,lp->cur_rra); + printk ("status %x, cur_rx %d, cur_rra %x\n",status,lp->cur_rx,lp->cur_rra); if (status & SONIC_RCR_PRX) { - pkt_len = lp->rda[entry].rx_pktlen; - pkt_ptr = (char *)KSEG1ADDR(vdma_log2phys((lp->rda[entry].rx_pktptr_h << 16) + - lp->rda[entry].rx_pktptr_l)); + pkt_len = rd->rx_pktlen; + pkt_ptr = (char *)sonic_chiptomem((rd->rx_pktptr_h << 16) + + rd->rx_pktptr_l); if (sonic_debug > 3) - printk ("pktptr %p (rba %p) h:%x l:%x, rra h:%x l:%x bsize h:%x l:%x\n", pkt_ptr,lp->rba, - lp->rda[entry].rx_pktptr_h,lp->rda[entry].rx_pktptr_l, - lp->rra[lp->cur_rra & 15].rx_bufadr_h,lp->rra[lp->cur_rra & 15].rx_bufadr_l, + printk ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", pkt_ptr,lp->rba, + rd->rx_pktptr_h,rd->rx_pktptr_l, SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0)); /* Malloc up new buffer. */ @@ -620,21 +349,26 @@ if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++; } - lp->rda[entry].in_use = 1; - entry = (++lp->cur_rx) & SONIC_RDS_MASK; + rd->in_use = 1; + rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK]; /* now give back the buffer to the receive buffer area */ if (status & SONIC_RCR_LPKT) { /* * this was the last packet out of the current receice buffer * give the buffer back to the SONIC */ - SONIC_WRITE(SONIC_RWP,(lp->rra_laddr + (++lp->cur_rra & 15) * sizeof(sonic_rr_t)) & 0xffff); - } + lp->cur_rra += sizeof(sonic_rr_t); + if (lp->cur_rra > (lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t))) + lp->cur_rra = lp->rra_laddr; + SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff); + } else + printk ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",dev->name); } - - /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(NET_BH) for us and will work on them - when we get to the bottom-half routine. */ + /* + * If any worth-while packets have been received, dev_rint() + * has done a mark_bh(NET_BH) for us and will work on them + * when we get to the bottom-half routine. + */ return; } @@ -689,16 +423,15 @@ for (i = 1; i <= dev->mc_count; i++) { addr = dmi->dmi_addr; dmi = dmi->next; - lp->cda.cam_desc[i].cam_frag2 = addr[1] << 8 | addr[0]; - lp->cda.cam_desc[i].cam_frag1 = addr[3] << 8 | addr[2]; - lp->cda.cam_desc[i].cam_frag0 = addr[5] << 8 | addr[4]; + lp->cda.cam_desc[i].cam_cap0 = addr[1] << 8 | addr[0]; + lp->cda.cam_desc[i].cam_cap1 = addr[3] << 8 | addr[2]; + lp->cda.cam_desc[i].cam_cap2 = addr[5] << 8 | addr[4]; lp->cda.cam_enable |= (1 << i); } - /* number of CAM entries to load */ - SONIC_WRITE(SONIC_CDC,dev->mc_count+1); + SONIC_WRITE(SONIC_CDC,16); /* issue Load CAM command */ SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff); - SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM); + SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM); } } @@ -736,7 +469,6 @@ SONIC_WRITE(SONIC_CMD,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RXDIS); - /* * initialize the receive resource area */ @@ -761,7 +493,7 @@ SONIC_WRITE(SONIC_URRA,lp->rra_laddr >> 16); SONIC_WRITE(SONIC_EOBC,(SONIC_RBSIZE-2) >> 1); - lp->cur_rra = SONIC_NUM_RRS - 2; + lp->cur_rra = lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t); /* load the resource pointers */ if (sonic_debug > 3) @@ -796,7 +528,6 @@ /* fix last descriptor */ lp->rda[SONIC_NUM_RDS-1].link = lp->rda_laddr; lp->cur_rx = 0; - SONIC_WRITE(SONIC_URDA,lp->rda_laddr >> 16); SONIC_WRITE(SONIC_CRDA,lp->rda_laddr & 0xffff); @@ -816,13 +547,14 @@ SONIC_WRITE(SONIC_UTDA,lp->tda_laddr >> 16); SONIC_WRITE(SONIC_CTDA,lp->tda_laddr & 0xffff); + lp->cur_tx = lp->dirty_tx = 0; /* * put our own address to CAM desc[0] */ - lp->cda.cam_desc[0].cam_frag2 = dev->dev_addr[1] << 8 | dev->dev_addr[0]; - lp->cda.cam_desc[0].cam_frag1 = dev->dev_addr[3] << 8 | dev->dev_addr[2]; - lp->cda.cam_desc[0].cam_frag0 = dev->dev_addr[5] << 8 | dev->dev_addr[4]; + lp->cda.cam_desc[0].cam_cap0 = dev->dev_addr[1] << 8 | dev->dev_addr[0]; + lp->cda.cam_desc[0].cam_cap1 = dev->dev_addr[3] << 8 | dev->dev_addr[2]; + lp->cda.cam_desc[0].cam_cap2 = dev->dev_addr[5] << 8 | dev->dev_addr[4]; lp->cda.cam_enable = 1; for (i=0; i < 16; i++) @@ -832,7 +564,7 @@ * initialize CAM registers */ SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff); - SONIC_WRITE(SONIC_CDC,1); + SONIC_WRITE(SONIC_CDC,16); /* * load the CAM diff -u --recursive --new-file v2.2.10/linux/drivers/net/sonic.h linux/drivers/net/sonic.h --- v2.2.10/linux/drivers/net/sonic.h Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/sonic.h Mon Aug 9 12:04:39 1999 @@ -15,16 +15,6 @@ #define SONIC_H /* - * Macros to access SONIC registers - */ -#define SONIC_READ(reg) \ - *((volatile unsigned int *)base_addr+reg) - -#define SONIC_WRITE(reg,val) \ - *((volatile unsigned int *)base_addr+reg) = val - - -/* * SONIC register offsets */ @@ -242,9 +232,9 @@ typedef struct { u16 rx_status; /* status after reception of a packet */ - u16 pad0; + SREGS_PAD(pad0); u16 rx_pktlen; /* length of the packet incl. CRC */ - u16 pad1; + SREGS_PAD(pad1); /* * Pointers to the location in the receive buffer area (RBA) @@ -252,22 +242,22 @@ * a contiguous piece of memory. */ u16 rx_pktptr_l; - u16 pad2; + SREGS_PAD(pad2); u16 rx_pktptr_h; - u16 pad3; + SREGS_PAD(pad3); u16 rx_seqno; /* sequence no. */ - u16 pad4; + SREGS_PAD(pad4); u16 link; /* link to next RDD (end if EOL bit set) */ - u16 pad5; + SREGS_PAD(pad5); /* * Owner of this descriptor, 0= driver, 1=sonic */ u16 in_use; - u16 pad6; + SREGS_PAD(pad6); caddr_t rda_next; /* pointer to next RD */ } sonic_rd_t; @@ -278,23 +268,23 @@ */ typedef struct { u16 tx_status; /* status after transmission of a packet */ - u16 pad0; + SREGS_PAD(pad0); u16 tx_config; /* transmit configuration for this packet */ - u16 pad1; + SREGS_PAD(pad1); u16 tx_pktsize; /* size of the packet to be transmitted */ - u16 pad2; + SREGS_PAD(pad2); u16 tx_frag_count; /* no. of fragments */ - u16 pad3; + SREGS_PAD(pad3); u16 tx_frag_ptr_l; - u16 pad4; + SREGS_PAD(pad4); u16 tx_frag_ptr_h; - u16 pad5; + SREGS_PAD(pad5); u16 tx_frag_size; - u16 pad6; + SREGS_PAD(pad6); u16 link; /* ptr to next descriptor */ - u16 pad7; + SREGS_PAD(pad7); } sonic_td_t; @@ -304,13 +294,13 @@ typedef struct { u16 cam_entry_pointer; - u16 pad; - u16 cam_frag2; - u16 pad2; - u16 cam_frag1; - u16 pad1; - u16 cam_frag0; - u16 pad0; + SREGS_PAD(pad0); + u16 cam_cap0; + SREGS_PAD(pad1); + u16 cam_cap1; + SREGS_PAD(pad2); + u16 cam_cap2; + SREGS_PAD(pad3); } sonic_cd_t; #define CAM_DESCRIPTORS 16 @@ -319,8 +309,56 @@ typedef struct { sonic_cd_t cam_desc[CAM_DESCRIPTORS]; u16 cam_enable; - u16 pad; + SREGS_PAD(pad); } sonic_cda_t; +/* + * Some tunables for the buffer areas. Power of 2 is required + * the current driver uses one receive buffer for each descriptor. + */ +#define SONIC_NUM_RRS 16 /* number of receive resources */ +#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ +#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ +#define SONIC_RBSIZE 1520 /* size of one resource buffer */ + +#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) + + +/* Information that need to be kept for each board. */ +struct sonic_local { + sonic_cda_t cda; /* virtual CPU address of CDA */ + sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ + sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource arrea */ + sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ + struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ + unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ + unsigned char *rba; /* start of receive buffer areas */ + unsigned int cda_laddr; /* logical DMA address of CDA */ + unsigned int tda_laddr; /* logical DMA address of TDA */ + unsigned int rra_laddr; /* logical DMA address of RRA */ + unsigned int rda_laddr; /* logical DMA address of RDA */ + unsigned int rba_laddr; /* logical DMA address of RBA */ + unsigned int cur_rra; /* current indexes to resource areas */ + unsigned int cur_rx; + unsigned int cur_tx; + unsigned int dirty_tx; /* last unacked transmit packet */ + char tx_full; + struct enet_statistics stats; +}; + +/* Index to functions, as function prototypes. */ + +static int sonic_open(struct device *dev); +static int sonic_send_packet(struct sk_buff *skb, struct device *dev); +static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void sonic_rx(struct device *dev); +static int sonic_close(struct device *dev); +static struct enet_statistics *sonic_get_stats(struct device *dev); +static void sonic_multicast_list(struct device *dev); +static int sonic_init(struct device *dev); + +static const char *version = + "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n"; #endif /* SONIC_H */ diff -u --recursive --new-file v2.2.10/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.2.10/linux/drivers/net/sunhme.c Sat May 29 11:10:15 1999 +++ linux/drivers/net/sunhme.c Mon Aug 9 12:05:45 1999 @@ -3406,7 +3406,16 @@ /* Set the latency timer and cache line size as well, * PROM leaves it at zero. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + { + unsigned char min_gnt, latency_timer; + + pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt); + if (min_gnt == 0) + latency_timer = 64; + else + latency_timer = ((min_gnt << 3) & 0xff); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer); + } #ifdef __sparc_v9__ /* NOTE: Cache line size is in 32-bit word units. */ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); diff -u --recursive --new-file v2.2.10/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.2.10/linux/drivers/net/syncppp.c Fri Apr 16 13:58:46 1999 +++ linux/drivers/net/syncppp.c Mon Aug 9 12:04:39 1999 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "syncppp.h" @@ -771,7 +772,7 @@ } sp->obytes += skb->len; /* Control is high priority so it doesnt get queued behind data */ - skb->priority=1; + skb->priority=TC_PRIO_CONTROL; skb->dev = dev; dev_queue_xmit(skb); } @@ -813,7 +814,7 @@ dev->name, ntohl (ch->type), ch->par1, ch->par2, ch->rel, ch->time0, ch->time1); sp->obytes += skb->len; - skb->priority=1; + skb->priority=TC_PRIO_CONTROL; skb->dev = dev; dev_queue_xmit(skb); } diff -u --recursive --new-file v2.2.10/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.2.10/linux/drivers/net/tulip.c Tue Jan 19 13:18:45 1999 +++ linux/drivers/net/tulip.c Mon Aug 9 12:04:39 1999 @@ -327,6 +327,10 @@ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, }; +enum desc_status_bits { + DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, +}; + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -2698,8 +2702,8 @@ /* Same setup recently queued, we need not add it. */ } else { unsigned long flags; - unsigned int entry; - + unsigned int entry, dummy = 0; + save_flags(flags); cli(); entry = tp->cur_tx++ % TX_RING_SIZE; @@ -2709,7 +2713,8 @@ tp->tx_ring[entry].length = (entry == TX_RING_SIZE-1) ? 0x02000000 : 0; tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = 0x80000000; + /* race with chip, set DescOwned later */ + dummy = entry; entry = tp->cur_tx++ % TX_RING_SIZE; } @@ -2724,6 +2729,8 @@ dev->tbusy = 1; tp->tx_full = 1; } + if (dummy >= 0) + tp->tx_ring[dummy].status = DescOwned; restore_flags(flags); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); diff -u --recursive --new-file v2.2.10/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.2.10/linux/drivers/net/via-rhine.c Mon May 10 13:00:10 1999 +++ linux/drivers/net/via-rhine.c Mon Aug 9 12:04:57 1999 @@ -1,6 +1,6 @@ /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */ /* - Written 1998 by Donald Becker. + Written 1998-1999 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License (GPL), incorporated herein by reference. @@ -20,7 +20,7 @@ */ static const char *versionA = -"via-rhine.c:v1.00 9/5/98 Written by Donald Becker\n"; +"via-rhine.c:v1.01 2/27/99 Written by Donald Becker\n"; static const char *versionB = " http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; @@ -81,9 +81,14 @@ #include #include -/* This driver was written to use PCI memory space, however some boards - only work with I/O space accesses. */ +/* This driver was written to use PCI memory space, however some x86 + motherboards only configure I/O space accesses correctly. */ +#if defined(__i386__) && !defined(VIA_USE_MEMORY) #define VIA_USE_IO +#endif +#if defined(__alpha__) +#define VIA_USE_IO +#endif #ifdef VIA_USE_IO #undef readb #undef readw @@ -105,6 +110,7 @@ #define RUN_AT(x) (jiffies + (x)) #if (LINUX_VERSION_CODE >= 0x20100) +char kernel_version[] = UTS_RELEASE; #else #ifndef __alpha__ #define ioremap vremap @@ -502,6 +508,7 @@ #ifndef MODULE int via_rhine_probe(struct device *dev) { + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); return pci_etherdev_probe(dev, pci_tbl); } #endif @@ -510,13 +517,9 @@ struct device *dev, long ioaddr, int irq, int chip_id, int card_idx) { - static int did_version = 0; /* Already printed version info */ struct netdev_private *np; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - if (debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - dev = init_etherdev(dev, 0); printk(KERN_INFO "%s: %s at 0x%lx, ", @@ -685,6 +688,8 @@ ioaddr + IntrEnable); np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; + if (np->duplex_lock) + np->chip_cmd |= CmdFDuplex; writew(np->chip_cmd, ioaddr + ChipCmd); check_duplex(dev); @@ -1053,7 +1058,6 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - np->stats.rx_bytes += pkt_len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -1182,7 +1186,7 @@ } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - rx_mode = 0x0C; + rx_mode = 0x08; } writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); } diff -u --recursive --new-file v2.2.10/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.2.10/linux/drivers/net/wavelan.c Thu Apr 29 11:53:41 1999 +++ linux/drivers/net/wavelan.c Mon Aug 9 12:04:57 1999 @@ -1616,11 +1616,8 @@ if((frequency->e == 0) && (frequency->m >= 0) && (frequency->m < BAND_NUM)) { - /* frequency in units of 250 kHz (as read in the offset register) */ - short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 }; - /* Get frequency offset. */ - freq = bands[frequency->m] >> 1; + freq = channel_bands[frequency->m] >> 1; } /* Verify that the frequency is allowed. */ @@ -1791,6 +1788,7 @@ u_short table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ + int c = 0; /* Channel number */ /* Read the frequency table. */ fee_read(ioaddr, 0x71 /* frequency table */, table, 10); @@ -1801,6 +1799,12 @@ /* Look in the table if the frequency is allowed */ if(table[9 - (freq / 16)] & (1 << (freq % 16))) { + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < NELS(channel_bands))) + c++; + list[i].i = c; /* Set the list index */ + /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; list[i++].e = 1; @@ -1969,14 +1973,12 @@ } else { - int bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa, (unsigned char *)&psa.psa_subband, 1); if(psa.psa_subband <= 4) { - wrq->u.freq.m = bands[psa.psa_subband]; + wrq->u.freq.m = fixed_bands[psa.psa_subband]; wrq->u.freq.e = (psa.psa_subband != 0); } else @@ -1986,9 +1988,9 @@ case SIOCSIWSENS: /* Set the level threshold. */ - if(!suser()) - return -EPERM; - psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); /* update the Wavelan checksum */ @@ -2000,7 +2002,8 @@ /* Read the level threshold. */ psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, (unsigned char *) &psa.psa_thr_pre_set, 1); - wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; break; case SIOCSIWENCODE: @@ -2087,12 +2090,6 @@ { struct iw_range range; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(struct iw_range)); - if(ret) - break; - /* Set the length (useless: it's constant). */ wrq->u.data.length = sizeof(struct iw_range); @@ -2117,9 +2114,12 @@ range.max_qual.level = MMR_SIGNAL_LVL; range.max_qual.noise = MMR_SILENCE_LVL; + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ + /* Copy structure to the user buffer. */ - copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range)); + if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) + ret = -EFAULT; } break; @@ -2136,18 +2136,12 @@ { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, }; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(priv)); - if(ret) - break; - /* Set the number of available ioctls. */ wrq->u.data.length = 4; /* Copy structure to the user buffer. */ - copy_to_user(wrq->u.data.pointer, (u_char *) priv, - sizeof(priv)); + if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv))) + ret = -EFAULT; } break; @@ -2169,14 +2163,11 @@ struct sockaddr address[IW_MAX_SPY]; int i; - /* Verify where the user has set his addresses. */ - ret = verify_area(VERIFY_READ, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number); - if(ret) - break; /* Copy addresses to the driver. */ - copy_from_user(address, wrq->u.data.pointer, - sizeof(struct sockaddr) * lp->spy_number); + if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } /* Copy addresses to the lp structure. */ for(i = 0; i < lp->spy_number; i++) @@ -2215,13 +2206,6 @@ struct sockaddr address[IW_MAX_SPY]; int i; - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - (sizeof(iw_qual) + sizeof(struct sockaddr)) - * IW_MAX_SPY); - if(ret) - break; - /* Copy addresses from the lp structure. */ for(i = 0; i < lp->spy_number; i++) { @@ -2231,13 +2215,18 @@ } /* Copy addresses to the user buffer. */ - copy_to_user(wrq->u.data.pointer, address, - sizeof(struct sockaddr) * lp->spy_number); - + if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } + /* Copy stats to the user buffer (just after). */ - copy_to_user(wrq->u.data.pointer + + if (copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number); + lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) { + ret = -EFAULT; + break; + } /* Reset updated flags. */ for(i = 0; i < lp->spy_number; i++) @@ -2283,14 +2272,11 @@ /* Are there addresses to copy? */ if(lp->his_number > 0) { - /* Verify where the user has set his addresses. */ - ret = verify_area(VERIFY_READ, wrq->u.data.pointer, - sizeof(char) * lp->his_number); - if(ret) - break; /* Copy interval ranges to the driver */ - copy_from_user(lp->his_range, wrq->u.data.pointer, - sizeof(char) * lp->his_number); + if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) { + ret = -EFAULT; + break; + } /* Reset structure. */ memset(lp->his_sum, 0x00, sizeof(long) * 16); @@ -2304,15 +2290,10 @@ /* Give back the distribution statistics */ if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) { - /* Verify the user buffer. */ - ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, - sizeof(long) * 16); - if(ret) - break; - /* Copy data to the user buffer. */ - copy_to_user(wrq->u.data.pointer, lp->his_sum, - sizeof(long) * lp->his_number); + if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number)) + ret = -EFAULT; + } /* if(pointer != NULL) */ break; #endif /* HISTOGRAM */ @@ -4265,6 +4246,11 @@ /* Create device and set basic arguments. */ dev = kmalloc(sizeof(struct device), GFP_KERNEL); + if(dev==NULL) + { + ret = -ENOMEM; + break; + } memset(dev, 0x00, sizeof(struct device)); dev->name = name[i]; dev->base_addr = io[i]; diff -u --recursive --new-file v2.2.10/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h --- v2.2.10/linux/drivers/net/wavelan.h Wed Mar 10 16:51:35 1999 +++ linux/drivers/net/wavelan.h Mon Aug 9 12:04:57 1999 @@ -19,6 +19,8 @@ #ifndef _WAVELAN_H #define _WAVELAN_H +/************************** MAGIC NUMBERS ***************************/ + /* Detection of the WaveLAN card is done by reading the MAC * address from the card and checking it. If you have a non-AT&T * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), @@ -38,6 +40,25 @@ #define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ #define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + /*************************** PC INTERFACE ****************************/ diff -u --recursive --new-file v2.2.10/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.2.10/linux/drivers/net/wavelan.p.h Thu Apr 29 11:53:41 1999 +++ linux/drivers/net/wavelan.p.h Mon Aug 9 12:04:57 1999 @@ -32,7 +32,7 @@ * Web page * -------- * I try to maintain a web page with the Wireless LAN Howto at : - * http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * * Debugging and options * --------------------- @@ -164,7 +164,7 @@ * Marc Meertens , * Pauline Middelink , * Robert Morris , - * Jean Tourrilhes , + * Jean Tourrilhes , * Girish Welling , * Clark Woodworth * Yongguang Zhang @@ -292,9 +292,17 @@ * - Rectify a lot of (useless) debugging code * - Change the way to `#ifdef SET_PSA_CRC' * + * Changes made for release in 2.2.11 & 2.3.13 : + * ------------------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * * Wishes & dreams: * ---------------- - * - roaming + * - roaming (see Pcmcia driver) */ /***************************** INCLUDES *****************************/ @@ -382,11 +390,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v19 (wireless extensions) 20/4/99\n"; +static const char *version = "wavelan.c : v20 (wireless extensions) 29/7/99\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES 256 /* TODO: express in HZ. */ +#define WATCHDOG_JIFFIES (256*HZ/100) /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) diff -u --recursive --new-file v2.2.10/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.2.10/linux/drivers/net/yellowfin.c Fri Dec 18 09:45:17 1998 +++ linux/drivers/net/yellowfin.c Mon Aug 9 12:04:39 1999 @@ -76,6 +76,7 @@ #include #include /* Processor type for cache alignment. */ #include +#include #include #include @@ -1054,7 +1055,7 @@ u16 desc_status = desc->status; int data_size = desc->request_cnt - desc->result_cnt; u8 *buf_addr = bus_to_virt(desc->addr); - s16 frame_status = *(s16*)&(buf_addr[data_size - 2]); /* ?Alpha safe on 885? */ + s16 frame_status = get_unaligned((s16*)(buf_addr+data_size-2)); if (yellowfin_debug > 4) printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n", diff -u --recursive --new-file v2.2.10/linux/drivers/net/z85230.c linux/drivers/net/z85230.c --- v2.2.10/linux/drivers/net/z85230.c Sat Apr 24 17:51:48 1999 +++ linux/drivers/net/z85230.c Mon Aug 9 12:04:39 1999 @@ -187,7 +187,6 @@ 1, EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx, 9, NV|MIE|NORESET, 23, 3, /* Extended mode AUTO TX and EOM*/ - 31, 3, /* Extended mode AUTO TX and EOM*/ 255 }; @@ -673,6 +672,7 @@ { kfree(c->rx_buf[0]); c->rx_buf[0]=NULL; + c->rx_buf[1]=NULL; return -ENOBUFS; } @@ -834,6 +834,8 @@ int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c) { + unsigned long flags; + printk("Opening sync interface for TX-DMA\n"); c->sync = 1; c->mtu = dev->mtu+64; @@ -889,14 +891,21 @@ c->regs[R14]|= DTRREQ; write_zsreg(c, R14, c->regs[R14]); + c->regs[R1]&= ~TxINT_ENAB; + write_zsreg(c, R1, c->regs[R1]); + /* * Set up the DMA configuration */ + flags = claim_dma_lock(); + disable_dma(c->txdma); clear_dma_ff(c->txdma); set_dma_mode(c->txdma, DMA_MODE_WRITE); disable_dma(c->txdma); + + release_dma_lock(flags); /* * Select the DMA interrupt handlers @@ -918,6 +927,7 @@ int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c) { + unsigned long flags; u8 chk; c->irqs = &z8530_nop; c->max = 0; @@ -927,10 +937,14 @@ * Disable the PC DMA channels */ + flags = claim_dma_lock(); + disable_dma(c->txdma); clear_dma_ff(c->txdma); c->txdma_on = 0; c->tx_dma_used = 0; + + release_dma_lock(flags); /* * Disable DMA control mode diff -u --recursive --new-file v2.2.10/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.2.10/linux/drivers/pci/oldproc.c Wed Jun 9 16:59:34 1999 +++ linux/drivers/pci/oldproc.c Mon Aug 9 12:04:39 1999 @@ -103,6 +103,7 @@ DEVICE( DEC, DEC_21152, "DC21152"), DEVICE( DEC, DEC_21153, "DC21153"), DEVICE( DEC, DEC_21154, "DC21154"), + DEVICE( DEC, DEC_21285, "DC21285 Footbridge"), DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"), DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"), @@ -222,6 +223,9 @@ DEVICE( X, X_AGX016, "ITT AGX016"), DEVICE( PICOP, PICOP_PT86C52X, "PT86C52x Vesuvius"), DEVICE( PICOP, PICOP_PT80C524, "PT80C524 Nile"), + DEVICE( MYLEX, MYLEX_DAC960P_V2,"DAC960P V2"), + DEVICE( MYLEX, MYLEX_DAC960P_V3,"DAC960P V3"), + DEVICE( MYLEX, MYLEX_DAC960P_V4,"DAC960P V4"), DEVICE( APPLE, APPLE_BANDIT, "Bandit"), DEVICE( APPLE, APPLE_GC, "Grand Central"), DEVICE( APPLE, APPLE_HYDRA, "Hydra"), @@ -303,6 +307,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 +465,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"), @@ -498,11 +504,13 @@ DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"), DEVICE( S3, S3_SONICVIBES, "SonicVibes"), DEVICE( DCI, DCI_PCCOM4, "PC COM PCI Bus 4 port serial Adapter"), + DEVICE( GENROCO, GENROCO_HFP832, "TURBOstor HFP832"), DEVICE( INTEL, INTEL_82375, "82375EB"), DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"), DEVICE( INTEL, INTEL_82378, "82378IB"), DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), DEVICE( INTEL, INTEL_82434, "82434LX Mercury/Neptune"), + DEVICE( INTEL, INTEL_I960, "i960"), DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"), DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"), DEVICE( INTEL, INTEL_7116, "SAA7116"), @@ -536,6 +544,7 @@ DEVICE( KTI, KTI_ET32P2, "ET32P2"), DEVICE( ADAPTEC, ADAPTEC_7810, "AIC-7810 RAID"), DEVICE( ADAPTEC, ADAPTEC_7821, "AIC-7860"), + DEVICE( ADAPTEC, ADAPTEC_38602, "AIC-7860"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), @@ -627,8 +636,8 @@ case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller"; case PCI_CLASS_STORAGE_IDE: return "IDE interface"; case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; - case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; - case PCI_CLASS_STORAGE_RAID: return "RAID bus controller"; + case PCI_CLASS_STORAGE_IPI: return "IPI storage controller"; + case PCI_CLASS_STORAGE_RAID: return "RAID storage controller"; case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller"; case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller"; @@ -736,6 +745,7 @@ case PCI_VENDOR_ID_N9: return "Number Nine"; case PCI_VENDOR_ID_UMC: return "UMC"; case PCI_VENDOR_ID_X: return "X TECHNOLOGY"; + case PCI_VENDOR_ID_MYLEX: return "Mylex"; case PCI_VENDOR_ID_PICOP: return "PicoPower"; case PCI_VENDOR_ID_APPLE: return "Apple"; case PCI_VENDOR_ID_NEXGEN: return "Nexgen"; @@ -826,6 +836,7 @@ case PCI_VENDOR_ID_NETVIN: return "NetVin"; case PCI_VENDOR_ID_S3: return "S3 Inc."; case PCI_VENDOR_ID_DCI: return "Decision Computer Int."; + case PCI_VENDOR_ID_GENROCO: return "Genroco"; case PCI_VENDOR_ID_INTEL: return "Intel"; case PCI_VENDOR_ID_KTI: return "KTI"; case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; diff -u --recursive --new-file v2.2.10/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.2.10/linux/drivers/pci/pci.c Sun Mar 7 15:19:55 1999 +++ linux/drivers/pci/pci.c Mon Aug 9 12:04:39 1999 @@ -184,6 +184,11 @@ } dev = kmalloc(sizeof(*dev), GFP_ATOMIC); + if(dev==NULL) + { + printk(KERN_ERR "pci: out of memory.\n"); + continue; + } memset(dev, 0, sizeof(*dev)); dev->bus = bus; dev->devfn = devfn; @@ -292,6 +297,11 @@ * Insert it into the tree of buses. */ child = kmalloc(sizeof(*child), GFP_ATOMIC); + if(child==NULL) + { + printk(KERN_ERR "pci: out of memory for bridge.\n"); + continue; + } memset(child, 0, sizeof(*child)); child->next = bus->children; bus->children = child; diff -u --recursive --new-file v2.2.10/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.2.10/linux/drivers/sbus/audio/audio.c Thu Apr 22 19:24:51 1999 +++ linux/drivers/sbus/audio/audio.c Mon Aug 9 12:05:13 1999 @@ -117,6 +117,13 @@ * TODO: Make number of input/output buffers tunable parameters */ +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x202ff + init_waitqueue_head(&drv->open_wait); + init_waitqueue_head(&drv->output_write_wait); + init_waitqueue_head(&drv->output_drain_wait); + init_waitqueue_head(&drv->input_read_wait); +#endif + drv->num_output_buffers = 8; drv->output_buffer_size = (4096 * 2); drv->playing_count = 0; @@ -264,6 +271,7 @@ * If status & 2, a buffer was claimed for DMA and is still in use. * * The playing_count for non-DMA hardware should never be non-zero. + * Value of status for non-DMA hardware should always be 1. */ if (status & 1) { if (drv->playing_count) @@ -300,8 +308,9 @@ /* If we got back a buffer, see if anyone wants to write to it */ if ((status & 1) || ((drv->output_count + drv->playing_count) - < drv->num_output_buffers)) + < drv->num_output_buffers)) { wake_up_interruptible(&drv->output_write_wait); + } /* If the output queue is empty, shut down the driver. */ if ((drv->output_count < 1) && (drv->playing_count < 1)) { @@ -664,7 +673,7 @@ case SOUND_MIXER_WRITE_CD: case SOUND_MIXER_WRITE_LINE: case SOUND_MIXER_WRITE_IMIX: - if(get_user(k, arg)) + if(COPY_IN(arg, k)) return -EFAULT; tprintk(("setting input volume (0x%x)", k)); if (drv->ops->get_input_channels) @@ -695,7 +704,7 @@ case SOUND_MIXER_WRITE_PCM: case SOUND_MIXER_WRITE_VOLUME: case SOUND_MIXER_WRITE_SPEAKER: - if(get_user(k, arg)) + if(COPY_IN(arg, k)) return -EFAULT; tprintk(("setting output volume (0x%x)", k)); if (drv->ops->get_output_channels) @@ -736,7 +745,7 @@ case SOUND_MIXER_WRITE_RECSRC: if (!drv->ops->set_input_port) return -EINVAL; - if(get_user(k, arg)) + if(COPY_IN(arg, k)) return -EFAULT; /* only one should ever be selected */ if (k & SOUND_MASK_IMIX) j = AUDIO_ANALOG_LOOPBACK; diff -u --recursive --new-file v2.2.10/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.2.10/linux/drivers/sbus/audio/cs4231.c Wed Apr 28 08:47:39 1999 +++ linux/drivers/sbus/audio/cs4231.c Mon Aug 9 12:05:13 1999 @@ -1,7 +1,9 @@ /* * drivers/sbus/audio/cs4231.c * - * Copyright 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) + * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) + * The 4231/ebus support was written by David Miller, who didn't bother + * crediting himself here, so I will. * * Based on the AMD7930 driver: * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) @@ -11,7 +13,7 @@ * * This was culled from the Crystal docs on the 4231a, and the addendum they * faxed me on the 4231. - * The APC DMA controller support unfortunately is not documented. Thanks, Sun + * The APC DMA controller support unfortunately is not documented. Thanks, Sun. */ #include @@ -69,15 +71,17 @@ static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, unsigned char balance); static void cs4231_ready(struct sparcaudio_driver *drv); -static void cs4231_playintr(struct sparcaudio_driver *drv); +static void cs4231_playintr(struct sparcaudio_driver *drv, int); static int cs4231_recintr(struct sparcaudio_driver *drv); static int cs4231_output_muted(struct sparcaudio_driver *drv, int value); static void cs4231_pollinput(struct sparcaudio_driver *drv); -static void eb4231_pollinput(struct sparcaudio_driver *drv); static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir, unsigned int length); static void cs4231_getsamplecount(struct sparcaudio_driver *drv, unsigned int length, unsigned int value); +#ifdef EB4231_SUPPORT +static void eb4231_pollinput(struct sparcaudio_driver *drv); +#endif #define CHIP_READY udelay(100); cs4231_ready(drv); udelay(1000); @@ -1228,11 +1232,20 @@ MOD_DEC_USE_COUNT; } -static void cs4231_playintr(struct sparcaudio_driver *drv) +static void cs4231_playintr(struct sparcaudio_driver *drv, int push) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int status = 0; + if (!push) { + if (!cs4231_chip->perchip_info.play.active) { + cs4231_chip->regs->dmapnva = cs4231_chip->output_next_dma_handle; + cs4231_chip->regs->dmapnc = cs4231_chip->output_next_dma_size; + } + sparcaudio_output_done(drv, 0); + return; + } + if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) cs4231_chip->playlen = cs4231_chip->output_size; @@ -1421,7 +1434,7 @@ status += 2; } - sparcaudio_input_done(drv, 1); + sparcaudio_input_done(drv, status); return 1; } @@ -1489,21 +1502,20 @@ cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY; cs4231_chip->regs->dmacsr &= ~APC_PPAUSE; - cs4231_playintr(drv); + cs4231_playintr(drv, cs4231_chip->regs->dmapnva == 0 ? 1 : 0); cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP; cs4231_enable_play(drv); cs4231_ready(drv); - } else - cs4231_playintr(drv); + } } #ifdef EB4231_SUPPORT static void eb4231_stop_output(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - int dcsr; + unsigned int dcsr; dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n", readl(&cs4231_chip->eb2p->dcsr), @@ -1635,6 +1647,68 @@ cs4231_pollinput(drv); } +#ifdef EB4231_SUPPORT +static void eb4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, + unsigned long count) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dcsr; + + cs4231_chip->input_ptr = buffer; + cs4231_chip->input_size = count; + + if (cs4231_chip->perchip_info.record.active || + (cs4231_chip->perchip_info.record.pause)) + return; + + cs4231_ready(drv); + + cs4231_chip->perchip_info.record.active = 1; + cs4231_chip->recording_count = 0; + + dcsr = readl(&cs4231_chip->eb2c->dcsr); + if (!(dcsr & EBUS_DCSR_EN_DMA)) { + writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2c->dcsr)); + writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2c->dcsr)); + + eb4231_recintr(drv); + + writel(EBUS_DCSR_BURST_SZ_16 | + (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT), + &(cs4231_chip->eb2c->dcsr)); + + cs4231_enable_rec(drv); + cs4231_ready(drv); + } else + eb4231_recintr(drv); +} + +static void eb4231_stop_input(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dcsr; + + cs4231_chip->perchip_info.record.active = 0; + + cs4231_chip->input_ptr = NULL; + cs4231_chip->input_size = 0; + if (cs4231_chip->input_dma_handle) { + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + } + if (cs4231_chip->input_next_dma_handle) { + cs4231_chip->input_next_dma_handle = 0; + cs4231_chip->input_next_dma_size = 0; + } + + dcsr = readl(&(cs4231_chip->eb2c->dcsr)); + if (dcsr & EBUS_DCSR_EN_DMA) + writel(dcsr & ~EBUS_DCSR_EN_DMA, &(cs4231_chip->eb2c->dcsr)); + + cs4231_disable_rec(drv); +} +#endif + static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; @@ -1763,13 +1837,25 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int dummy; - /* Read status. */ - dummy = readl(&cs4231_chip->eb2c->dcsr); + /* Clear the interrupt. */ + dummy = readl(&(cs4231_chip->eb2c->dcsr)); + writel(dummy, &(cs4231_chip->eb2c->dcsr)); - cs4231_chip->perchip_info.record.samples += - cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), - cs4231_chip->reclen); - eb4231_recintr(drv); + if ((dummy & EBUS_DCSR_TC) != 0 + /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) { + cs4231_chip->perchip_info.record.samples += + cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), + cs4231_chip->reclen); + eb4231_recintr(drv); + } + + if ((dummy & EBUS_DCSR_A_LOADED) == 0) { + cs4231_chip->perchip_info.record.active = 0; + eb4231_recintr(drv); +#if 1 + eb4231_getsamplecount(drv, cs4231_chip->reclen, 1); +#endif + } } /* ebus audio play interrupt handler. */ @@ -1827,7 +1913,8 @@ cs4231_chip->perchip_info.play.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), cs4231_chip->playlen); - cs4231_playintr(drv); + if (!(dummy & APC_XINT_EMPT)) + cs4231_playintr(drv, 1); } /* Any other conditions we need worry about? */ } @@ -1859,7 +1946,7 @@ cs4231_chip->perchip_info.play.error = 1; } cs4231_chip->perchip_info.play.active = 0; - cs4231_playintr(drv); + cs4231_playintr(drv, 0); cs4231_getsamplecount(drv, cs4231_chip->playlen, 0); } @@ -1937,8 +2024,8 @@ cs4231_ioctl, eb4231_start_output, eb4231_stop_output, - cs4231_start_input, - cs4231_stop_input, + eb4231_start_input, + eb4231_stop_input, cs4231_audio_getdev, cs4231_set_output_volume, cs4231_get_output_volume, diff -u --recursive --new-file v2.2.10/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h --- v2.2.10/linux/drivers/sbus/audio/cs4231.h Thu Apr 22 19:24:51 1999 +++ linux/drivers/sbus/audio/cs4231.h Mon Aug 9 12:05:13 1999 @@ -255,19 +255,19 @@ #define APC_XINT_PLAY 0x40000 /* Playback ext intr */ #define APC_XINT_CAPT 0x20000 /* Capture ext intr */ #define APC_XINT_GENL 0x10000 /* Error ext intr */ -#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt */ -#define APC_XINT_PEMP 0x4000 /* Play pipe empty */ +#define APC_XINT_EMPT 0x8000 /* Pipe empty interrupt (0 write to pva) */ +#define APC_XINT_PEMP 0x4000 /* Play pipe empty (pva and pnva not set) */ #define APC_XINT_PNVA 0x2000 /* Playback NVA dirty */ #define APC_XINT_PENA 0x1000 /* play pipe empty Int enable */ #define APC_XINT_COVF 0x800 /* Cap data dropped on floor */ #define APC_XINT_CNVA 0x400 /* Capture NVA dirty */ -#define APC_XINT_CEMP 0x200 /* Capture pipe empty interrupt */ +#define APC_XINT_CEMP 0x200 /* Capture pipe empty (cva and cnva not set) */ #define APC_XINT_CENA 0x100 /* Cap. pipe empty int enable */ #define APC_PPAUSE 0x80 /* Pause the play DMA */ #define APC_CPAUSE 0x40 /* Pause the capture DMA */ #define APC_CDC_RESET 0x20 /* CODEC RESET */ -#define APC_PDMA_READY 0x08 /* Play DMA Go */ -#define APC_CDMA_READY 0x04 /* Capture DMA Go */ +#define APC_PDMA_READY 0x08 /* Play DMA Go */ +#define APC_CDMA_READY 0x04 /* Capture DMA Go */ #define APC_CHIP_RESET 0x01 /* Reset the chip */ #define APC_INIT_SETUP (APC_CDMA_READY | APC_PDMA_READY | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_GENL | APC_INT_PENDING | APC_PLAY_INT | APC_CAPT_INT | APC_GENL_INT) diff -u --recursive --new-file v2.2.10/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.2.10/linux/drivers/sbus/char/bpp.c Mon Mar 15 16:11:30 1999 +++ linux/drivers/sbus/char/bpp.c Mon Aug 9 12:05:10 1999 @@ -149,18 +149,18 @@ */ struct bpp_regs { /* DMA registers */ - __u32 p_csr; /* DMA Control/Status Register */ - __u32 p_addr; /* Address Register */ - __u32 p_bcnt; /* Byte Count Register */ - __u32 p_tst_csr; /* Test Control/Status (DMA2 only) */ + __volatile__ __u32 p_csr; /* DMA Control/Status Register */ + __volatile__ __u32 p_addr; /* Address Register */ + __volatile__ __u32 p_bcnt; /* Byte Count Register */ + __volatile__ __u32 p_tst_csr; /* Test Control/Status (DMA2 only) */ /* Parallel Port registers */ - __u16 p_hcr; /* Hardware Configuration Register */ - __u16 p_ocr; /* Operation Configuration Register */ - __u8 p_dr; /* Parallel Data Register */ - __u8 p_tcr; /* Transfer Control Register */ - __u8 p_or; /* Output Register */ - __u8 p_ir; /* Input Register */ - __u16 p_icr; /* Interrupt Control Register */ + __volatile__ __u16 p_hcr; /* Hardware Configuration Register */ + __volatile__ __u16 p_ocr; /* Operation Configuration Register */ + __volatile__ __u8 p_dr; /* Parallel Data Register */ + __volatile__ __u8 p_tcr; /* Transfer Control Register */ + __volatile__ __u8 p_or; /* Output Register */ + __volatile__ __u8 p_ir; /* Input Register */ + __volatile__ __u16 p_icr; /* Interrupt Control Register */ }; /* P_CSR. Bits of type RW1 are cleared with writting '1'. */ diff -u --recursive --new-file v2.2.10/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.2.10/linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Apr 12 09:51:04 1999 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Aug 9 12:04:57 1999 @@ -1,3 +1,22 @@ +Wed Jul 21 1999 23:00 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2a-2 + - merge of driver 3.2a-1 with linux-2.3.11-pre3 + +Sun May 9 15:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2a-1 + - Fix the misdetection of SYM53C875E (was detected as a 876). + - Set the actual host ID used for each host in the scsi host data + structure. The mid-layer SCSI driver needs this information. + +Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2a + - Add 'hostid:#id' boot option. This option allows to change the + default SCSI id the driver uses for controllers. + - Remove nvram layouts and driver set-up structures from the C source, + and use the one defined in sym53c8xx_defs.h file. + (shared by both drivers). + - Set for now MAX LUNS to 16 (instead of 8). + Thu Mar 11 23:00 1999 Gerard Roudier (groudier@club-internet.fr) * revision 3.2 (8xx-896 driver bundle) - Only define the host template in ncr53c8xx.h and include the diff -u --recursive --new-file v2.2.10/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.2.10/linux/drivers/scsi/ChangeLog.sym53c8xx Mon Apr 12 09:51:04 1999 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Mon Aug 9 12:04:57 1999 @@ -1,3 +1,40 @@ +Sat Jul 24 12:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3g + - merge of driver 1.3f with linux-2.2.11-pre3 + - remove the broken testing of the chip being connected to SCSI + from the SCSI interrupt handling code. + +Sun May 9 15:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3f + - Fix the misdetection of SYM53C875E (was detected as a 876). + - Fix the misdetection of SYM53C810 not A (was detected as a 810A). + - Support for the 53C895A by Pamela Delaney + The 53C895A contains all of the features of the 896 but has only + one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing + using dual cycle PCI data transfers. + - Call request_region() event if MMIO is used and not normal IO. + This allows sym and the ncr driver to be loaded in any order + without any risk of attaching the same device. + - Set the actual host ID used for each host in the scsi host data + structure. The mid-layer SCSI driver needs this information. + - Miscellaneous minor fixes. + +Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3e + - Support for any number of LUNs (64) (SPI2-compliant). + (Btw, this may only be ever usefull under linux-2.2 ;-)) + +Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3d + - Add 'hostid:#id' boot option. This option allows to change the + default SCSI id the driver uses for controllers. + - Make SCRIPTS not use self-mastering for PCI. + There were still 2 places the driver used this feature of the + 53C8XX family. + - Move some data structures (nvram layouts and driver set-up) to + the sym53c8xx_defs.h file. So, the both drivers will share them. + - Set MAX LUNS to 16 (instead of 8). + Sat Mar 20 21:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3b - Add support for NCR PQS PDS. diff -u --recursive --new-file v2.2.10/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c --- v2.2.10/linux/drivers/scsi/NCR53C9x.c Fri Dec 18 09:47:38 1998 +++ linux/drivers/scsi/NCR53C9x.c Mon Aug 9 12:04:39 1999 @@ -3390,6 +3390,7 @@ struct ESP_regs *eregs; Scsi_Cmnd *SCptr; int what_next = do_intr_end; + unsigned long flags; #ifdef CONFIG_SCSI_SUNESP struct sparc_dma_registers *dregs = (struct sparc_dma_registers*) esp->dregs; @@ -3610,7 +3611,9 @@ } SCptr->result = (DID_RESET << 16); + spin_lock_irqsave(&io_request_lock,flags); SCptr->scsi_done(SCptr); + spin_unlock_irqrestore(&io_request_lock, flags); } esp->current_SC = NULL; if(esp->disconnected_SC) { @@ -3625,7 +3628,9 @@ } SCptr->result = (DID_RESET << 16); + spin_lock_irqsave(&io_request_lock,flags); SCptr->scsi_done(SCptr); + spin_unlock_irqrestore(&io_request_lock, flags); } } esp->resetting_bus = 0; diff -u --recursive --new-file v2.2.10/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.2.10/linux/drivers/scsi/README.ncr53c8xx Mon Apr 12 09:51:04 1999 +++ linux/drivers/scsi/README.ncr53c8xx Mon Aug 9 12:04:57 1999 @@ -4,7 +4,7 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -10 March 1999 +9 May 1999 =============================================================================== 1. Introduction @@ -736,6 +736,13 @@ Serial NVRAM nvram:n do not look for serial NVRAM nvram:y test controllers for onboard serial NVRAM + (alternate binary form) + mvram= + 0x01 look for NVRAM (equivalent to nvram=y) + 0x02 ignore NVRAM "Synchronous negotiation" parameters for all devices + 0x04 ignore NVRAM "Wide negotiation" parameter for all devices + 0x08 ignore NVRAM "Scan at boot time" parameter for all devices + 0x80 also attach controllers set to OFF in the NVRAM (sym53c8xx only) Check SCSI BUS buschk: