diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/CREDITS linux.ac/CREDITS --- linux.vanilla/CREDITS Tue Jun 15 16:49:44 1999 +++ linux.ac/CREDITS Mon Jul 19 20:31:16 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 @@ -1306,6 +1318,13 @@ D: XF86_8514 D: cfdisk (curses based disk partitioning program) +N: Heinz Mauelshagen +E: mge@ez-darmstadt.telekom.de +D: Logical Volume Manager +S: Bartningstr. 12 +S: 64289 Darmstadt +S: Germany + N: Mike McLagan E: mike.mclagan@linux.org W: http://www.invlogic.com/~mmclagan @@ -1603,6 +1622,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 +1666,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 @@ -2253,6 +2282,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Changes linux.ac/Documentation/Changes --- linux.vanilla/Documentation/Changes Thu May 27 22:11:46 1999 +++ linux.ac/Documentation/Changes Mon Jul 19 03:52:36 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.4b release of Samba: +ftp://ftp.samba.org/pub/samba/samba-2.0.4b.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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/Configure.help linux.ac/Documentation/Configure.help --- linux.vanilla/Documentation/Configure.help Tue Jun 15 16:49:44 1999 +++ linux.ac/Documentation/Configure.help Mon Jul 19 20:31:16 1999 @@ -87,13 +87,13 @@ a system with only one CPU, like most personal computers, say N. If you have a system with more than one CPU, say Y. - If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If + If you say N here, the kernel will run on single and multi-processor + machines, but will use only one CPU of a multi-processor machine. If you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel + single-processor machines. On a single-processor machine, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or + Note that if you say Y here and choose architectures "586" or "Pentium" under "Processor family", the kernel will not work on 486 architectures. Similarly, multiprocessor kernels for the "PPro" architecture may not work on all Pentium based boards. @@ -136,7 +136,7 @@ If you are not sure, say Y; apart from resulting in a 45 KB bigger kernel, it won't hurt. - + Timer and CPU usage LEDs CONFIG_LEDS If you define this option, the LEDs on your machine will be used @@ -688,6 +688,17 @@ It's pretty unlikely that you have one of these: say N. +Mylex DAC960/DAC1100 PCI RAID Controller support +CONFIG_BLK_DEV_DAC960 + This driver adds support for the Mylex DAC960, AcceleRAID, and + eXtremeRAID PCI RAID controllers. See README.DAC960 for further + information about this driver. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called DAC960.o. + Parallel port IDE device support CONFIG_PARIDE There are many external CD-ROM and disk devices that connect through @@ -927,6 +938,29 @@ called on26.o. You must also have a high-level driver for the type of device that you want to support. +Logical Volume Manager (LVM) support +CONFIG_BLK_DEV_LVM + This driver lets you combine several hard disks, hard disk partitions + or even multiple devices into a volume group. Imagine a volume group as + a kind of virtual disk. Logical volumes, which can be thought of as + virtual partitions, can be created in the volume group. + You can resize volume groups and logical volumes after creation time, + corresponding to new capacity needs. Logical volumes are accessed as + block devices named /dev/VolumeGroupName/LogicalVolumeName. + + For details see /usr/src/linux/Documentation/LVM-HOWTO. + + To get the newest software see . + +Logical Volume Manager proc filesystem information +CONFIG_LVM_PROC_FS + If you say Y here, you are able to see overall Logical Volume Manager, + Volume Group, Logical and Physical Volume information in /proc/lvm. + + You must check, that the "proc filesystem support" (CONFIG_PROC_FS) is + enabled too, to use this option. + + Multiple devices driver support CONFIG_BLK_DEV_MD This driver lets you combine several hard disk partitions into one @@ -945,6 +979,13 @@ If unsure, say N. +Autodetect RAID partitions +CONFIG_AUTODETECT_RAID + This feature lets the kernel detect RAID partitions on bootup. + An autodetect RAID partition is a normal partition with partition + type 0xfd. Use this if you want to boot RAID devices, or want to + run them automatically. + Linear (append) mode CONFIG_MD_LINEAR If you say Y here, then your multiple devices driver will be able to @@ -1024,6 +1065,21 @@ If unsure, say Y. +Translucent Block Device Support (EXPERIMENTAL) +CONFIG_MD_TRANSLUCENT + DO NOT USE THIS STUFF YET! + + currently there is only a placeholder there as the implementation + is not yet usable. + +Logical Volume Manager support (EXPERIMENTAL) +CONFIG_MD_LVM + DO NOT USE THIS STUFF YET! + + i have released this so people can comment on the architecture, + but user-space tools are still unusable so there is nothing much + you can do with this. + Boot support (linear, striped) CONFIG_MD_BOOT To boot with an initial linear or striped md device you have to @@ -1844,6 +1900,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 @@ -2627,6 +2688,76 @@ The module will be called ip_masq_markfw.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IP: masquerading virtual server support +CONFIG_IP_MASQUERADE_VS + IP Virtual Server support will let you build a virtual server + based on cluster of two or more real servers. This option must + be enabled for at least one of the clustered computers that will + take care of intercepting incomming connections to the virtual IP + and scheduling them to real servers. + Three request dispatching techniques are implemented, they are + virtual server via NAT, virtual server via tunneling and virtual + server via direct routing. The round-robin scheduling, the weighted + round-robin secheduling, or the weighted least-connection scheduling + algorithm can be used to choose which server the connection is + directed to, thus load balancing can be achieved among the servers. + For more information and its administration program, please visit + the following URL: + http://proxy.iinchina.net/~wensong/ippfvs/ + If you want this, say Y. + +IP masquerading VS table size (the Nth power of 2) +CONFIG_IP_MASQUERADE_VS_TAB_BITS + Using a big IP masquerading hash table for virtual server will greatly + reduce conflicts in the masquerading hash table when there are + thousands of active connections. + Note the table size must be power of 2. The table size will be the + value of 2 to the your input number power. For example, the default + number is 12, so the table size is 4096. Don't input the number too + small, otherwise you will lose performance on it. + You can adapt the table size yourself, according to your virtual + server application. It is good to set the table size larger than + the number of connections per second multiplying average lasting time + of connection in the table. For example, your virtual server gets + 20 connections per second, the connection lasts for 200 seconds in + average in the masquerading table, the table size should be larger + than 20x200, it is good to set the table size 4096 (2**12). + +IPVS: round-robin scheduling +CONFIG_IP_MASQUERADE_VS_RR + The robin-robin scheduling algorithm simply directs network + connections to different real servers in a round-robin manner. + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +IPVS: weighted round-robin scheduling +CONFIG_IP_MASQUERADE_VS_WRR + The weighted robin-robin scheduling algorithm directs network + connections to different real servers based on server weights + in a round-robin manner. Servers with higher weights receive + new connections first than those with less weights, and servers + with higher weights get more connections than those with less + weights and servers with equal weights get equal connections. + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +IPVS: weighted least-connection scheduling +CONFIG_IP_MASQUERADE_VS_WLC + The weighted least-connection scheduling algorithm directs network + connections to the server with the least number of alive connections + dividing the server weight. + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +IPVS: persistent client connection scheduling +CONFIG_IP_MASQUERADE_VS_PCC + The persistent client connection feature means that after a client + establishs a connection to the selected server, all connections + from the same client will be directed to the same server in a + specified period. + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + IP: always defragment (required for masquerading) CONFIG_IP_ALWAYS_DEFRAG If you say Y here, then all incoming fragments (parts of IP packets @@ -3243,6 +3374,13 @@ ### Don't know what's going on here. ### # +YAM driver for AX.25 +CONFIG_YAM + Support for the YAM modem on serial port. If you want to compile this + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. + BAYCOM picpar and par96 driver for AX.25 CONFIG_BAYCOM_PAR This is a driver for Baycom style simple amateur radio modems that @@ -4989,6 +5127,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 +5264,15 @@ module, say M here and read Documentation/modules.txt. If you don't know what to use this for, you don't need it. +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -5478,9 +5636,12 @@ that has a program like lynx or netscape) is a family of intelligent multiprotocol WAN adapters with data transfer rates up to T1 (1.544 Mbps). They are also known as Synchronous Data Link Adapters (SDLA) - and designated S502E(A), S503 or S508. These cards support the X.25, - Frame Relay, and PPP protocols. If you have one or more of these - cards, say Y to this option; you may then also want to read the file + and designated S503 or S508. These cards support the X.25, Frame + Relay, PPP, Cisco HDLC protocols. The driver also offers API support + for protocols like HDLC (LAPB), HDLC Streaming and BiSync. + + If you have one or more of these cards, say Y to this option; you + may then also want to read the file Documentation/networking/wanpipe.txt. The next questions will ask you about the protocols you want the driver to support. @@ -5500,26 +5661,48 @@ WANPIPE X.25 support CONFIG_WANPIPE_X25 Say Y to this option if you are planning to connect a WANPIPE card - to an X.25 network. You should then also have said Y to "CCITT X.25 - Packet Layer" and "LAPB Data Link Driver", above. If you say N, the - X.25 support will not be included in the driver (saves about 16 KB - of kernel memory). + to an X.25 network. If you say N, the X.25 support will not be + included in the driver. The X.25 option is ONLY supported on S508 + cards. WANPIPE Frame Relay support CONFIG_WANPIPE_FR Say Y to this option if you are planning to connect a WANPIPE card - to a frame relay network. You should then also have said Y to "Frame - Relay (DLCI) support", above. If you say N, the frame relay - support will not be included in the driver (saves about 16 KB of - kernel memory). + to a frame relay network. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is ONLY + supported on S508 cards. WANPIPE PPP support CONFIG_WANPIPE_PPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). You should - then also have said Y to "PPP (point-to-point) support", above. If - you say N, the PPP support will not be included in the driver (saves - about 16 KB of kernel memory). + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is ONLY supported on S508 cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S508 card ONLY. This support also allows + user to build applications using the HDLC streaming API. If you say + N, the Cisco HDLC support and HDLC streaming API will not be + included in the driver. + +WANPIPE BiSync Streaming API support +CONFIG_WANPIPE_BSTRM + Say Y to this option if you are planning to use a WANPIPE card to + develop user applications to send RAW BiSync data. This option + provides an API support for customers to build their own + applications. This API ONLY supports S503 cards. If you say N, then + BiSync API support will not be included in the driver. + +WANPIPE HDLC (LAPB) API support +CONFIG_WANPIPE_HDLC + Say Y to this option if you are planning to use a WANPIPE card to + develop user application to send HDLC (LAPB) data. This option + provides an API support for customers to build their own + applications. This API ONLY supports the S508 cards. If you say N, + then HDLC (LAPB) API support will not be included in the driver. Ethernet (10 or 100Mbit) CONFIG_NET_ETHERNET @@ -5734,7 +5917,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 +6675,25 @@ The module will be called ibmtr.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +IBM Olympic chipset PCI adapter support +CONFIG_IBMOL + This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II + Wake On Lan, and PCI 100/16/4 adapters. + + If you have such an adapter, say Y and read the Token-Ring mini-HOWTO, + available via FTP (user:anonymous) from + ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called olympic.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + Also read the linux/Documentation/networking/olympic.txt or check the + Linux Token Ring Project site for the latest information at + http://www.linuxtr.net + SysKonnect adapter support CONFIG_SKTR This is support for all SysKonnect Token Ring cards, specifically @@ -7204,11 +7406,12 @@ If unsure, say N. -System V and Coherent filesystem support +System V, Version 7 and Coherent filesystem support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel - machines. Saying Y here would allow you to read to and write from - their floppies and hard disk partitions. + machines, and Version 7 was used on the DEC PDP-11. Saying Y here + would allow you to read to and write from their floppies and hard + disk partitions. If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order @@ -7360,6 +7563,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 +8325,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 @@ -8731,9 +8956,15 @@ APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with APM compliant BIOSes. If you say Y here, the system time will be - reset after a USER RESUME operation, the /proc/apm device will - provide battery status information, and user-space programs will - receive notification of APM "events" (e.g., battery status change). + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g., battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. Supporting software is available; for more information, read the Battery Powered Linux mini-HOWTO, available via FTP (user: @@ -8746,9 +8977,7 @@ This driver does not support the TI 4000M TravelMate and the ACER 486/DX4/75 because they don't have compliant BIOSes. Many "green" desktop machines also don't have compliant BIOSes, and this driver - will cause those machines to panic during the boot phase (typically, - these machines are using a data segment of 0040, which is reserved - for the Linux kernel). + may cause those machines to panic during the boot phase. If you are running Linux on a laptop, you may also want to read the Linux Laptop home page on the WWW at @@ -8825,18 +9054,6 @@ backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. -Power off on shutdown -CONFIG_APM_POWER_OFF - Enable the ability to power off the computer after the Linux kernel - is halted. You will need software (e.g., a suitable version of the - halt(8) command ("man 8 halt")) to cause the computer to power down. - Recent versions of the sysvinit package available from - ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ (user: - anonymous) contain support for this ("halt -p" shuts down Linux and - powers off the computer, if executed from runlevel 0). As with the - other APM options, this option may not work reliably with some APM - BIOS implementations. - Ignore multiple suspend/standby events CONFIG_APM_IGNORE_MULTIPLE_SUSPEND This option is necessary on the IBM Thinkpad 560, but should work on @@ -9191,7 +9408,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. @@ -9268,6 +9485,15 @@ You can say M here to compile this driver as a module; the module is called sb.o. +### +### Don't know what this is +### +#PCI Legacy soundblaster enabler +#CONFIG_SOUND_PCISB +# +#ESS-Tech Maestro support +#CONFIG_SOUND_ESSMAESTRO + Generic OPL2/OPL3 FM synthesizer support CONFIG_SOUND_ADLIB Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -9764,6 +9990,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 +10061,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 +10117,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 +10153,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 +10171,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 +10224,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 +10270,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 +11010,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 +11736,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/LVM-HOWTO linux.ac/Documentation/LVM-HOWTO --- linux.vanilla/Documentation/LVM-HOWTO Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/LVM-HOWTO Wed Jun 16 14:25:27 1999 @@ -0,0 +1,118 @@ +Heinz Mauelshagen's LVM (Logical Volume Manager) howto. 01/28/1999 + + +Abstract: +--------- +The LVM adds a kind of virtual disks and virtual partitions functionality +to the Linux operating system + +It achieves this by adding an additional layer between the physical peripherals +and the i/o interface in the kernel. + +This allows the concatenation of several disk partitions or total disks +(so-called physical volumes or PVs) or even multiple devices +to form a storage pool (so-called Volume Group or VG) with +allocation units called physical extents (called PE). +You can think of the volume group as a virtual disk. +Please see scenario below. + +Some or all PEs of this VG then can be allocated to so-called Logical Volumes +or LVs in units called logical extents or LEs. +Each LE is mapped to a corresponding PE. +LEs and PEs are equal in size. +Logical volumes are a kind of virtual partitions. + + +The LVs can be used through device special files similar to the known +/dev/sd[a-z]* or /dev/hd[a-z]* named /dev/VolumeGroupName/LogicalVolumeName. + +But going beyond this, you are able to extend or reduce +VGs _AND_ LVs at runtime! + +So... +If for example the capacity of a LV gets too small and your VG containing +this LV is full, you could add another PV to that VG and simply extend +the LV afterwards. +If you reduce or delete a LV you can use the freed capacity for different +LVs in the same VG. + + +The above scenario looks like this: + + /------------------------------------------\ + | /--PV2---\ VG 1 /--PVn---\ | + | |-VGDA---| |-VGDA-- | | + | |PE1PE2..| |PE1PE2..| | + | | | ...... | | | + | | | | | | + | | /-----------------------\ | | + | | \-------LV 1------------/ | | + | | ..PEn| | ..PEn| | + | \--------/ \--------/ | + \------------------------------------------/ + +PV 1 could be /dev/sdc1 sized 3GB +PV n could be /dev/sde1 sized 4GB +VG 1 could be test_vg +LV 1 could be /dev/test_vg/test_lv +VGDA is the volume group descriptor area holding the LVM metadata +PE1 up to PEn is the number of physical extents on each disk(partition) + + + +Installation steps see INSTALL and insmod(1)/modprobe(1), kmod/kerneld(8) +to load the logical volume manager module if you did not bind it +into the kernel. + + +Configuration steps for getting the above scenario: + +1. Set the partition system id to 0xFE on /dev/sdc1 and /dev/sde1. + +2. do a "pvcreate /dev/sd[ce]1" + For testing purposes you can use more than one partition on a disk. + You should not use more than one partition because in the case of + a striped LV you'll have a performance breakdown. + +3. do a "vgcreate test_vg /dev/sd[ce]1" to create the new VG named "test_vg" + which has the total capacity of both partitions. + vgcreate activates (transfers the metadata into the LVM driver in the kernel) + the new volume group too to be able to create LVs in the next step. + +4. do a "lvcreate -L1500 -ntest_lv test_vg" to get a 1500MB linear LV named + "test_lv" and it's block device special "/dev/test_vg/test_lv". + + Or do a "lvcreate -i2 -I4 -l1500 -nanother_test_lv test_vg" to get a 100 LE + large logical volume with 2 stripes and stripesize 4 KB. + +5. For example generate a filesystem in one LV with + "mke2fs /dev/test_vg/test_lv" and mount it. + +6. extend /dev/test_vg/test_lv to 1600MB with relative size by + "lvextend -L+100 /dev/test_vg/test_lv" + or with absolute size by + "lvextend -L1600 /dev/test_vg/test_lv" + +7. reduce /dev/test_vg/test_lv to 900 logical extents with relative extents by + "lvreduce -l-700 /dev/test_vg/test_lv" + or with absolute extents by + "lvreduce -l900 /dev/test_vg/test_lv" + +9. rename a VG by deactivating it with + "vgchange -an test_vg" # only VGs with _no_ open LVs can be deactivated! + "vgrename test_vg whatever" + and reactivate it again by + "vgchange -ay whatever" + +9. rename a LV after closing it by + "lvchange -an /dev/whatever/test_lv" # only closed LVs can be deactivated + "lvrename /dev/whatever/test_lv /dev/whatever/whatvolume" + or by + "lvrename whatever test_lv whatvolume" + and reactivate it again by + "lvchange -ay /dev/whatever/whatvolume" + +10. if you own Ted Tso's resize2fs program, you are able to resize the + ext2 type filesystems contained in logical volumes without destroyiing + the data by + "e2fsadm -L+100 /dev/test_vg/another_test_lv" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/cpqarray.txt linux.ac/Documentation/cpqarray.txt --- linux.vanilla/Documentation/cpqarray.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/cpqarray.txt Mon Jul 5 05:11:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/dcache.txt linux.ac/Documentation/filesystems/dcache.txt --- linux.vanilla/Documentation/filesystems/dcache.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/filesystems/dcache.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,173 @@ +Some dcache details + +A traditional Unix system has inodes (`index nodes') as in-core +descriptors of files. An inode refers to the actual file, not +to a directory entry naming it. Linux v2.1.43 introduced dentries +(`directory entries') as in-core descriptors of file names. + +The entire purpose of dentries is to make the map +filename -> inode fast. An interesting side effect +is that the kernel knows what name was used to open a file +and that a system call getcwd() is possible. + +Thus, the central part of the dcache code are the lines + dentry = reserved_lookup(base, &this); + if (!dentry) { + dentry = cached_lookup(base, &this); + if (!dentry) + dentry = real_lookup(base, &this); + } +in namei.c. The reserved_lookup() takes care of . and ..; +the cached_lookup() is what we have the dcache for, +and the real_lookup() goes to the filesystem. + +The cached_lookup() returns the value of d_lookup(), +but does a d_revalidate() before returning, and if that fails +and the dentry has no children, it returns NULL. + [This is a rather obscure part. The d_revalidate() + is allowed to fail for any reason - for example, + autofs uses a timeout to make d_revalidate fail - + which means that the final dentry we come up with + need not be the dentry that d_lookup() found. + This causes bugs in the vfat filesystem. + Moreover, if d_revalidate(D) fails but D still has + children, then D is used anyway. + This also causes bugs in the vfat filesystem. + I think also nfs has problems.] + + + + +A struct dentry has five members of type struct list_head: + struct list_head d_hash; /* lookup hash list */ + struct list_head d_lru; /* d_count = 0 LRU list */ + struct list_head d_child; /* child of parent list */ + struct list_head d_subdirs; /* our children */ + struct list_head d_alias; /* inode alias list */ + + [Some of these names were very badly chosen, and lead + to confusion all the time. We should do a global replace + changing d_subdirs into d_children and d_child into d_sister.] + + + +1. d_hash + +The d_hash field of a dentry links the dentry into +the list of dentries for filenames with a given hash value +with list head dentry_hashtable[hashvalue] defined in dcache.c. +This list is used in d_lookup() to find a dentry with given name +and parent. It is used in d_validate() to find a dentry with +known hash and parent. + [The present code takes the parent into account when + computing a hash. Not doing this would make the code + simpler and faster, possibly at the expense of a few + more collisions. Has anyone investigated this?] +The d_hash field is an empty list when the file is a mount point +(cf. d_validate) or has been deleted, or when the dentry was +dropped for some other reason. + + +d_add(D,I) will put D into its hash chain and provide it +with the inode I. It is called by all filesystem lookup routines. + +d_drop(D) will remove D from its hash chain. A dentry is called +`unhashed' when its d_hash field is an empty list. +Sometimes dentries are dropped temporarily to make sure +no lookup will find them. The general routine vfs_rmdir(I,D) +will drop D if d_count=2, so that all filesystem rmdir() +routines can return -EBUSY when D still occurs in the hash list. +The filesystem routines for unlink and rmdir call d_delete() +which again calls d_drop(). + +[The d_hash field is referred to in many places that should +not know about its existence, in the phrase + if (list_empty(&dentry->d_hash)) ... +No doubt there should be a line + #define unhashed(d) (list_empty(&(d)->d_hash)) +in dcache.h, together with a comment describing the semantics +of being unhashed. Then all these occurrences of d_hash can +be removed. Next, d_drop() should be renamed d_unhash().] + +The dentry for the root of a mounted filesystem is returned by +d_alloc_root() and is unhashed. + + + +2. d_lru +The simplest list is the one joining the d_lru fields of +dentries that had d_count = 0 at some point in time. +The list head is the variable dentry_unused defined in dcache.c. +The number of elements in this list is dentry_stat.nr_unused. +There are no references to the d_lru field outside dcache.[ch]. + +Note that d_count is incremented by dget(), invoked by d_lookup(), +without removing the dentry from the LRU list. Thus, anyone hoping +to find unused dentries on this list must first check d_count. +If a dentry is not on the LRU list, its d_lru field is an +empty list (initialized by d_alloc()). + +dput(D) tries to get rid of D altogether when d_count = 0, but +puts D at the head of the LRU list if it is still on the hash list. +Thus, every D with d_count = 0 will be on the LRU list. + +select_dcache(ict,pct) removes D with d_count > 0 from the +LRU list, and moves D that are ready to be sacrificed for memory +to the end of the list. (If ict and/or pct is given, then we are +satisfied when the selected D's involve ict inodes or pct pages.) + +prune_dcache(ct) removes D with d_count > 0 from the LRU list, +and frees unused D, stopping when ct of them have been freed. + +shrink_dcache_sb(sb) removes all unused D with given superblock +from the LRU list. + +select_parent(D) move all unused descendants of D to the end +of the LRU list. + + + +3. d_child and d_subdirs +As already noted, the names are terrible. The d_child field +does not refer to a child but to a sibling, and the d_subdirs +field does not refer to a subdirectory but to a child, directory +or not. These two fields form a threaded tree: the d_subdirs field +points to the first child, and the d_child field is member of the +circularly linked list of all children of one parent. + +To be more precise: this circularly linked list of all children +of one parent P passes through the d_child fields of all children +and through the d_subdirs field of the parent P. + + + +4. d_alias +Somewhat similar to the above, where we had a circularly linked list +with one special element, we here have a circularly linked list +passing through the d_alias field of all dentries that are aliases +of one inode, and through the i_dentry field of the inode. + +The dentry is added to this list by d_instantiate(). +It is removed again by dentry_iput() which is called by dput() +and d_delete(). + + + + +So far about the lists in the dentry structure. +Some of the routines in dcache.c have been mentioned already. +Let me describe one of the more obscure ones. + +d_move(D,T) is the routine called by the filesystem code +just before finishing the rename(D,T) call. Since both +dentries D and T may be busy we cannot just throw one away. +Instead they are partially interchanged: +D and T interchange names, and D is put into T's hash queue, +and T is unhashed; D and T interchange parents, and are put +on the list of children of their new parent. +The result is that the file D that got renamed is now in perfect +shape again - it has been renamed. T, if it existed, lost its +name string, if it was short, but perhaps this is harmless - +let us hope no-one will ever ask for T's name anymore. + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/sysv-fs.txt linux.ac/Documentation/filesystems/sysv-fs.txt --- linux.vanilla/Documentation/filesystems/sysv-fs.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/filesystems/sysv-fs.txt Fri Jun 4 23:52:54 1999 @@ -2,20 +2,22 @@ It implements all of - Xenix FS, - SystemV/386 FS, + - Version 7 FS - Coherent FS. This is version beta 4. To install: -* Answer the 'System V and Coherent filesystem support' question with 'y' - when configuring the kernel. +* Answer the 'System V, Version 7 and Coherent filesystem support' question + with a 'y' when configuring the kernel. * To mount a disk or a partition, use mount [-r] -t sysv device mountpoint The file system type names -t sysv -t xenix + -t v7 -t coherent - may be used interchangeably, but the last two will eventually disappear. + the xenix and coherent options will eventually disappear. Bugs in the present implementation: - Coherent FS: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/filesystems/ufs.txt linux.ac/Documentation/filesystems/ufs.txt --- linux.vanilla/Documentation/filesystems/ufs.txt Fri Apr 16 22:10:51 1999 +++ linux.ac/Documentation/filesystems/ufs.txt Mon Jul 19 03:46:35 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/CREDITS linux.ac/Documentation/isdn/CREDITS --- linux.vanilla/Documentation/isdn/CREDITS Tue Jun 15 16:49:44 1999 +++ linux.ac/Documentation/isdn/CREDITS Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/HiSax.cert linux.ac/Documentation/isdn/HiSax.cert --- linux.vanilla/Documentation/isdn/HiSax.cert Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/isdn/HiSax.cert Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/INTERFACE linux.ac/Documentation/isdn/INTERFACE --- linux.vanilla/Documentation/isdn/INTERFACE Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/INTERFACE Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README linux.ac/Documentation/isdn/README --- linux.vanilla/Documentation/isdn/README Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/README Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.HiSax linux.ac/Documentation/isdn/README.HiSax --- linux.vanilla/Documentation/isdn/README.HiSax Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/README.HiSax Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.act2000 linux.ac/Documentation/isdn/README.act2000 --- linux.vanilla/Documentation/isdn/README.act2000 Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/isdn/README.act2000 Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.audio linux.ac/Documentation/isdn/README.audio --- linux.vanilla/Documentation/isdn/README.audio Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/README.audio Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.avmb1 linux.ac/Documentation/isdn/README.avmb1 --- linux.vanilla/Documentation/isdn/README.avmb1 Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/README.avmb1 Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.concap linux.ac/Documentation/isdn/README.concap --- linux.vanilla/Documentation/isdn/README.concap Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/isdn/README.concap Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.eicon linux.ac/Documentation/isdn/README.eicon --- linux.vanilla/Documentation/isdn/README.eicon Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/isdn/README.eicon Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.icn linux.ac/Documentation/isdn/README.icn --- linux.vanilla/Documentation/isdn/README.icn Sun Nov 8 15:08:48 1998 +++ linux.ac/Documentation/isdn/README.icn Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/isdn/README.x25 linux.ac/Documentation/isdn/README.x25 --- linux.vanilla/Documentation/isdn/README.x25 Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/isdn/README.x25 Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/locks.txt linux.ac/Documentation/locks.txt --- linux.vanilla/Documentation/locks.txt Sat Jan 9 21:50:34 1999 +++ linux.ac/Documentation/locks.txt Fri Jun 4 23:52:55 1999 @@ -13,12 +13,11 @@ The old flock(2) emulation in the kernel was swapped for proper BSD compatible flock(2) support in the 1.3.x series of kernels. With the -release of the 2.1.x kernel series, support for the old emulation has -been totally removed, so that we don't need to carry this baggage -forever. +release of the 2.1.x kernel series, support for the old emulation was +totally removed, so that we don't need to carry this baggage forever. -This should not cause problems for anybody, since everybody using a -2.1.x kernel should have updated their C library to a suitable version +This should not cause problems for anybody, since everybody using a 2.1.x +or 2.2.x kernel should have updated their C library to a suitable version anyway (see the file "linux/Documentation/Changes".) 1.2 Allow Mixed Locks Again @@ -31,9 +30,9 @@ for example. This gave rise to some other subtle problems if sendmail was configured to rebuild the alias file. Sendmail tried to lock the aliases.dir file with fcntl() at the same time as the GDBM routines tried to lock this -file with flock(). With pre 1.3.96 kernels this could result in deadlocks that, -over time, or under a very heavy mail load, would eventually cause the kernel -to lock solid with deadlocked processes. +file with flock(). With kernels before 1.3.96 this could result in deadlocks +that, over time or under a very heavy mail load, would eventually cause the +kernel to lock solid with deadlocked processes. 1.2.2 The Solution @@ -60,7 +59,7 @@ file for which a mandatory lock existed. From this release of the kernel, mandatory locking can be turned on and off -on a per-filesystem basis, using the mount options 'mand' and 'nomand'. +on a per-file-system basis, using the mount options 'mand' and 'nomand'. The default is to disallow mandatory locking. The intention is that mandatory locking only be enabled on a local filesystem as the specific need arises. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/m68k/kernel-options.txt linux.ac/Documentation/m68k/kernel-options.txt --- linux.vanilla/Documentation/m68k/kernel-options.txt Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/m68k/kernel-options.txt Fri Jun 4 23:52:55 1999 @@ -1,5 +1,3 @@ - - Command Line Options for Linux/m68k =================================== @@ -14,7 +12,7 @@ Often I've been asked which command line options the Linux/m68k kernel understands, or how the exact syntax for the ... option is, or ... about the option ... . I hope, this document supplies all the -answers... +answers. Note that some options might be outdated, their descriptions being incomplete or missing. Please update the information and send in the @@ -110,20 +108,19 @@ [Strange and maybe uninteresting stuff ON] This unusual translation of device names has some strange -consequences: If, for example, you have a symbolic link from /dev/fd +consequences: if, for example, you have a symbolic link from /dev/fd to /dev/fd0D720 as an abbreviation for floppy driver #0 in DD format, you cannot use this name for specifying the root device, because the kernel cannot see this symlink before mounting the root FS and it isn't in the table above. If you use it, the root device will not be -set at all, without an error message. Another example: You cannot use a +set at all, without an error message. Another example: you cannot use a partition on e.g. the sixth SCSI disk as the root filesystem, if you want to specify it by name. This is, because only the devices up to -/dev/sde are in the table above, but not /dev/sdf. Although, you can -use the sixth SCSI disk for the root FS, but you have to specify the -device by number... (see below). Or, even more strange, you can use the -fact that there is no range checking of the partition number, and your -knowledge that each disk uses 16 minors, and write "root=/dev/sde17" -(for /dev/sdf1). +/dev/sde are in the table above, but not /dev/sdf. You can use the sixth +SCSI disk for the root filesystem, but you have to specify the device by +number (see below). Even more strange, you can use the fact that there is +no range checking of the partition number, and your knowledge that each +disk uses 16 minors, and write "root=/dev/sde17" (for /dev/sdf1). [Strange and maybe uninteresting stuff OFF] @@ -181,7 +178,7 @@ Devices possible for Amiga: - "ser": built-in serial port; parameters: 9600bps, 8N1 - - "mem": Save the messages to a reserved area in chip mem. After + - "mem": Save the messages to a reserved area in chip memory. After rebooting, they can be read under AmigaOS with the tool 'dmesg'. @@ -205,7 +202,7 @@ Syntax: ramdisk= This option instructs the kernel to set up a ramdisk of the given -size in KBytes. Do not use this option if the ramdisk contents are +size in kilobytes. Do not use this option if the ramdisk contents are passed by bootstrap! In this case, the size is selected automatically and should not be overwritten. @@ -234,10 +231,10 @@ drivers/net/Space.c in the Linux source. Most prominent are eth0, ... eth3, sl0, ... sl3, ppp0, ..., ppp3, dummy, and lo. - The non-ethernet drivers (sl, ppp, dummy, lo) obviously ignore the -settings by this options. Also, the existing ethernet drivers for + The non-Ethernet drivers (sl, ppp, dummy, lo) obviously ignore the +settings by this options. Also, the existing Ethernet drivers for Linux/m68k (ariadne, a2065, hydra) don't use them because Zorro boards -are really Plug-'n-Play, so the "ether=" option is useless altogether +are really Plug-'n'-Play, so the "ether=" option is useless altogether for Linux/m68k. @@ -288,8 +285,8 @@ to use (minimum 4, default 4), is the size of each buffer in kilobytes (minimum 4, default 32) and says how much percent of error will be tolerated when setting a frequency -(maximum 10, default 0). For example with 3% you can play 8000Hz -AU-Files on the Falcon with its hardware frequency of 8195Hz and thus +(maximum 10, default 0). For example, with 3% you can play 8000 Hz Sun +audio files on the Falcon with its hardware frequency of 8195 Hz and thus don't need to expand the sound. @@ -482,7 +479,7 @@ xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the initialisation of the video-card. If you're missing a corresponding yres_virtual: the external part is legacy, -therefore we don't support hardware-dependend functions like hardware-scroll, +therefore we don't support hardware-dependent functions like hardware scroll, panning or blanking. 4.1.7) eclock: @@ -653,7 +650,7 @@ "ov_midi", ... These options are meant for switching on an OverScan video extension. The difference to the bare option is that the switch-on is done after video initialization, and somehow synchronized -to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched +to the HBLANK. A specialty is that ov_ikbd and ov_midi are switched off before rebooting, so that OverScan is disabled and TOS boots correctly. @@ -737,8 +734,8 @@ - vga70 : 640x400, 31 kHz, 70 Hz Please notice that the ECS and VGA modes require either an ECS or AGA -chipset, and that these modes are limited to 2-bit color for the ECS -chipset and 8-bit color for the AGA chipset. +chip set, and that these modes are limited to 2-bit color for the ECS +chip set and 8-bit color for the AGA chip set. 5.1.2) depth ------------ @@ -842,11 +839,11 @@ Syntax: clock:x x = clock input in MHz for WD33c93 chip. Normal values would be from -8 through 20. The default value depends on your hostadapter(s), +8 through 20. The default value depends on your host adapter(s), default for the A3000 internal controller is 14, for the A2091 it's 8 -and for the GVP hostadapters it's either 8 or 14, depending on the -hostadapter and the SCSI-clock jumper present on some GVP -hostadapters. +and for the GVP host adapters it's either 8 or 14, depending on the +host adapter and the SCSI-clock jumper present on some GVP +host adapters. 5.3.6) next ----------- @@ -875,8 +872,8 @@ The earlier versions of the GVP driver did not handle DMA address-mask settings correctly which made it necessary for some people to use this option, in order to get their GVP controller -running under Linux. These problems have hopefully been solved and the -use of this option is now highly unrecommended! +running under Linux. These problems should now be solved and +further use of this option is highly discouraged! Incorrect use can lead to unpredictable behavior, so please only use this option if you *know* what you are doing and have a reason to do diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/modules.txt linux.ac/Documentation/modules.txt --- linux.vanilla/Documentation/modules.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/modules.txt Fri Jun 4 23:52:54 1999 @@ -59,7 +59,7 @@ Most low-level SCSI drivers: (i.e. aha1542, in2000) All SCSI high-level drivers: disk, tape, cdrom, generic. - Most ethernet drivers: (too many to list, please see the file + Most Ethernet drivers: (too many to list, please see the file ./Documentation/networking/net-modules.txt) Most CDROM drivers: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/mtrr.txt linux.ac/Documentation/mtrr.txt --- linux.vanilla/Documentation/mtrr.txt Thu May 27 22:11:47 1999 +++ linux.ac/Documentation/mtrr.txt Fri Jun 4 23:52:56 1999 @@ -40,7 +40,7 @@ reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 reg02: base=0xf8000000 (3968MB), size= 4MB: write-combining, count=1 -This is for videoram at base address 0xf8000000 and size 4 MBytes. To +This is for video RAM at base address 0xf8000000 and size 4 megabytes. To find out your base address, you need to look at the output of your X server, which tells you where the linear framebuffer address is. A typical line that you may get is: @@ -56,7 +56,7 @@ (--) S3: videoram: 4096k -That's 4 MBytes, which is 0x400000 bytes (in hexadecimal). +That's 4 megabytes, which is 0x400000 bytes (in hexadecimal). A patch is being written for XFree86 which will make this automatic: in other words the X server will manipulate /proc/mtrr using the ioctl() interface, so users won't have to do anything. If you use a diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/nbd.txt linux.ac/Documentation/nbd.txt --- linux.vanilla/Documentation/nbd.txt Sun Nov 8 15:08:49 1998 +++ linux.ac/Documentation/nbd.txt Fri Jun 4 23:52:55 1999 @@ -4,11 +4,11 @@ means, that it works on my computer, and it worked on one of school computers. - What is it: With this compiled in the kernel, linux can use a remote + What is it: With this compiled in the kernel, Linux can use a remote server as one of its block devices. So every time the client computer wants to read /dev/nd0, it sends a request over TCP to the server, which will reply with the data read. This can be used for stations with - low-disk space (or even diskless - if you boot from floppy) to + low disk space (or even diskless - if you boot from floppy) to borrow disk space from another computer. Unlike NFS, it is possible to put any filesystem on it etc. It is impossible to use NBD as a root filesystem, since it requires a user-level program to start. It also diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/00-INDEX linux.ac/Documentation/networking/00-INDEX --- linux.vanilla/Documentation/networking/00-INDEX Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/00-INDEX Fri Jun 4 23:52:54 1999 @@ -13,9 +13,9 @@ alias.txt - info on using alias network devices arcnet-hardware.txt - - tons of info on arcnet, hubs, arcnet card jumper settings, etc. + - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt - - info on the using the arcnet driver itself. + - info on the using the ARCnet driver itself. ax25.txt - info on using AX.25 and NET/ROM code for Linux baycom.txt @@ -69,13 +69,13 @@ smc9.txt - the driver for SMC's 9000 series of Ethernet cards soundmodem.txt - - Linux driver for soundcards as AX.25 modems + - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. tulip.txt - info on using DEC 21040/21041/21140 based PCI Ethernet cards. vortex.txt - - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards. + - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt - Wan router documentation wanpipe.txt diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/CREDITS.ipvs linux.ac/Documentation/networking/CREDITS.ipvs --- linux.vanilla/Documentation/networking/CREDITS.ipvs Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/CREDITS.ipvs Tue Jun 1 16:26:00 1999 @@ -0,0 +1,26 @@ +The contributors of Linux Virtual Server project are listed +as follows in alphabetical order. + + Mike Douglas + Virtual Server Logo. + + Matthew Kellett + Added the loadable load-balancing module to VS-0.5 patch + for kernel 2.0. + + Peter Kese + Suggested the idea of the local-node feature and provided a + local-node prototype patch for VS via tunneling. + Port the VS patch to kernel 2.2 and rewrite of the code + The persistent client connection feature. + + Joseph Mack + Gaving a talk about Linux Virtual Server in the LinuxExpo'99. + + Rob Thomas + Wrote the the "Greased Turkey" document about how to setup a + load-sharing server. (a little bit stale, though) + + Wensong Zhang + Chief author and developer. + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/ChangeLog.ipvs linux.ac/Documentation/networking/ChangeLog.ipvs --- linux.vanilla/Documentation/networking/ChangeLog.ipvs Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/ChangeLog.ipvs Fri Jul 9 14:33:46 1999 @@ -0,0 +1,292 @@ +ChangeLog of Virtual Server patch for Linux 2.2 + +Virtual Server patch for Linux 2.2 - Version 0.7 - July 9, 1999 + +Changes: +- Added a separate masq hash table for IPVS. + +- Added slow timers to expire masq entries. + Slow timers are checked in one second by default. Most overhead + of cascading timers is avoided. + + With this new hash table and slow timers, the system can hold + huge number of masq entries, but make sure that you have + enough free memory. One masq entry costs 128 bytes memory + effectively (Thank Alan Cox), if your box holds 1 million masq + entries (it means that your box can receive 2000 connections per + second if masq expire time is 500 seconds in average.), make sure + that you have 128M free memory. And, thank Alan for suggesting + the early random drop algorithm for masq entries that prevents + the system from running out of memory, I will design and implement + this feature in the near future. + +- Fixed the unlocking bug in the ip_vs_del_dest(). + Thank Ted Pavlic for reporting it. + +---------------------------------------------------------------------- + +Virtual Server patch for Linux 2.2 - Version 0.6 - July 1, 1999 + +Changes: +- Fixed the overflow bug in the ip_vs_procinfo(). + Thank Ted Pavlic for reporting it. + +- Added the functionality to change weight and forwarding + (dispatching) method of existing real server. + This is useful for load-informed scheduling. + +- Added the functionality to change scheduler of virtual service + on the fly. + +- Reorganized some code and changed names of some functions. + This make the code more readable. + +---------------------------------------------------------------------- + +Virtual Server patch for Linux 2.2 - Version 0.5 - June 22, 1999 + +Changes: +- Fixed the bug that LocalNode doesn't work in vs-0.4-2.2.9. + Thank Changwon Kim for + reporting the bug and pointing me the checksum update + problem in the code. + +- some code of VS in the ip_fw_demasquerade was reorganized + so that the packets for VS-Tunneling, VS-DRouting and LocalNode + skip the checksum update. This make the code right and efficient + + +---------------------------------------------------------------------- + +Virtual Server patch for Linux 2.2 - Version 0.4 - June 1, 1999 + +Most of the code was rewritten. The locking and refcnt was changed +The violation of "no floats in kernel mode" rule in the weighted +least-connection scheduling was fixed. This patch is more efficient, +and should be more stable. + + +---------------------------------------------------------------------- + +Virtual Server patch for Linux 2.2 - Version 0.1~0.3 - May 1999 + +Peter Kese ported the VS patch to kernel 2.2, +rewrote the code and loadable scheduling modules. + +========================================================================== + +ChangeLog of Virtual Server patch for Linux 2.0 +---------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.9 - May 1, 1999 + +Differences with virtual server patch version 0.8: + +- Add Virtual Server via Direct Routing + This approach was first implemented in IBM's NetDispatcher. All real + servers have their loopback alias interface configured with the virtual + IP address, the load balancer and the real servers must have one of + their interfaces physically linked by a HUB/Switch. When the packets + destined for the virtual IP address arrives, the load balnacer directly + route them to the real servers, the real servers processing the requests + and return the reply packets directly to the clients. Compared to the + virtual server via IP tunneling approach, this approach doesn't have + tunneling overhead(In fact, this overhead is minimal in most situations), + but requires that one of the load balancer's interfaces and the real + servers' interfaces must be in physical segment. + +- Add more satistics information + The active connection counter and the total connection counter of + each real server were added for all the scheduling algorithms. + +- Add resetting(zeroing) counters + The total connection counters of all real servers can be reset to zero. + +- Change some statements in the masq_expire function and the + ip_fw_demasquerade function, so that ip_masq_free_ports won't become + abnormal number after the masquerading entries for virtual server + are released. + +- Fix the bug of "double unlock on device queue" + Remove the unnecessary function call of skb_device_unlock(skb) in the + ip_pfvs_encapsule function, which sometimes cause "kernel: double + unlock on device queue" waring in the virtual server via tunneling. + +- Many functions of virtual server patch was splitted into the + linux/net/ipv4/ip_masq_pfvs.c. + +- Upgrade ippfvsadm 1.0.2 to ippfvsadm 1.0.3 + Zeroing counters is supported in the new version. The ippfvsadm 1.0.3 + can be used for all kernel with different virtual server options + without rebuilding the program. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.8 - March 6, 1999 + +Differences with virtual server patch version 0.7: + +- Add virtual FTP server support + The original ippfvs via IP tunneling could not be used to + build a virtual FTP server, because the real servers could + not establish data connections to clients. The code was + added to parse the port number in the ftp control data + and create the corresponding masquerading entry for the + coming data connection. + Although the original ippfvs via NAT could be used to build + a virtual server, the data connection was established in + this way. + Real Server port:20 ----> ippfvs: allocate a free masq port + -----> the client port + It is not elegent but time-consuming. Now it was changed + as follows: + Real Server port:20 ----> ippfvs port: 20 + ----> the client port + +- Change the port checking order in the ip_fw_demasquerade() + If the size of masquerade hash table is well chosen, checking + a masquerading entry in the hash table will just require one + hit. It is much efficient than checking port for virtual + services, and there are at least 3 incoming packets for each + connection, which require port checking. So, it is efficient + to check the masquerading hash table first and then check + port for virtual services. + +- Remove a useless statement in the ip_masq_new_pfvs() + The useless statement in the ip_masq_new_pfvs function is + ip_masq_free_ports[masq_proto_num(proto)]++; + which may disturb system. + +- Change the header printing of the ip_pfvs_procinfo() + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.7 - Febuary 10, 1999 + +Differences with virtual server patch version 0.6: + +- Fix a bug in detect the finish of connection for tunneling + or NATing to the local node. + Since the server reply the client directly in tunneling or + NATing to the local node, the load balancer (LinuxDirector) + can only detect a FIN segment. It is mistake that the masq + entry is removed only if both-side FIN segments are detected, + and then the masq entry expires in 15 minutes. For the + situation above, the code was changed to set the masq entry + expire in TCP_FIN_TIMEOUT (2min) when an incoming FIN segment + is detecting. +- Add the patch version printing in the ip_pfvs_procinfo() + It would be easy for users and hackers to know which + virtual server patch version they are running. Thank + Peter Kese for the suggestion. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.6 - Febuary 2, 1999 + +Differences with virtual server patch version 0.5: + +- Add the local node feature in virtual server. + If the local node feature is enabled, the load balancer can + not only redirect the packets of the specified port to the + other servers (remote nodes) to process it, but also can process + the packets locally (local node). Which node is chosen depends on + the scheduling algorithms. + This local node feature can be used to build a virtual server of + a few nodes, for example, 2, 3 or more sites, in which it is a + resource waste if the load balancer is only used to redirect + packets. It is wise to direct some packets to the local node to + process. This feature can also be used to build distributed + identical servers, in which one is too busy to handle requests + locally, then it can seamlessly forward requests to other servers + to process them. + This feature can be applied to both virtual server via NAT and + virtual server via IP tunneling. + Thank Peter Kese for idea of "Two node Virtual + Server" and his single line patch for virtual server via IP + tunneling. +- Remove a useless function call ip_send_check in the virtual + server via IP tunneling code. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.5 - November 25, 1998 + +Differences with virtual server patch version 0.4: + +- Add the feature of virtual server via IP tunneling. + If the ippfvs is enabled using IP tunneling, the load balancer + chooses a real server from a cluster based on a scheduling algorithm, + encapsules the packet and forwards it to the chosen server. All real + servers are configured with "ifconfig tunl0 up". + When the chosen server receives the encapsuled packet, it decapsules + the packet, processes the request and returns the reply packets + directly to the client without passing the load balancer. This can + greatly increase the scalability of virtual server. +- Fix a bug in the ip_portfw_del() for the weighted RR scheduling. + The bug in version 0.4 is when the weighted round-robin scheduling + is used, deleting the last rule for a virtual server will report + "setsockopt failed: Invalid argument" warning, in fact the last + rule is deleted but the gen_scheduling_seq() works on a null list + and causes that warning. +- Add and modify some description for virtual server options in + the Linux kernel configuration help texts. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.4 - November 12, 1998 + +Differences with virtual server patch version 0.3: + +- Fix a memory access error bug. + The set_serverpointer_null() function is added to scan all the existing + ip masquerading records for its server pointer which points to the + server specified and set it null. It is useful when administrators + delete a real server or all real servers, those pointers pointing to + the server must be set null. Otherwise, decreasing the connection + counter of the server may cause memory access error when the connection + terminates or timeout. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.3 - November 10, 1998 + +Differences with virtual server patch version 0.2: + +- Change the simple round-robin scheduling to the weighted round-robin + scheduling. Simple is a special instance of the weighted round-robin + scheduling when the weights of the servers are the same. +- The scheduling algorithm, originally called the weighted round-robin + scheduling in version 0.2, actually is the weighted least-connection + scheduling. So the concept is clarified here. +- Add the least-connection scheduling algorithm. Although it is a + special instance of the weighted least-connection scheduling algorithm, + it is used to avoid dividing the weight in looking up servers when + the weights of the servers are the same, so the overhead of scheduling + can be minimized in this case. +- Change the type of the server load variables, curr_load and least_load, + from integer to float in the weighted least-connection scheduling. + It can make a better load-balancing when the weights specified are high. +- Merge the original two patches into one. Users have to specify which + scheduling algorithm is used, the weighted round-robin scheduling, + the least-connection scheduling, or the weighted least-connection + scheduling, before rebuild the kernel. +- Change the ip_pfvs_proc function to make the output of the port + forwarding & virtual server table more beautiful. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.2 - May 28, 1998 + +Differences with virtual server patch version 0.1: + +- Add the weighted round-robin scheduling patch. + +-------------------------------------------------------------------- + +Virtual Server Patch for Linux - Version 0.1 - May 26, 1998 + +- Implement the infrastructure of virtual server. +- Implement the simple round-robin scheduling algorithm. + +-------------------------------------------------------------------- diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/Configurable linux.ac/Documentation/networking/Configurable --- linux.vanilla/Documentation/networking/Configurable Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/Configurable Fri Jun 4 23:52:54 1999 @@ -20,11 +20,11 @@ 7000 Others are already accessible via the related user space programs. -For example, MAX_WINDOW has a default of 32k which is a good choice for -modern hardware, but if you have a slow (8 bit) ethercard and/or a slow +For example, MAX_WINDOW has a default of 32 k which is a good choice for +modern hardware, but if you have a slow (8 bit) Ethernet card and/or a slow machine, then this will be far too big for the card to keep up with fast -Tx'ing machines on the same net, resulting in overruns and receive errors. -A value of about 4k would be more appropriate, which can be set via: +machines transmitting on the same net, resulting in overruns and receive errors. +A value of about 4 k would be more appropriate, which can be set via: # route add -net 192.168.3.0 window 4096 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/DLINK.txt linux.ac/Documentation/networking/DLINK.txt --- linux.vanilla/Documentation/networking/DLINK.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/DLINK.txt Fri Jun 4 23:52:54 1999 @@ -18,8 +18,8 @@ pocket adapters, for the parallel port on a Linux based machine. Some adapter "clones" will also work. Xircom is _not_ a clone... These drivers _can_ be used as loadable modules, - and were developed for use on Linux v1.1.13 and above. - For use on Linux v1.0.X, or earlier releases, see below. + and were developed for use on Linux 1.1.13 and above. + For use on Linux 1.0.X, or earlier releases, see below. I have used these drivers for NFS, ftp, telnet and X-clients on remote machines. Transmissions with ftp seems to work as @@ -57,7 +57,7 @@ de620.h Macros for de620.c If you are upgrading from the d-link tar release, there will - also be a "dlink-patches" file that will patch Linux v1.1.18: + also be a "dlink-patches" file that will patch Linux 1.1.18: linux/drivers/net/Makefile linux/drivers/net/CONFIG linux/drivers/net/MODULES @@ -162,10 +162,10 @@ 6. USING THE DRIVERS WITH EARLIER RELEASES. - The later v1.1.X releases of the Linux kernel include some + The later 1.1.X releases of the Linux kernel include some changes in the networking layer (a.k.a. NET3). This affects these drivers in a few places. The hints that follow are - _not_ tested by me, since I don't have the diskspace to keep + _not_ tested by me, since I don't have the disk space to keep all releases on-line. Known needed changes to date: - release patchfile: some patches will fail, but they should diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/README.ipvs linux.ac/Documentation/networking/README.ipvs --- linux.vanilla/Documentation/networking/README.ipvs Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/README.ipvs Fri Jul 9 13:51:54 1999 @@ -0,0 +1,93 @@ +README of Virtual Server Patch for Linux 2.2.10 +-------------------------------------------------------------------- + +Virtual Server Patch for Linux 2.2.10 - Version 0.7 - July 9, 1999 + +Copyright (c) 1998,1999 by Wensong Zhang, Peter Kese. +This is free software. See below for details. + +The ipvs is IP Virtual Server support in Linux kernel, which can be used +to build a high-performance and highly available server. Check out the +Linux Virtual Server Project homepage on the World Wide Web: + http://proxy.iinchina.net/~wensong/ippfvs/ +for the most recent information and original sources about ipvs. + +We now call the Linux box running ipvs LinuxDirector. Thank +Robert Thomas for this name, I love it. :-) + +This patch (Version 0.7) is for the Linux kernel 2.2.10. See the ChangeLog +for how the code has been improved and what new features it has now. + +To rebuild a Linux kernel with virtual server support, first get a clean +copy of the Linux kernel source of the right version and apply the patch +to the kernel. The commands can be as follows: + cd /usr/src/linux + cat /ipvs-0.7-2.2.10.patch | patch -p1 +Then make sure the following kernel compile options at least are selected +via "make menuconfig" or "make xconfig". + +Kernel Compile Options: + +Code maturity level options --- + [*] Prompt for development and/or incomplete code/drivers +Networking options --- + [*] Network firewalls + .... + [*] IP: firewalling + [*] IP: always defragment (required for masquerading) + .... + [*] IP: masquerading + .... + [*] IP: masquerading virtual server support + (12) IP masquerading table size (the Nth power of 2) + < > IPVS: round-robin scheduling + < > IPVS: weighted round-robin scheduling + < > IPVS: weighted least-connection scheduling + < > IPVS: persistent client connection scheduling +Note that you can compile scheduling algorithms in kernel or as modules. + +Finally, rebuild the kernel. Once you have your kernel properly built, +update your system kernel and reboot. + +Note that there are three request dispatching techniques existing together +in the LinuxDirector, and there are also three scheduling algorithms +implemented. Both the VS via IP Tunneling and the VS via Direct Routing +can greatly increase the scalability of virtual server. If the VS-Tunneling +is selected, it requires that all the servers must be configured with + ifconfig tunl0 netmask 255.255.255.255 +If the VS-DRouting is chosen, it requires that all servers must be configured +with the following command: + ifconfig lo:0 netmask 255.255.255.255 +The localnode feature can make that the LinuxDiretor can not only redirect +packets to other servers, but also process packets locally. + +Thanks must go to other contributors, check the CREDITS file to know +who they are. + +There is a mailing list for virtual server. You are welcome to talk about +building the virtual server kernel, using the virtual server and making +the virtual server better there. :-) To subscribe, send a message to + majordomo@iinchina.net +with the body of "subscribe linux-virtualserver". + + +Wensong Zhang + + +-------------------------------------------------------------------- + +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. + +-------------------------------------------------------------------- diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet-hardware.txt linux.ac/Documentation/networking/arcnet-hardware.txt --- linux.vanilla/Documentation/networking/arcnet-hardware.txt Sat Jan 9 21:50:35 1999 +++ linux.ac/Documentation/networking/arcnet-hardware.txt Fri Jun 4 23:52:54 1999 @@ -20,14 +20,14 @@ ARCnet is a network type which works in a way similar to popular Ethernet networks but which is also different in some very important ways. -First of all, you can get ARCnet cards in at least two speeds: 2.5Mbps -(slower than Ethernet) and 100Mbps (faster than normal Ethernet). In fact, +First of all, you can get ARCnet cards in at least two speeds: 2.5 Mbps +(slower than Ethernet) and 100 Mbps (faster than normal Ethernet). In fact, there are others as well, but these are less common. The different hardware types, as far as I'm aware, are not compatible and so you cannot wire a -100Mbps card to a 2.5Mbps card, and so on. From what I hear, my driver does -work with 100Mbps cards, but I haven't been able to verify this myself, -since I only have the 2.5Mbps variety. It is probably not going to saturate -your 100Mbps card. Stop complaining :) +100 Mbps card to a 2.5 Mbps card, and so on. From what I hear, my driver does +work with 100 Mbps cards, but I haven't been able to verify this myself, +since I only have the 2.5 Mbps variety. It is probably not going to saturate +your 100 Mbps card. Stop complaining. :) You also cannot connect an ARCnet card to any kind of Ethernet card and expect it to work. @@ -52,17 +52,17 @@ useful for realtime networks. In addition, all known ARCnet cards have an (almost) identical programming -interface. This means that with one "arcnet" driver you can support any -card; whereas, with Ethernet, each manufacturer uses what is sometimes a +interface. This means that with one ARCnet driver you can support any +card, whereas with Ethernet each manufacturer uses what is sometimes a completely different programming interface, leading to a lot of different, sometimes very similar, Ethernet drivers. Of course, always using the same programming interface also means that when high-performance hardware -facilities like PCI busmastering DMA appear, it's hard to take advantage of +facilities like PCI bus mastering DMA appear, it's hard to take advantage of them. Let's not go into that. One thing that makes ARCnet cards difficult to program for, however, is the limit on their packet sizes; standard ARCnet can only send packets that are -up to 508 bytes in length. This is smaller than the internet "bare minimum" +up to 508 bytes in length. This is smaller than the Internet "bare minimum" of 576 bytes, let alone the Ethernet MTU of 1500. To compensate, an extra level of encapsulation is defined by RFC1201, which I call "packet splitting," that allows "virtual packets" to grow as large as 64K each, @@ -1005,9 +1005,9 @@ only (the JP0 jumper is hardwired), and BNC only. This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC, -nowhere else, not even on the few xeroxed sheets from the manual). +nowhere else, not even on the few Xeroxed sheets from the manual). -SMC Arcnet Board Type LCS-8830-T +SMC ARCnet Board Type LCS-8830-T ------------------------------------ | | @@ -1070,7 +1070,7 @@ DIP Switches 1-5 of SW2 encode the RAM and ROM Address Range: -Switches Ram Rom +Switches RAM ROM 12345 Address Range Address Range 00000 C:0000-C:07ff C:2000-C:3fff 10000 C:0800-C:0fff @@ -1170,11 +1170,11 @@ DIP Switches: The DIP switches accessible on the accessible end of the card while - it is installed, is used to set the arcnet address. There are 8 + it is installed, is used to set the ARCnet address. There are 8 switches. Use an address from 1 to 254. Switch No. - 12345678 Arcnet address + 12345678 ARCnet address ----------------------------------------- 00000000 FF (Don't use this!) 00000001 FE @@ -1222,7 +1222,7 @@ from the upper memory regions, and then attempting to load ARCETHER using these addresses. - I recommend using an arcnet memory address of 0xD000, and putting + I recommend using an ARCnet memory address of 0xD000, and putting the EMS page frame at 0xC000 while using QEMM stealth mode. That way, you get contiguous high memory from 0xD100 almost all the way the end of the megabyte. @@ -1687,7 +1687,7 @@ |____________________________________________| |__| -UM9065L : Arcnet Controller +UM9065L : ARCnet Controller SW 1 : Shared Memory Address and I/O Base @@ -1800,7 +1800,7 @@ J1-J5 IRQ Select J6-J21 Unknown (Probably extra timeouts & ROM enable ...) LED1 Activity LED -BNC Coax connector (STAR arcnet) +BNC Coax connector (STAR ARCnet) RAM 2k of SRAM ROM Boot ROM socket UFS Unidentified Flying Sockets @@ -1905,7 +1905,7 @@ ------------------------ - from Vojtech Pavlik -This is another SMC 90C65 based arcnet card. I couldn't identify the +This is another SMC 90C65-based ARCnet card. I couldn't identify the manufacturer, but it might be DataPoint, because the card has the original arcNet logo in its upper right corner. @@ -1942,9 +1942,9 @@ SW2 1-8: Node ID Select SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable BNC Coax connector -XTAL 20MHz Crystal +XTAL 20 MHz Crystal Setting the Node ID @@ -2081,11 +2081,11 @@ 6-8 Base I/O Address Select SW2 1-8 Node ID Select (ID0-ID7) J1 IRQ Select -J2 Rom Enable +J2 ROM Enable J3 Extra Timeout LED1 Activity LED -BNC Coax connector (BUS arcnet) -RJ Twisted Pair Connector (daisychain) +BNC Coax connector (BUS ARCnet) +RJ Twisted Pair Connector (daisy chain) Setting the Node ID @@ -2419,7 +2419,7 @@ Legend: -COM90C65: Arcnet Probe +COM90C65: ARCnet Probe S1 1-8: Node ID Select S2 1-3: I/O Base Address Select 4-6: Memory Base Address Select @@ -2791,7 +2791,7 @@ SW2 1-8: Node ID Select (ID0-ID7) SW3 1-5: IRQ Select 6-7: Extra Timeout - 8 : Rom Enable + 8 : ROM Enable JP1 Led connector BNC Coax connector @@ -3089,7 +3089,7 @@ 0 = Jumper Installed 1 = Open -Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O +Top Jumper line Bit 7 = ROM Enable 654=Memory location 321=I/O Settings for Memory Location (Top Jumper Line) 456 Address selected diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/arcnet.txt linux.ac/Documentation/networking/arcnet.txt --- linux.vanilla/Documentation/networking/arcnet.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/arcnet.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,3 @@ - ---------------------------------------------------------------------------- NOTE: See also arcnet-hardware.txt in this directory for jumper-setting and cabling information if you're like many of us and didn't happen to get a @@ -92,10 +91,10 @@ http://www.perftech.com/ or ftp to ftp.perftech.com. Novell makes a networking stack for DOS which includes ARCnet drivers. Try -ftp'ing to ftp.novell.com. +FTPing to ftp.novell.com. You can get the Crynwr packet driver collection (including arcether.com, the -one you'll want to use with arcnet cards) from +one you'll want to use with ARCnet cards) from oak.oakland.edu:/simtel/msdos/pktdrvr. It won't work perfectly on a 386+ without patches, though, and also doesn't like several cards. Fixed versions are available on my WWW page, or via e-mail if you don't have WWW @@ -183,7 +182,7 @@ ----------------------- Configure and rebuild Linux. When asked, answer 'm' to "Generic ARCnet -support" and to support for your ARcnet chipset if you want to use the +support" and to support for your ARCnet chipset if you want to use the loadable module. You can also say 'y' to "Generic ARCnet support" and 'm' to the chipset support if you wish. @@ -269,7 +268,7 @@ Arcether client, assuming you remember to load winpkt of course. LAN Manager and Windows for Workgroups: These programs use protocols that - are incompatible with the internet standard. They try to pretend + are incompatible with the Internet standard. They try to pretend the cards are Ethernet, and confuse everyone else on the network. However, v2.00 and higher of the Linux ARCnet driver supports this @@ -288,7 +287,7 @@ you're completely insane, and/or you need to build some kind of hybrid network that uses both encapsulation types. -OS2: I've been told it works under Warp Connect with an ARCnet driver from +OS/2: I've been told it works under Warp Connect with an ARCnet driver from SMC. You need to use the 'arc0e' interface for this. If you get the SMC driver to work with the TCP/IP stuff included in the "normal" Warp Bonus Pack, let me know. @@ -309,7 +308,7 @@ The ARCnet driver v2.10 ALPHA supports three protocols, each on its own "virtual network device": - arc0 - RFC1201 protocol, the official internet standard which just + arc0 - RFC1201 protocol, the official Internet standard which just happens to be 100% compatible with Novell's TRXNET driver. Version 1.00 of the ARCnet driver supported _only_ this protocol. arc0 is the fastest of the three protocols (for @@ -331,13 +330,13 @@ reasons yet to be determined. (Probably it's the smaller MTU that does it.) - arc0s - The "[s]imple" RFC1051 protocol is the "previous" internet + arc0s - The "[s]imple" RFC1051 protocol is the "previous" Internet standard that is completely incompatible with the new standard. Some software today, however, continues to support the old standard (and only the old standard) including NetBSD and AmiTCP. RFC1051 also does not support RFC1201's packet splitting, and the MTU of 507 is still - smaller than the internet "requirement," so it's quite + smaller than the Internet "requirement," so it's quite possible that you may run into problems. It's also slower than RFC1201 by about 25%, for the same reason as arc0e. @@ -388,16 +387,16 @@ Linux but runs the free Microsoft LANMAN Client instead. Worse, one of the Linux computers (freedom) also has a modem and acts as - a router to my internet provider. The other Linux box (insight) also has + a router to my Internet provider. The other Linux box (insight) also has its own IP address and needs to use freedom as its default gateway. The - XT (patience), however, does not have its own internet IP address and so + XT (patience), however, does not have its own Internet IP address and so I assigned it one on a "private subnet" (as defined by RFC1597). To start with, take a simple network with just insight and freedom. Insight needs to: - talk to freedom via RFC1201 (arc0) protocol, because I like it more and it's faster. - - use freedom as its internet gateway. + - use freedom as its Internet gateway. That's pretty easy to do. Set up insight like this: ifconfig arc0 insight @@ -417,20 +416,20 @@ /* and default gateway is configured by pppd */ Great, now insight talks to freedom directly on arc0, and sends packets - to the internet through freedom. If you didn't know how to do the above, + to the Internet through freedom. If you didn't know how to do the above, you should probably stop reading this section now because it only gets worse. Now, how do I add patience into the network? It will be using LANMAN Client, which means I need the arc0e device. It needs to be able to talk to both insight and freedom, and also use freedom as a gateway to the - internet. (Recall that patience has a "private IP address" which won't - work on the internet; that's okay, I configured Linux IP masquerading on + Internet. (Recall that patience has a "private IP address" which won't + work on the Internet; that's okay, I configured Linux IP masquerading on freedom for this subnet). So patience (necessarily; I don't have another IP number from my provider) has an IP address on a different subnet than freedom and - insight, but needs to use freedom as an internet gateway. Worse, most + insight, but needs to use freedom as an Internet gateway. Worse, most DOS networking programs, including LANMAN, have braindead networking schemes that rely completely on the netmask and a 'default gateway' to determine how to route packets. This means that to get to freedom or @@ -449,7 +448,7 @@ This way, freedom will send all packets for patience through arc0e, giving its IP address as gatekeeper (on the private subnet). When it - talks to insight or the internet, it will use its "freedom" internet IP + talks to insight or the Internet, it will use its "freedom" Internet IP address. You will notice that we haven't configured the arc0e device on insight. @@ -473,7 +472,7 @@ [RFC1201 NETWORK] [ETHER-ENCAP NETWORK] - (registered internet subnet) (RFC1597 private subnet) + (registered Internet subnet) (RFC1597 private subnet) (IP Masquerade) /---------------\ * /---------------\ @@ -523,7 +522,7 @@ Once the driver is running, you can run the arcdump shell script (available from me or in the full ARCnet package, if you have it) as root to list the contents of the arcnet buffers at any time. To make any sense at all out of -this, you should grab the pertinent RFC's. (some are listed near the top of +this, you should grab the pertinent RFCs. (some are listed near the top of arcnet.c). arcdump assumes your card is at 0xD0000. If it isn't, edit the script. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/baycom.txt linux.ac/Documentation/networking/baycom.txt --- linux.vanilla/Documentation/networking/baycom.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/baycom.txt Fri Jun 4 23:52:54 1999 @@ -31,7 +31,7 @@ Its devices are called bcp0 through bcp3. baycom_epp: - This driver supports the epp modem. + This driver supports the EPP modem. Its devices are called bce0 through bce3. This driver is work-in-progress. @@ -60,10 +60,10 @@ an additional power supply. Furthermore, it incorporates a carrier detect circuitry. -epp: This is a high speed modem adaptor that connects to an enhanced parallel port. +EPP: This is a high-speed modem adaptor that connects to an enhanced parallel port. Its target audience is users working over a high speed hub (76.8kbit/s). -eppfpga: This is a redesign of the epp adaptor. +eppfpga: This is a redesign of the EPP adaptor. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/cs89x0.txt linux.ac/Documentation/networking/cs89x0.txt --- linux.vanilla/Documentation/networking/cs89x0.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/cs89x0.txt Fri Jun 4 23:52:54 1999 @@ -203,7 +203,7 @@ * io=### - specify IO address (200h-360h) * irq=## - specify interrupt level * mmode=##### - specify memory base address -* dma=# - specify dma channel +* dma=# - specify DMA channel * media=rj45 - specify media type or media=2 or media=aui @@ -412,33 +412,33 @@ assigned during hardware configuration. The following tests are performed: * IO Register Read/Write Test - The IO Register Read/Write test insures that the CS8900/20 can be + The IO Register Read/Write test ensures that the CS8900/20 can be accessed in IO mode, and that the IO base address is correct. * Shared Memory Test - The Shared Memory test insures the CS8900/20 can be accessed in memory + The Shared Memory test ensures the CS8900/20 can be accessed in memory mode and that the range of memory addresses assigned does not conflict with other devices in the system. * Interrupt Test - The Interrupt test insures there are no conflicts with the assigned IRQ + The Interrupt test ensures there are no conflicts with the assigned IRQ signal. * EEPROM Test - The EEPROM test insures the EEPROM can be read. + The EEPROM test ensures the EEPROM can be read. * Chip RAM Test - The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is working properly. * Internal Loop-back Test - The Internal Loop Back test insures the adapter's transmitter and + The Internal Loop Back test ensures the adapter's transmitter and receiver are operating properly. If this test fails, make sure the adapter's cable is connected to the network (check for LED activity for example). * Boot PROM Test - The Boot PROM test insures the Boot PROM is present, and can be read. + The Boot PROM test ensures the Boot PROM is present, and can be read. Failure indicates the Boot PROM was not successfully read due to a hardware problem or due to a conflicts on the Boot PROM address assignment. (Test only applies if the adapter is configured to use the @@ -564,7 +564,7 @@ Telephone :(800) 888-5016 (from inside U.S. and Canada) :(512) 442-7555 (from outside the U.S. and Canada) Fax :(512) 912-3871 -Email :ethernet@crystal.cirrus.com +E-mail :ethernet@crystal.cirrus.com WWW :http://www.crystal.com diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/dgrs.txt linux.ac/Documentation/networking/dgrs.txt --- linux.vanilla/Documentation/networking/dgrs.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/dgrs.txt Fri Jun 4 23:52:54 1999 @@ -1,4 +1,4 @@ - The Digi Intl. RightSwitch SE-X (dgrs) Device Driver + The Digi International RightSwitch SE-X (dgrs) Device Driver This is a Linux driver for the Digi International RightSwitch SE-X EISA and PCI boards. These are 4 (EISA) or 6 (PCI) port Ethernet diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/eql.txt linux.ac/Documentation/networking/eql.txt --- linux.vanilla/Documentation/networking/eql.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/eql.txt Fri Jun 4 23:52:54 1999 @@ -471,58 +471,3 @@ able to data at over 48Kb/s [ISDN link -Simon]. I managed a transfer of up to 7.5 Kbyte/s on one go, but averaged around 6.4 Kbyte/s, which I think is pretty cool. :) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/load-balancing.txt linux.ac/Documentation/networking/load-balancing.txt --- linux.vanilla/Documentation/networking/load-balancing.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/load-balancing.txt Fri Jun 4 23:52:54 1999 @@ -0,0 +1,122 @@ +Load balancing using multipaths (patch version: 4) +================================================== + +Contact Guus Sliepen if you need help, want to know +more, have remarks or further idea's with relation to this. + +Intro +----- + +If you have multiple physical network links to another computer, and you want +some kind of load balancing, you can now do so. Please note that this only +applies to IPv4 traffic, not for IPX, IPv6 or any other protocol (yet). + +Needed +----- + +* LATEST iproute package from ftp://ftp.inr.ac.ru/ip-routing/ +* CONFIG_IP_ROUTE_MULTIPATH enabled in kernel configuration (it's in + Networking options, below the Advanced Router option you'll have to enable + too) +* Ofcourse you must also have patched your kernel and recompiled it for this + feature to be enabled. + +To do +----- + +* Make sure the devices you want to combine are up, they all accept the + packets you want to send (ie, they must all have the same IP address/netmask + or something clever to get the same result) +* Just to make sure, remove any routes via those devices (route del ...) +* Now add all routes via one iproute command using the 'nexthops' statement: + + ip route add / equalize \\ + nexthop dev \\ + nexthop dev \\ + nexthop ... + +* Just to make sure, flush route cache: + + echo 1 >/proc/sys/net/ipv4/route/flush + +Example +------- + +This is an example showing how to make a 20 Mbit connection between two +computers using 2 10 Mbit ethernet cards per computer. Computer 1 has IP +192.168.1.1 and computer 2 has IP 192.168.1.2. We start from scratch: + +[computer1]~/>ifconfig eth0 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ifconfig eth1 192.168.1.1 netmask 255.255.255.0 +[computer1]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer1]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer1]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +[computer2]~/>ifconfig eth0 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ifconfig eth1 192.168.1.2 netmask 255.255.255.0 +[computer2]~/>route del -net 192.168.1.0 netmask 255.255.255.0 +[computer2]~/>ip route add 192.168.1.0/24 equalize nexthop dev eth0 nexthop dev eth1 +[computer2]~/>echo 1 >/proc/sys/net/ipv4/route/flush + +You can even add more computers, just replace the x in 192.168.1.x with the +number of your computer, and make sure all eth0's are connected to each other +and all eth1's. You can also use more devices, just ifconfig them all and +remove the default routes that are generated, and add extra nexthops. + +Notes +----- + +If you want to add a gateway entry in your routing table, and want it to be +balanced too, you first have to make singlepath entries for every network +interface you want to use, after that add the gateway with all the nexthops +filled in, then delete the singlepath routes and then add the normal +multipath route. + +Older patch versions used a /proc entry to control load-balancing. This does +not work anymore. You should use the 'equalize' flag instead while adding new +routes. You need a fresh version of iproute for that. + +Status +------ + +Packet type: Balanced? Note +---------------------------------------------------------------------- +ARP no But we don't want them to ;) +ICMP yes +Connectionless UDP yes +Connected UDP yes +Broadcast UDP no Would be nice if it would, + but this is rarely used for + high bandwith data transfers. +TCP yes At least all data packets are, + maybe some control packets are + not. + +Bugs +---- + +It is possible that under extreme conditions the kernel will run out of +memory for network buffers. This might be temporarily, but if you're unlucky +it is permanent and then your network will be dead. However, completely +flooding my 486/66 with 2.5 megabyte per second random traffic only gave an +occasional 'Couldn't allocate a sk_buff of size 1514' message, but that was +not permanent, and there were no crashes. + +Technically +----------- + +Load balancing needed a slight adjustment to the unpatched linux kernel, +because of the route cache. Multipath is an option already found in the old +2.1.x kernels. However, once a packet arrives, and it matches a multipath +route, a (quasi random) device out of the list of nexthops is taken for its +destination. That's okay, but after that the kernel puts everything into a +hash table, and the next time a packet with the same source/dest/tos arrives, +it finds it is in the hash table, and routes it via the same device as last +time. The adjustment I made is as follows: If the kernel sees that the route +to be taken has got the 'equalize' flag set, it not only selects the random +device, but also tags the packet with the RTCF_EQUALIZE flag. If another +packet of the same kind arrives, it is looked up in the hash table. It then +checks if our flag is set, and if so, it deletes the entry in the cache and +has to recalculate the destination again. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/multicast.txt linux.ac/Documentation/networking/multicast.txt --- linux.vanilla/Documentation/networking/multicast.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/multicast.txt Fri Jun 4 23:52:54 1999 @@ -1,11 +1,13 @@ -Behaviour of cards under Multicast. This is how they currently -behave not what the hardware can do - i.e. the lance driver doesn't -use its filter, even though the code for loading it is in the DEC -lance based driver. +Behaviour of Cards Under Multicast +================================== -The following multicast requirements are needed +This is how they currently behave, not what the hardware can do--for example, +the Lance driver doesn't use its filter, even though the code for loading +it is in the DEC Lance-based driver. + +The following are requirements for multicasting ----------------------------------------------- -Appletalk Multicast hardware filtering not important but +AppleTalk Multicast hardware filtering not important but avoid cards only doing promisc IP-Multicast Multicast hardware filters really help IP-MRoute AllMulti hardware filters are of no help diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/olympic.txt linux.ac/Documentation/networking/olympic.txt --- linux.vanilla/Documentation/networking/olympic.txt Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/networking/olympic.txt Wed Jun 9 20:08:19 1999 @@ -0,0 +1,75 @@ + +IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README + +Release 0.2.0 - Release + June 8th 1999 Peter De Schrijver & Mike Phillips + + +Thanks: +Erik De Cock, Adrian Bridgett and Frank Fiene for their +patience and testing. +Paul Norton without whose tr.c code we would have had +a lot more work to do. + +Options: + +The driver accepts three options: ringspeed, pkt_buf_sz, and +message_level. + +These options can be specified differently for each card found. + +ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will +make the card autosense the ringspeed and join at the appropriate speed, +this will be the default option for most people. 4 or 16 allow you to +explicitly force the card to operate at a certain speed. The card will fail +if you try to insert it at the wrong speed. (Although some hubs will allow +this so be *very* careful). The main purpose for explicitly setting the ring +speed is for when the card is first on the ring. In autosense mode, if the card +cannot detect any active monitors on the ring it will not open, so you must +re-init the card at the appropriate speed. Unfortunately at present the only +way of doing this is rmmod and insmod which is a bit tough if it is compiled +in the kernel. + +pkt_buf_sz: This is this initial receive buffer allocation size. This will +default to 4096 if no value is entered. You may increase performance of the +driver by setting this to a value larger than the network packet size, although +the driver now re-sizes buffers based on MTU settings as well. + +message_level: Controls level of messages created by the driver. Defaults to 0: +which only displays start-up and critical messages. Presently any non-zero +value will display all soft messages as well. NB This does not turn +debuging messages on, that must be done by modified the source code. + +Multi-card: + +The driver will detect multiple cards and will work with shared interrupts, +each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The +driver should also happily reside in the system with other drivers. It has +been tested with ibmtr.c running, and I personnally have had one Olicom PCI +card and two IBM olympic cards (all on the same interrupt), all running +together. + +Variable MTU size: + +The driver can handle a MTU size upto either 4500 or 18000 depending upon +ring speed. The driver also changes the size of the receive buffers as part +of the mtu re-sizing, so if you set mtu = 18000, you will need to be able +to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring +position = 296,000 bytes of memory space, plus of course anything +necessary for the tx sk_buff's. Remember this is per card, so if you are +building routers, gateway's etc, you could start to use a lot of memory +real fast. + +Network Monitor Mode: + +By modifying the #define OLYMPIC_NETWORK_MONITOR from 0 to 1 in the +source code the driver will implement a quasi network monitoring +mode. All unexpected MAC frames (beaconing etc.) will be received +by the driver and the source and destination addresses printed. +Also an entry will be added in /proc/net called olympic_tr. This +displays low level information about the configuration of the ring and +the adapter. This feature has been designed for network adiministrators +to assist in the diagnosis of network / ring problems. + +6/8/99 Peter De Schrijver and Mike Phillips + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/policy-routing.txt linux.ac/Documentation/networking/policy-routing.txt --- linux.vanilla/Documentation/networking/policy-routing.txt Sun Nov 8 15:08:47 1998 +++ linux.ac/Documentation/networking/policy-routing.txt Fri Jun 4 23:52:54 1999 @@ -83,7 +83,7 @@ 2. Opposite case. Just forget all that you know about routing tables. Every rule is supplied with its own gateway, device info. record. This approach is not appropriate for automated - route maintanance, but it is ideal for manual configuration. + route maintenance, but it is ideal for manual configuration. HOWTO: iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ] diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/networking/z8530drv.txt linux.ac/Documentation/networking/z8530drv.txt --- linux.vanilla/Documentation/networking/z8530drv.txt Sun Nov 8 15:08:46 1998 +++ linux.ac/Documentation/networking/z8530drv.txt Fri Jun 4 23:52:54 1999 @@ -252,7 +252,7 @@ speed 1200 # the default baudrate clock dpll # clock source: - # dpll = normal halfduplex operation + # dpll = normal half duplex operation # external = MODEM provides own Rx/Tx clock # divider = use full duplex divider if # installed (1) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/Introduction linux.ac/Documentation/sound/Introduction --- linux.vanilla/Documentation/sound/Introduction Thu May 27 22:11:48 1999 +++ linux.ac/Documentation/sound/Introduction Fri Jul 2 19:32:40 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 SoundBlasster. + +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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sound/OPL3-SA2 linux.ac/Documentation/sound/OPL3-SA2 --- linux.vanilla/Documentation/sound/OPL3-SA2 Tue Jan 19 02:57:22 1999 +++ linux.ac/Documentation/sound/OPL3-SA2 Sat Jun 12 20:06:07 1999 @@ -46,6 +46,21 @@ then email me if you are willing to experiment in an effort to make it work. +************************************************************************ +* I have now had two such machines, and I have fixed this to work +* properly when built into the kernel. The Toshiba Libretto series, or +* at least models 70CT and 110CT which I have owned, use a Yamaha +* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5, +* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1). All these +* configuration settings can be gathered by booting another OS which +* recognizes the card already. +* +* I have made things 'just work' for the non-modular case on such +* machines when configured properly. +* +* David Luyer +************************************************************************ + If you are using isapnp, follow the directions in its documentation to produce a configuration file. Here is the relevant excerpt I use for my SAx card from my isapnp.conf: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysctl/README linux.ac/Documentation/sysctl/README --- linux.vanilla/Documentation/sysctl/README Fri Apr 16 22:10:51 1999 +++ linux.ac/Documentation/sysctl/README Tue Jun 29 02:37:57 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysctl/fs.txt linux.ac/Documentation/sysctl/fs.txt --- linux.vanilla/Documentation/sysctl/fs.txt Fri Apr 16 22:10:51 1999 +++ linux.ac/Documentation/sysctl/fs.txt Tue Jun 29 02:37:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysctl/kernel.txt linux.ac/Documentation/sysctl/kernel.txt --- linux.vanilla/Documentation/sysctl/kernel.txt Fri Apr 16 22:10:51 1999 +++ linux.ac/Documentation/sysctl/kernel.txt Tue Jun 29 02:37:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysctl/sunrpc.txt linux.ac/Documentation/sysctl/sunrpc.txt --- linux.vanilla/Documentation/sysctl/sunrpc.txt Fri Apr 16 22:10:51 1999 +++ linux.ac/Documentation/sysctl/sunrpc.txt Tue Jun 29 02:37:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysctl/vm.txt linux.ac/Documentation/sysctl/vm.txt --- linux.vanilla/Documentation/sysctl/vm.txt Thu May 27 22:11:48 1999 +++ linux.ac/Documentation/sysctl/vm.txt Tue Jun 29 02:37:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/sysrq.txt linux.ac/Documentation/sysrq.txt --- linux.vanilla/Documentation/sysrq.txt Sun Nov 8 15:08:50 1998 +++ linux.ac/Documentation/sysrq.txt Fri Jun 4 23:52:56 1999 @@ -9,8 +9,8 @@ * How do I enable the magic SysRQ key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You need to say yes to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when -configuring the kernel. This option is only available it 2.1.x or later +You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when +configuring the kernel. This option is only available in 2.1.x or later kernels. * How do I use the magic SysRQ key? diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Documentation/video4linux/README.buz linux.ac/Documentation/video4linux/README.buz --- linux.vanilla/Documentation/video4linux/README.buz Thu Jan 1 01:00:00 1970 +++ linux.ac/Documentation/video4linux/README.buz Thu Jul 1 19:06:29 1999 @@ -0,0 +1,212 @@ +Iomega Buz Driver for Linux +=========================== + +by Rainer Johanni + +Compiling and Loading the Driver +================================ + +You must run a 2.2.x kernel in order to use this driver. + +To compile the driver, just type make. + +Besides the files in this directory, the driver needs the +'videodev' and the 'i2c' module from the Linux kernel. +In order to get these modules available, enable module support +for VIDEODEV and BTTV (which implies i2c) in your kernel +configuration. You find these devices in the menu +"Character Devices" in your Kernel Configuration. + +Before you load the driver you must have a video device +at major device node 81. If you don't have it yet, do the +following (as root!): + +cd /dev +mknod video0 c 81 0 +ln -s video0 video + +Edit the 'update' script if you want to give the driver +special options and then type (as root) + +./update + +to insert all the necessary modules into the kernel. + +If you want to make full use of the Video for Linux uncompressed +grabbing facilities, you must either + +- obtain and install the "big_physarea patch" for your kernel and + set aside the necessary memory during boot time. + There seem to be several versions of this patch against + various kernel versions floating around in the net, + you may obtain one e.g. from: + http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz + You also have to compile your driber AFTER installing that patch + in order to get it working + + or + +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. + For doing this add an entry in lilo.conf (if you use lilo): + append "mem=xxxM" + or add a line in your linux.par file (if you use loadlin): + mem=xxxM + +The second method is by far easier, however it is dangerous +if more than one driver at a time has the idea to use the memory +leftover by setting the mem=xxx parameter below the actual +memory size. + +Read also below how to use this memory! + + + +Driver Options +============== + +You are able to customize the behavior of the driver by giving +it some options at start time. + +default_input, default_norm +--------------------------- + +As soon as the driver is loaded, the Buz samples video signals +from one of its input ports and displays it on its output. +The driver uses the Composite Input and the video norm PAL for this. +If you want to change this default behavior, set default_input=1 +(for S-VHS input) or default_norm=1 for NTSC. + +v4l_nbufs, v4l_bufsize +---------------------- + +In order to make to make full use of the Video for Linux picture +grabbing facilities of the driver (which are needed by many +Video for Linux applications), the driver needs a set of +physically contiguous buffers for grabbing. These parameters +determine how many buffers of which size the driver will +allocate at open (the open will fail if it is unable to do so!). + +These values do not affect the MJPEG grabbing facilities of the driver, +they are needed for uncompressed image grabbing only!!! + +v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) +should be sufficient in allmost all cases. Only special applications +(streaming captures) will need more buffers and then mostly the +MJPEG capturing features of the Buz will be more apropriate. +So leave this parameter at it's default unless you know what you do. + +The things for v4l_bufsize are more complicated: +v4l_bufsize is set by default to 128 [KB] which is the maximum +amount of physically contiguous memory Linux is able to allocate +without kernel changes. This is sufficient for grabbing 24 bit color images +up to sizes of approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072). + +In order to be able to capture bigger images you have either to +- obtain and install the "big_physarea patch" and set aside + the necessary memory during boot time or +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. +In that case, usefull settings for v4l_bufsize are +- 1296 [Kb] for grabbing 24 bit images of max size 768*576 +- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) +You may reduce these numbers accordingly if you know you are only +grabbing 720 pixels wide images or NTSC images (max height 480). + +In some cases it may happen that Linux isn't even able to obtain +the default 128 KB buffers. If you don't need uncompressed image +grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4) +in order to be able to open the video device. + +vidmem +------ + +The video mem address of the video card. +The driver has a little database for some videocards +to determine it from there. If your video card is not in there +you have either to give it to the driver as a parameter +or set in in a VIDIOCSFBUF ioctl + +The videocard database is contained in the file "videocards.h" +Gernot Ziegler wants to keep an actual version of that file. +If your card is not contained in that file, look at +http://www.lysator.liu.se/~gz/buz/ for an actual version of +"videocards.h". + +triton, natoma +-------------- + +The driver tries to detect if you have a triton or natome chipset +in order to take special messures for these chipsets. +If this detection fails but you are sure you have such a chipset, +set the corresponding variable to 1. +This is a very special option and may go away in the future. + + + +Programming interface +===================== + +This driver should be fully compliant to Video for Linux, so all +tools working with Video for Linux should work with (hopefully) +no problems. + +A description of the Video for Linux programming interace can be found at: +http://roadrunner.swansea.linux.org.uk/v4lapi.shtml + +Besides the Video for Linux interface, the driver has a "proprietary" +interface for accessing the Buz's MJPEG capture and playback facilities. + +The ioctls for that interface are as follows: + +BUZIOC_G_PARAMS +BUZIOC_S_PARAMS + +Get and set the parameters of the buz. The user should allways +do a BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default +settings, change what he likes and then make a BUZIOC_S_PARAMS call. +A typical application should at least set the members +input, norm and decimation of the struct buz_params. +For a full description of all members see "buz.h" + +BUZIOC_REQBUFS + +Before being able to capture/playback, the user has to request +the buffers he is wanting to use. Fill the structure +buz_requestbuffers with the size (recommended: 256*1024) and +the number (recommended 32 up to 256). There are no such restrictions +as for the Video for Linux buffers, you should LEAVE SUFFICIENT +MEMORY for your system however, else strange things will happen .... +On return, the buz_requestbuffers structure contains number and +size of the actually allocated buffers. +You should use these numbers for doing a mmap of the buffers +into the user space. +The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap +maps the MJPEG buffer instead of the V4L buffers. + +BUZIOC_QBUF_CAPT +BUZIOC_QBUF_PLAY + +Queue a buffer for capture or playback. The first call also starts +streaming capture. When streaming capture is going on, you may +only queue further buffers or issue syncs until streaming +capture is switched off again with a argument of -1 to +a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl. + +BUZIOC_SYNC + +Issue this ioctl when all buffers are queued. This ioctl will +block until the first buffer becomes free for saving its +data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY). + +BUZIOC_G_STATUS + +Get the status of the input lines (video source connected/norm). +This ioctl may be subject to change. + + + + + +See the examples directory delivered with this driver +for actual coding examples! diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/MAINTAINERS linux.ac/MAINTAINERS --- linux.vanilla/MAINTAINERS Tue Jun 15 16:49:45 1999 +++ linux.ac/MAINTAINERS Mon Jul 19 20:31:16 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) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/Makefile linux.ac/Makefile --- linux.vanilla/Makefile Tue Jun 15 16:49:45 1999 +++ linux.ac/Makefile Mon Jul 19 20:48:43 1999 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 10 -EXTRAVERSION = +EXTRAVERSION = -ac12 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 @@ -65,12 +66,12 @@ # INSTALL_PATH specifies where to place the updated kernel and system map # images. Uncomment if you want to place them anywhere other than root. -#INSTALL_PATH=/boot +INSTALL_PATH=/boot # # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory # relocations required by build roots. This is not defined in the -# makefile but the arguement can be passed to make if needed. +# makefile but the argument can be passed to make if needed. # # @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/README linux.ac/README --- linux.vanilla/README Tue Jun 15 16:49:45 1999 +++ linux.ac/README Mon Jul 19 19:48:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/boot/bootp.c linux.ac/arch/alpha/boot/bootp.c --- linux.vanilla/arch/alpha/boot/bootp.c Sun Nov 8 15:08:23 1998 +++ linux.ac/arch/alpha/boot/bootp.c Tue Jun 22 03:35:46 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/boot/main.c linux.ac/arch/alpha/boot/main.c --- linux.vanilla/arch/alpha/boot/main.c Wed Mar 10 21:13:00 1999 +++ linux.ac/arch/alpha/boot/main.c Tue Jun 22 03:35:46 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/Makefile linux.ac/arch/alpha/kernel/Makefile --- linux.vanilla/arch/alpha/kernel/Makefile Thu Jan 14 01:25:21 1999 +++ linux.ac/arch/alpha/kernel/Makefile Wed Jun 30 00:35:30 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.ac/arch/alpha/kernel/alpha_ksyms.c --- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/alpha_ksyms.c Mon Jun 7 01:13:17 1999 @@ -71,6 +71,10 @@ EXPORT_SYMBOL(_writel); EXPORT_SYMBOL(_memcpy_fromio); EXPORT_SYMBOL(_memcpy_toio); +#ifdef CONFIG_ALPHA_JENSEN +EXPORT_SYMBOL (_memcpy_fromio_g32a); +EXPORT_SYMBOL (_memcpy_toio_g32a); +#endif EXPORT_SYMBOL(_memset_c_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_cia.c linux.ac/arch/alpha/kernel/core_cia.c --- linux.vanilla/arch/alpha/kernel/core_cia.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/core_cia.c Fri Jun 4 23:52:48 1999 @@ -535,8 +535,6 @@ * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, * we may want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. */ *(vuip)CIA_IOC_PCI_W0_BASE = 1U | (CIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_mcpcia.c linux.ac/arch/alpha/kernel/core_mcpcia.c --- linux.vanilla/arch/alpha/kernel/core_mcpcia.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_mcpcia.c Wed Jun 30 00:48:06 1999 @@ -18,7 +18,6 @@ #include #include #include -#include #define __EXTERN_INLINE inline #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/core_pyxis.c linux.ac/arch/alpha/kernel/core_pyxis.c --- linux.vanilla/arch/alpha/kernel/core_pyxis.c Sun Nov 8 15:08:25 1998 +++ linux.ac/arch/alpha/kernel/core_pyxis.c Wed Jun 30 00:35:55 1999 @@ -425,17 +425,22 @@ { /* * 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_BASE = PYXIS_DMA_WIN_BASE_DEFAULT | 1U; *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; *(vuip)PYXIS_T0_BASE = 0; - *(vuip)PYXIS_W1_BASE = 0x0 ; + *(vuip)PYXIS_W1_BASE = (PYXIS_DMA_WIN_BASE_DEFAULT + + PYXIS_DMA_WIN_SIZE_DEFAULT) | 1U; + *(vuip)PYXIS_W1_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U; + *(vuip)PYXIS_T1_BASE = PYXIS_DMA_WIN_SIZE_DEFAULT; + *(vuip)PYXIS_W2_BASE = 0x0 ; *(vuip)PYXIS_W3_BASE = 0x0 ; mb(); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/entry.S linux.ac/arch/alpha/kernel/entry.S --- linux.vanilla/arch/alpha/kernel/entry.S Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/entry.S Fri Jun 4 23:52:48 1999 @@ -527,6 +527,8 @@ call_pal PAL_swpctx unop bsr $1,undo_switch_stack + lda $8,0x3fff + bic $30,$8,$8 mov $17,$0 ret $31,($26),1 .end alpha_switch_to diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/es1888.c linux.ac/arch/alpha/kernel/es1888.c --- linux.vanilla/arch/alpha/kernel/es1888.c Sun Nov 8 15:08:24 1998 +++ linux.ac/arch/alpha/kernel/es1888.c Wed Jun 30 00:36:09 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/irq.h linux.ac/arch/alpha/kernel/irq.h --- linux.vanilla/arch/alpha/kernel/irq.h Thu Dec 31 18:10:39 1998 +++ linux.ac/arch/alpha/kernel/irq.h Wed Jun 30 00:36:18 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/machvec.h linux.ac/arch/alpha/kernel/machvec.h --- linux.vanilla/arch/alpha/kernel/machvec.h Thu Jan 14 01:25:21 1999 +++ linux.ac/arch/alpha/kernel/machvec.h Wed Jun 30 00:48:06 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/osf_sys.c linux.ac/arch/alpha/kernel/osf_sys.c --- linux.vanilla/arch/alpha/kernel/osf_sys.c Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/kernel/osf_sys.c Wed Jun 30 00:36:27 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; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/process.c linux.ac/arch/alpha/kernel/process.c --- linux.vanilla/arch/alpha/kernel/process.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/process.c Thu Jul 8 02:02:28 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -76,7 +75,7 @@ } #ifdef __SMP__ -void +int cpu_idle(void *unused) { /* An endless idle loop with no priority at all. */ @@ -329,7 +328,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/proto.h linux.ac/arch/alpha/kernel/proto.h --- linux.vanilla/arch/alpha/kernel/proto.h Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/proto.h Sun Jun 13 19:58:21 1999 @@ -193,7 +193,7 @@ /* process.c */ extern void generic_kill_arch (int mode, char *reboot_cmd); -extern void cpu_idle(void *) __attribute__((noreturn)); +extern int cpu_idle(void *) __attribute__((noreturn)); /* ptrace.c */ extern int ptrace_set_bpt (struct task_struct *child); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/setup.c linux.ac/arch/alpha/kernel/setup.c --- linux.vanilla/arch/alpha/kernel/setup.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/setup.c Tue Jun 22 03:35:46 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)) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/signal.c linux.ac/arch/alpha/kernel/signal.c --- linux.vanilla/arch/alpha/kernel/signal.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/signal.c Mon Jul 19 19:48:17 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/smp.c linux.ac/arch/alpha/kernel/smp.c --- linux.vanilla/arch/alpha/kernel/smp.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/smp.c Wed Jul 7 06:58:59 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/sys_dp264.c linux.ac/arch/alpha/kernel/sys_dp264.c --- linux.vanilla/arch/alpha/kernel/sys_dp264.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/sys_dp264.c Wed Jun 30 00:36:53 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/kernel/time.c linux.ac/arch/alpha/kernel/time.c --- linux.vanilla/arch/alpha/kernel/time.c Tue Jun 15 16:49:45 1999 +++ linux.ac/arch/alpha/kernel/time.c Wed Jun 30 00:36:53 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/lib/io.c linux.ac/arch/alpha/lib/io.c --- linux.vanilla/arch/alpha/lib/io.c Fri Apr 16 22:10:51 1999 +++ linux.ac/arch/alpha/lib/io.c Mon Jul 19 03:45:42 1999 @@ -2,6 +2,7 @@ * Alpha IO and memory functions.. Just expand the inlines in the header * files.. */ +#include #include #include #include @@ -451,6 +452,48 @@ from++; } } + +#ifdef CONFIG_ALPHA_JENSEN +/* Special memcopy for EISA-Cards that permit only + * 32-bit accesses. Two 16-bit words are combined and + * written as one 32-bit word to the IO space. + */ + +void _memcpy_fromio_g32a(void * to, unsigned long from, long count) +{ + + if ((((long)to&1)!=0)&&((from&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_fromio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __readlua((u16 *)to, (u16 *)(to+2), from); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} + +void _memcpy_toio_g32a(unsigned long to, void * from, long count) +{ + if ((((long)from&1)!=0)&&((to&3)!=0)&&((count&3)!=0)) + { + printk ("memcpy_toio_g32: Unaligned Data!\n"); + return; + } + + count-=4; + do { + __writelua(*(u16 *)from, *(u16 *)(from+2), to); + count -= 4; + to += 4; + from += 4; + } while (count >= 0); +} +#endif /* * "memset" on IO memory space. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/ieee-math.c linux.ac/arch/alpha/math-emu/ieee-math.c --- linux.vanilla/arch/alpha/math-emu/ieee-math.c Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/math-emu/ieee-math.c Wed Jun 30 00:36:53 1999 @@ -704,20 +704,21 @@ * FPCR_INV if invalid operation occurred, etc. */ unsigned long -ieee_CVTQT (int f, unsigned long a, unsigned long *b) +ieee_CVTQT (int f, 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; + if (a != 0) { + op_b.s = (a < 0 ? 1 : 0); + op_b.f[0] = (a < 0 ? -a : a); + op_b.f[1] = 0; + op_b.e = 55; + normalize(&op_b); + return round_t_ieee(f, &op_b, b); + } else { + *b = 0; + return 0; } - op_b.e = 55; - normalize(&op_b); - return round_t_ieee(f, &op_b, b); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/math-emu/ieee-math.h linux.ac/arch/alpha/math-emu/ieee-math.h --- linux.vanilla/arch/alpha/math-emu/ieee-math.h Thu May 27 22:11:48 1999 +++ linux.ac/arch/alpha/math-emu/ieee-math.h Wed Jun 30 00:36:53 1999 @@ -20,7 +20,7 @@ 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_CVTQT (int rm, 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, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/mm/fault.c linux.ac/arch/alpha/mm/fault.c --- linux.vanilla/arch/alpha/mm/fault.c Sun Nov 8 15:08:23 1998 +++ linux.ac/arch/alpha/mm/fault.c Wed Jul 7 06:58:59 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/alpha/mm/init.c linux.ac/arch/alpha/mm/init.c --- linux.vanilla/arch/alpha/mm/init.c Tue Jun 15 16:49:46 1999 +++ linux.ac/arch/alpha/mm/init.c Wed Jun 30 00:48:14 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/process.c linux.ac/arch/arm/kernel/process.c --- linux.vanilla/arch/arm/kernel/process.c Sun Nov 8 15:08:44 1998 +++ linux.ac/arch/arm/kernel/process.c Mon Jul 19 19:48:17 1999 @@ -27,9 +27,7 @@ #include #include #include -#include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/arm/kernel/time.c linux.ac/arch/arm/kernel/time.c --- linux.vanilla/arch/arm/kernel/time.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/arm/kernel/time.c Mon Jul 19 19:48:17 1999 @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/Makefile linux.ac/arch/i386/Makefile --- linux.vanilla/arch/i386/Makefile Thu Dec 31 18:10:39 1998 +++ linux.ac/arch/i386/Makefile Sun Jun 6 02:46:05 1999 @@ -62,6 +62,13 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +vmlinux: arch/i386/vmlinux.lds + +arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE + gcc -E -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds + +FORCE: ; + zImage: vmlinux @$(MAKEBOOT) zImage diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/boot/setup.S linux.ac/arch/i386/boot/setup.S --- linux.vanilla/arch/i386/boot/setup.S Tue Jun 15 16:49:46 1999 +++ linux.ac/arch/i386/boot/setup.S Tue Jun 29 02:19:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/config.in linux.ac/arch/i386/config.in --- linux.vanilla/arch/i386/config.in Wed Apr 28 19:14:24 1999 +++ linux.ac/arch/i386/config.in Mon Jun 7 00:10:09 1999 @@ -33,6 +33,10 @@ define_bool CONFIG_X86_GOOD_APIC y fi +choice 'Maximum Physical Memory' \ + "1GB CONFIG_1GB \ + 2GB CONFIG_2GB" 1GB + bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP @@ -105,7 +109,6 @@ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - bool ' Power off on shutdown' CONFIG_APM_POWER_OFF bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/defconfig linux.ac/arch/i386/defconfig --- linux.vanilla/arch/i386/defconfig Fri Apr 16 22:10:51 1999 +++ linux.ac/arch/i386/defconfig Mon Jul 19 19:48:17 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 @@ -89,13 +91,24 @@ # # Additional Block Devices # +CONFIG_BLK_DEV_LVM=y +CONFIG_LVM_PROC_FS=y # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_MD=y +CONFIG_AUTODETECT_RAID=y +CONFIG_MD_LINEAR=y +CONFIG_MD_STRIPED=y +CONFIG_MD_MIRRORING=y +CONFIG_MD_RAID5=y +CONFIG_MD_TRANSLUCENT=y +CONFIG_MD_LVM=y +CONFIG_MD_BOOT=y # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_HD is not set # @@ -228,6 +241,7 @@ # CONFIG_TR is not set # CONFIG_HOSTESS_SV11 is not set # CONFIG_COSA is not set +# CONFIG_SEALEVEL_4021 is not set # CONFIG_RCPCI is not set # CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set @@ -239,6 +253,11 @@ # CONFIG_HAMRADIO is not set # +# IrDA subsystem support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -285,6 +304,7 @@ # # CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_DMARAM is not set # # Ftape, the floppy tape device driver diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/apm.c linux.ac/arch/i386/kernel/apm.c --- linux.vanilla/arch/i386/kernel/apm.c Tue Jan 19 02:57:23 1999 +++ linux.ac/arch/i386/kernel/apm.c Mon Jun 7 00:10:10 1999 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1998 Stephen Rothwell + * Copyright 1994-1999 Stephen Rothwell * (Stephen.Rothwell@canb.auug.org.au) * Development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -33,6 +33,7 @@ * Nov 1998, Version 1.7 * Jan 1999, Version 1.8 * Jan 1999, Version 1.9 + * Jun 1999, Version 1.10 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -90,6 +91,12 @@ * Use CONFIG_SMP instead of __SMP__ * Ignore BOUNCES for three seconds. * Stephen Rothwell + * 1.10: Reset time across standby. + * Allow more inititialisation on SMP. + * Remove CONFIG_APM_POWER_OFF and make it boot time + * configurable (default on). + * Make debug only a boot time parameter (remove APM_DEBUG). + * Try to blank all devices on any error. * * APM 1.1 Reference: * @@ -144,51 +151,14 @@ */ #define APM_MINOR_DEV 134 -/* Configurable options: - * - * CONFIG_APM_IGNORE_USER_SUSPEND: define to ignore USER SUSPEND requests. - * This is necessary on the NEC Versa M series, which generates these when - * resuming from SYSTEM SUSPEND. However, enabling this on other laptops - * will cause the laptop to generate a CRITICAL SUSPEND when an appropriate - * USER SUSPEND is ignored -- this may prevent the APM driver from updating - * the system time on a RESUME. - * - * CONFIG_APM_DO_ENABLE: enable APM features at boot time. From page 36 of - * the specification: "When disabled, the APM BIOS does not automatically - * power manage devices, enter the Standby State, enter the Suspend State, - * or take power saving steps in response to CPU Idle calls." This driver - * will make CPU Idle calls when Linux is idle (unless this feature is - * turned off -- see below). This should always save battery power, but - * more complicated APM features will be dependent on your BIOS - * implementation. You may need to turn this option off if your computer - * hangs at boot time when using APM support, or if it beeps continuously - * instead of suspending. Turn this off if you have a NEC UltraLite Versa - * 33/C or a Toshiba T400CDT. This is off by default since most machines - * do fine without this feature. - * - * CONFIG_APM_CPU_IDLE: enable calls to APM CPU Idle/CPU Busy inside the - * idle loop. On some machines, this can activate improved power savings, - * such as a slowed CPU clock rate, when the machine is idle. These idle - * call is made after the idle loop has run for some length of time (e.g., - * 333 mS). On some machines, this will cause a hang at boot time or - * whenever the CPU becomes idle. - * - * CONFIG_APM_DISPLAY_BLANK: enable console blanking using the APM. Some - * laptops can use this to turn of the LCD backlight when the VC screen - * blanker blanks the screen. Note that this is only used by the VC screen - * blanker, and probably won't turn off the backlight when using X11. Some - * problems have been reported when using this option with gpm (if you'd - * like to debug this, please do so). - * - * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist - * on returning multiple suspend/standby events whenever one occurs. We - * really only need one at a time, so just ignore any beyond the first. - * This is probably safe on most laptops. - * - * If you are debugging the APM support for your laptop, note that code for - * all of these options is contained in this file, so you can #define or - * #undef these on the next line to avoid recompiling the whole kernel. +/* + * See Documentation/Config.help for the configuration options. * + * Various options can be changed at boot time as follows: + * apm=on/off enable/disable APM + * [no-]debug log some debugging messages + * [no-]power-off power off on shutdown + * [no-]smp-power-off allow power off even for SMP */ /* KNOWN PROBLEM MACHINES: @@ -207,11 +177,6 @@ */ /* - * Define to have debug messages. - */ -#undef APM_DEBUG - -/* * Define to always call the APM BIOS busy routine even if the clock was * not slowed by the idle routine. */ @@ -266,27 +231,6 @@ __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) /* - * Forward declarations - */ -static void suspend(void); -static void standby(void); -static void set_time(void); - -static void check_events(void); -static void do_apm_timer(unsigned long); - -static int do_open(struct inode *, struct file *); -static int do_release(struct inode *, struct file *); -static ssize_t do_read(struct file *, char *, size_t , loff_t *); -static unsigned int do_poll(struct file *, poll_table *); -static int do_ioctl(struct inode *, struct file *, u_int, u_long); - -static int apm_get_info(char *, char **, off_t, int, int); - -extern int apm_register_callback(int (*)(apm_event_t)); -extern void apm_unregister_callback(int (*)(apm_event_t)); - -/* * Local variables */ static asmlinkage struct { @@ -313,15 +257,15 @@ #endif static int debug = 0; static int apm_disabled = 0; +static int power_off_enabled = 1; static struct wait_queue * process_list = NULL; static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; -static char driver_version[] = "1.9"; /* no spaces */ +static char driver_version[] = "1.10"; /* no spaces */ -#ifdef APM_DEBUG static char * apm_event_name[] = { "system standby", "system suspend", @@ -338,28 +282,6 @@ }; #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) -#endif - -static struct file_operations apm_bios_fops = { - NULL, /* lseek */ - do_read, - NULL, /* write */ - NULL, /* readdir */ - do_poll, - do_ioctl, - NULL, /* mmap */ - do_open, - NULL, /* flush */ - do_release, - NULL, /* fsync */ - NULL /* fasync */ -}; - -static struct miscdevice apm_device = { - APM_MINOR_DEV, - "apm", - &apm_bios_fops -}; typedef struct callback_list_t { int (* callback)(apm_event_t); @@ -502,7 +424,7 @@ return error; } -static int apm_driver_version(u_short *val) +static int __init apm_driver_version(u_short *val) { u32 eax; @@ -543,7 +465,7 @@ return set_power_state(0x0001, state); } -void apm_power_off(void) +void apm_power_off(int force) { /* * smp_hack == 2 means that we would have enabled APM support @@ -553,7 +475,8 @@ * they are doing because they booted with the smp-power-off * kernel option. */ - if (apm_enabled || (smp_hack == 2)) + if ((apm_enabled || (smp_hack == 2)) + && (power_off_enabled || force)) (void) apm_set_power_state(APM_STATE_OFF); } @@ -565,7 +488,7 @@ /* Blank the first display device */ error = set_power_state(0x0100, state); - if (error == APM_BAD_DEVICE) + if (error != APM_SUCCESS) /* try to blank them all instead */ error = set_power_state(0x01ff, state); return error; @@ -733,10 +656,8 @@ if (as->event_head == as->event_tail) { static int notified; - if (notified == 0) { + if (notified++ == 0) printk(KERN_ERR "apm: an event queue overflowed\n"); - notified = 1; - } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; } as->events[as->event_head] = event; @@ -764,21 +685,19 @@ { unsigned long flags; - if (!got_clock_diff) /* Don't know time zone, can't set clock */ - return; - - save_flags(flags); - cli(); - CURRENT_TIME = get_cmos_time() + clock_cmos_diff; - restore_flags(flags); + if (got_clock_diff) { /* Must know time zone in order to set clock */ + save_flags(flags); + cli(); + CURRENT_TIME = get_cmos_time() + clock_cmos_diff; + restore_flags(flags); + } } -static void suspend(void) +static void get_time_diff(void) { +#ifndef CONFIG_APM_RTC_IS_GMT unsigned long flags; - int err; -#ifndef CONFIG_APM_RTC_IS_GMT /* * Estimate time zone so that set_time can update the clock */ @@ -789,7 +708,14 @@ got_clock_diff = 1; restore_flags(flags); #endif +} + +static void suspend(void) +{ + unsigned long flags; + int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_SUSPEND); if (err) apm_error("suspend", err); @@ -812,9 +738,11 @@ { int err; + get_time_diff(); err = apm_set_power_state(APM_STATE_STANDBY); if (err) apm_error("standby", err); + set_time(); /* should not be necessary ... */ } static apm_event_t get_event(void) @@ -864,14 +792,14 @@ #endif while ((event = get_event()) != 0) { -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "apm: received %s notify\n", - apm_event_name[event - 1]); - else - printk(KERN_DEBUG "apm: received unknown " - "event 0x%02x\n", event); -#endif + if (debug) { + if (event <= NR_APM_EVENT_NAME) + printk(KERN_DEBUG "apm: received %s notify\n", + apm_event_name[event - 1]); + else + printk(KERN_DEBUG "apm: received unknown " + "event 0x%02x\n", event); + } #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE if (ignore_bounce && ((jiffies - last_resume) > BOUNCE_INTERVAL)) @@ -1277,6 +1205,8 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; + if (strncmp(str, "power-off", 9) == 0) + power_off_enabled = !invert; if (strncmp(str, "smp-power-off", 13) == 0) smp_hack = !invert; str = strchr(str, ','); @@ -1285,6 +1215,27 @@ } } +static struct file_operations apm_bios_fops = { + NULL, /* lseek */ + do_read, + NULL, /* write */ + NULL, /* readdir */ + do_poll, + do_ioctl, + NULL, /* mmap */ + do_open, + NULL, /* flush */ + do_release, + NULL, /* fsync */ + NULL /* fasync */ +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm", + &apm_bios_fops +}; + void __init apm_bios_init(void) { unsigned short bx; @@ -1378,14 +1329,6 @@ (apm_bios_info.dseg_len - 1) & 0xffff); } #endif -#ifdef CONFIG_SMP - if (smp_num_cpus > 1) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - if (smp_hack) - smp_hack = 2; - return; - } -#endif if (apm_bios_info.version > 0x100) { /* * We only support BIOSs up to version 1.2 @@ -1459,6 +1402,14 @@ if (apm_engage_power_management(0x0001) == APM_SUCCESS) apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; } +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + if (smp_hack) + smp_hack = 2; + return; + } +#endif init_timer(&apm_timer); apm_timer.function = do_apm_timer; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/i386_ksyms.c linux.ac/arch/i386/kernel/i386_ksyms.c --- linux.vanilla/arch/i386/kernel/i386_ksyms.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/i386_ksyms.c Wed Jun 16 00:13:04 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); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/init_task.c linux.ac/arch/i386/kernel/init_task.c --- linux.vanilla/arch/i386/kernel/init_task.c Sun Nov 8 15:08:22 1998 +++ linux.ac/arch/i386/kernel/init_task.c Fri Jun 4 23:52:47 1999 @@ -7,7 +7,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/irq.c linux.ac/arch/i386/kernel/irq.c --- linux.vanilla/arch/i386/kernel/irq.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/irq.c Mon Jul 19 03:31:01 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/irq.h linux.ac/arch/i386/kernel/irq.h --- linux.vanilla/arch/i386/kernel/irq.h Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/irq.h Mon Jul 19 05:16:15 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/kernel/process.c linux.ac/arch/i386/kernel/process.c --- linux.vanilla/arch/i386/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/i386/kernel/process.c Mon Jul 19 19:48:17 1999 @@ -26,12 +26,10 @@ #include #include #include -#include #include -#include #include #include -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) +#if defined(CONFIG_APM) #include #endif @@ -52,11 +50,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -#ifdef CONFIG_APM -extern int apm_do_idle(void); -extern void apm_do_busy(void); -#endif - static int hlt_counter=0; #define HARD_IDLE_TIMEOUT (HZ / 3) @@ -386,8 +379,8 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_power_off(); +#if defined(CONFIG_APM) + apm_power_off(0); #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/math-emu/fpu_emu.h linux.ac/arch/i386/math-emu/fpu_emu.h --- linux.vanilla/arch/i386/math-emu/fpu_emu.h Sun Nov 8 15:08:21 1998 +++ linux.ac/arch/i386/math-emu/fpu_emu.h Mon Jul 19 19:48:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/mm/init.c linux.ac/arch/i386/mm/init.c --- linux.vanilla/arch/i386/mm/init.c Tue Jan 26 09:44:20 1999 +++ linux.ac/arch/i386/mm/init.c Mon Jul 19 18:23:26 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/mm/ioremap.c linux.ac/arch/i386/mm/ioremap.c --- linux.vanilla/arch/i386/mm/ioremap.c Thu Dec 3 14:11:59 1998 +++ linux.ac/arch/i386/mm/ioremap.c Fri Jul 2 19:50:39 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds linux.ac/arch/i386/vmlinux.lds --- linux.vanilla/arch/i386/vmlinux.lds Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/i386/vmlinux.lds Mon Jul 19 21:00:32 1999 @@ -1,12 +1,12 @@ /* ld script to make i386 Linux kernel - * Written by Martin Mares + * Written by Martin Mares ; */ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - . = 0xC0000000 + 0x100000; + . = 0xC0000000 + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/i386/vmlinux.lds.S linux.ac/arch/i386/vmlinux.lds.S --- linux.vanilla/arch/i386/vmlinux.lds.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/i386/vmlinux.lds.S Sun Jun 6 02:44:33 1999 @@ -0,0 +1,69 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares ; + */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = PAGE_OFFSET_RAW + 0x100000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(8192); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/m68k/kernel/process.c linux.ac/arch/m68k/kernel/process.c --- linux.vanilla/arch/m68k/kernel/process.c Thu May 27 22:11:49 1999 +++ linux.ac/arch/m68k/kernel/process.c Mon Jun 7 00:10:10 1999 @@ -40,7 +40,6 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -87,9 +86,6 @@ void machine_power_off(void) { -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_set_power_state(APM_STATE_OFF); -#endif } void show_regs(struct pt_regs * regs) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/Makefile linux.ac/arch/mips/Makefile --- linux.vanilla/arch/mips/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/Makefile Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/algor/README linux.ac/arch/mips/algor/README --- linux.vanilla/arch/mips/algor/README Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/algor/README Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/Makefile linux.ac/arch/mips/arc/Makefile --- linux.vanilla/arch/mips/arc/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/Makefile Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/cmdline.c linux.ac/arch/mips/arc/cmdline.c --- linux.vanilla/arch/mips/arc/cmdline.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/cmdline.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/console.c linux.ac/arch/mips/arc/console.c --- linux.vanilla/arch/mips/arc/console.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/console.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/env.c linux.ac/arch/mips/arc/env.c --- linux.vanilla/arch/mips/arc/env.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/env.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/file.c linux.ac/arch/mips/arc/file.c --- linux.vanilla/arch/mips/arc/file.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/file.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/identify.c linux.ac/arch/mips/arc/identify.c --- linux.vanilla/arch/mips/arc/identify.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/identify.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/init.c linux.ac/arch/mips/arc/init.c --- linux.vanilla/arch/mips/arc/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/init.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/memory.c linux.ac/arch/mips/arc/memory.c --- linux.vanilla/arch/mips/arc/memory.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/memory.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/misc.c linux.ac/arch/mips/arc/misc.c --- linux.vanilla/arch/mips/arc/misc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/misc.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/printf.c linux.ac/arch/mips/arc/printf.c --- linux.vanilla/arch/mips/arc/printf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/printf.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/salone.c linux.ac/arch/mips/arc/salone.c --- linux.vanilla/arch/mips/arc/salone.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/salone.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/time.c linux.ac/arch/mips/arc/time.c --- linux.vanilla/arch/mips/arc/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/time.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/arc/tree.c linux.ac/arch/mips/arc/tree.c --- linux.vanilla/arch/mips/arc/tree.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/arc/tree.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/Makefile linux.ac/arch/mips/baget/Makefile --- linux.vanilla/arch/mips/baget/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/Makefile Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/baget.c linux.ac/arch/mips/baget/baget.c --- linux.vanilla/arch/mips/baget/baget.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/baget.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/bagetIRQ.S linux.ac/arch/mips/baget/bagetIRQ.S --- linux.vanilla/arch/mips/baget/bagetIRQ.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/bagetIRQ.S Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/balo.c linux.ac/arch/mips/baget/balo.c --- linux.vanilla/arch/mips/baget/balo.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/balo.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/balo_supp.S linux.ac/arch/mips/baget/balo_supp.S --- linux.vanilla/arch/mips/baget/balo_supp.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/balo_supp.S Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/irq.c linux.ac/arch/mips/baget/irq.c --- linux.vanilla/arch/mips/baget/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/irq.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/ld.script.balo linux.ac/arch/mips/baget/ld.script.balo --- linux.vanilla/arch/mips/baget/ld.script.balo Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/ld.script.balo Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/print.c linux.ac/arch/mips/baget/print.c --- linux.vanilla/arch/mips/baget/print.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/print.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/prom/Makefile linux.ac/arch/mips/baget/prom/Makefile --- linux.vanilla/arch/mips/baget/prom/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/prom/Makefile Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/prom/init.c linux.ac/arch/mips/baget/prom/init.c --- linux.vanilla/arch/mips/baget/prom/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/prom/init.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/reset.c linux.ac/arch/mips/baget/reset.c --- linux.vanilla/arch/mips/baget/reset.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/reset.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/setup.c linux.ac/arch/mips/baget/setup.c --- linux.vanilla/arch/mips/baget/setup.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/setup.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/time.c linux.ac/arch/mips/baget/time.c --- linux.vanilla/arch/mips/baget/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/time.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/vacserial.c linux.ac/arch/mips/baget/vacserial.c --- linux.vanilla/arch/mips/baget/vacserial.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/vacserial.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/baget/wbflush.c linux.ac/arch/mips/baget/wbflush.c --- linux.vanilla/arch/mips/baget/wbflush.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/baget/wbflush.c Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/boot/Makefile linux.ac/arch/mips/boot/Makefile --- linux.vanilla/arch/mips/boot/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/boot/Makefile Tue Jun 22 01:20:08 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/boot/ecoff.h linux.ac/arch/mips/boot/ecoff.h --- linux.vanilla/arch/mips/boot/ecoff.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/boot/ecoff.h Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/boot/elf2ecoff.c linux.ac/arch/mips/boot/elf2ecoff.c --- linux.vanilla/arch/mips/boot/elf2ecoff.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/boot/elf2ecoff.c Mon Jul 19 19:48:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/config.in linux.ac/arch/mips/config.in --- linux.vanilla/arch/mips/config.in Tue Feb 23 14:21:32 1999 +++ linux.ac/arch/mips/config.in Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/Makefile linux.ac/arch/mips/dec/Makefile --- linux.vanilla/arch/mips/dec/Makefile Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/dec/Makefile Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/boot/Makefile linux.ac/arch/mips/dec/boot/Makefile --- linux.vanilla/arch/mips/dec/boot/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/boot/Makefile Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/boot/decstation.c linux.ac/arch/mips/dec/boot/decstation.c --- linux.vanilla/arch/mips/dec/boot/decstation.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/boot/decstation.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/boot/ld.ecoff linux.ac/arch/mips/dec/boot/ld.ecoff --- linux.vanilla/arch/mips/dec/boot/ld.ecoff Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/boot/ld.ecoff Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/int-handler.S linux.ac/arch/mips/dec/int-handler.S --- linux.vanilla/arch/mips/dec/int-handler.S Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/dec/int-handler.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/irq.c linux.ac/arch/mips/dec/irq.c --- linux.vanilla/arch/mips/dec/irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/irq.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/Makefile linux.ac/arch/mips/dec/prom/Makefile --- linux.vanilla/arch/mips/dec/prom/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/Makefile Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/cmdline.c linux.ac/arch/mips/dec/prom/cmdline.c --- linux.vanilla/arch/mips/dec/prom/cmdline.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/cmdline.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/dectypes.h linux.ac/arch/mips/dec/prom/dectypes.h --- linux.vanilla/arch/mips/dec/prom/dectypes.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/dectypes.h Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/identify.c linux.ac/arch/mips/dec/prom/identify.c --- linux.vanilla/arch/mips/dec/prom/identify.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/identify.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/init.c linux.ac/arch/mips/dec/prom/init.c --- linux.vanilla/arch/mips/dec/prom/init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/init.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/locore.S linux.ac/arch/mips/dec/prom/locore.S --- linux.vanilla/arch/mips/dec/prom/locore.S Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/locore.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/memory.c linux.ac/arch/mips/dec/prom/memory.c --- linux.vanilla/arch/mips/dec/prom/memory.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/memory.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/prom/prom.h linux.ac/arch/mips/dec/prom/prom.h --- linux.vanilla/arch/mips/dec/prom/prom.h Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/prom/prom.h Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/promcon.c linux.ac/arch/mips/dec/promcon.c --- linux.vanilla/arch/mips/dec/promcon.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/promcon.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/reset.c linux.ac/arch/mips/dec/reset.c --- linux.vanilla/arch/mips/dec/reset.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/dec/reset.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/rtc-dec.c linux.ac/arch/mips/dec/rtc-dec.c --- linux.vanilla/arch/mips/dec/rtc-dec.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/rtc-dec.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/serial.c linux.ac/arch/mips/dec/serial.c --- linux.vanilla/arch/mips/dec/serial.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/serial.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/setup.c linux.ac/arch/mips/dec/setup.c --- linux.vanilla/arch/mips/dec/setup.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/dec/setup.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/time.c linux.ac/arch/mips/dec/time.c --- linux.vanilla/arch/mips/dec/time.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/time.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/dec/wbflush.c linux.ac/arch/mips/dec/wbflush.c --- linux.vanilla/arch/mips/dec/wbflush.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/dec/wbflush.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/defconfig linux.ac/arch/mips/defconfig --- linux.vanilla/arch/mips/defconfig Wed Mar 10 21:13:00 1999 +++ linux.ac/arch/mips/defconfig Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/Makefile linux.ac/arch/mips/jazz/Makefile --- linux.vanilla/arch/mips/jazz/Makefile Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/Makefile Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/floppy-jazz.c linux.ac/arch/mips/jazz/floppy-jazz.c --- linux.vanilla/arch/mips/jazz/floppy-jazz.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/floppy-jazz.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/hw-access.c linux.ac/arch/mips/jazz/hw-access.c --- linux.vanilla/arch/mips/jazz/hw-access.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/hw-access.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/int-handler.S linux.ac/arch/mips/jazz/int-handler.S --- linux.vanilla/arch/mips/jazz/int-handler.S Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/int-handler.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/jazzdma.c linux.ac/arch/mips/jazz/jazzdma.c --- linux.vanilla/arch/mips/jazz/jazzdma.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/jazzdma.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/kbd-jazz.c linux.ac/arch/mips/jazz/kbd-jazz.c --- linux.vanilla/arch/mips/jazz/kbd-jazz.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/jazz/kbd-jazz.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/reset.c linux.ac/arch/mips/jazz/reset.c --- linux.vanilla/arch/mips/jazz/reset.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/reset.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/rtc-jazz.c linux.ac/arch/mips/jazz/rtc-jazz.c --- linux.vanilla/arch/mips/jazz/rtc-jazz.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/rtc-jazz.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/jazz/setup.c linux.ac/arch/mips/jazz/setup.c --- linux.vanilla/arch/mips/jazz/setup.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/jazz/setup.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/Makefile linux.ac/arch/mips/kernel/Makefile --- linux.vanilla/arch/mips/kernel/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/Makefile Tue Jun 22 01:42:44 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/entry.S linux.ac/arch/mips/kernel/entry.S --- linux.vanilla/arch/mips/kernel/entry.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/entry.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/fpe.c linux.ac/arch/mips/kernel/fpe.c --- linux.vanilla/arch/mips/kernel/fpe.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/fpe.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/gdb-low.S linux.ac/arch/mips/kernel/gdb-low.S --- linux.vanilla/arch/mips/kernel/gdb-low.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/gdb-low.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/gdb-stub.c linux.ac/arch/mips/kernel/gdb-stub.c --- linux.vanilla/arch/mips/kernel/gdb-stub.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/gdb-stub.c Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/head.S linux.ac/arch/mips/kernel/head.S --- linux.vanilla/arch/mips/kernel/head.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/head.S Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/init_task.c linux.ac/arch/mips/kernel/init_task.c --- linux.vanilla/arch/mips/kernel/init_task.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/init_task.c Fri Jun 4 23:52:50 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/ipc.c linux.ac/arch/mips/kernel/ipc.c --- linux.vanilla/arch/mips/kernel/ipc.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/ipc.c Wed Jul 7 07:06:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irix5sys.h linux.ac/arch/mips/kernel/irix5sys.h --- linux.vanilla/arch/mips/kernel/irix5sys.h Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/irix5sys.h Tue Jun 22 01:20:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixelf.c linux.ac/arch/mips/kernel/irixelf.c --- linux.vanilla/arch/mips/kernel/irixelf.c Fri Nov 13 01:37:10 1998 +++ linux.ac/arch/mips/kernel/irixelf.c Tue Jun 29 02:52:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixinv.c linux.ac/arch/mips/kernel/irixinv.c --- linux.vanilla/arch/mips/kernel/irixinv.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/irixinv.c Tue Jun 22 01:21:37 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixioctl.c linux.ac/arch/mips/kernel/irixioctl.c --- linux.vanilla/arch/mips/kernel/irixioctl.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/mips/kernel/irixioctl.c Tue Jun 22 01:22:45 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irixsig.c linux.ac/arch/mips/kernel/irixsig.c --- linux.vanilla/arch/mips/kernel/irixsig.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/mips/kernel/irixsig.c Tue Jun 22 01:21:37 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/irq.c linux.ac/arch/mips/kernel/irq.c --- linux.vanilla/arch/mips/kernel/irq.c Mon Dec 28 23:09:40 1998 +++ linux.ac/arch/mips/kernel/irq.c Tue Jun 22 01:22:56 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/mips_ksyms.c linux.ac/arch/mips/kernel/mips_ksyms.c --- linux.vanilla/arch/mips/kernel/mips_ksyms.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/mips_ksyms.c Tue Jun 22 01:23:09 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/pci.c linux.ac/arch/mips/kernel/pci.c --- linux.vanilla/arch/mips/kernel/pci.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/pci.c Tue Jun 22 01:23:56 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/process.c linux.ac/arch/mips/kernel/process.c --- linux.vanilla/arch/mips/kernel/process.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/process.c Tue Jun 22 01:23:09 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/ptrace.c linux.ac/arch/mips/kernel/ptrace.c --- linux.vanilla/arch/mips/kernel/ptrace.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/ptrace.c Tue Jun 22 01:23:09 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_fpu.S linux.ac/arch/mips/kernel/r2300_fpu.S --- linux.vanilla/arch/mips/kernel/r2300_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_fpu.S Tue Jun 22 03:31:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_misc.S linux.ac/arch/mips/kernel/r2300_misc.S --- linux.vanilla/arch/mips/kernel/r2300_misc.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_misc.S Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r2300_switch.S linux.ac/arch/mips/kernel/r2300_switch.S --- linux.vanilla/arch/mips/kernel/r2300_switch.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r2300_switch.S Tue Jun 22 01:25:25 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_fpu.S linux.ac/arch/mips/kernel/r4k_fpu.S --- linux.vanilla/arch/mips/kernel/r4k_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r4k_fpu.S Tue Jun 22 01:25:31 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_misc.S linux.ac/arch/mips/kernel/r4k_misc.S --- linux.vanilla/arch/mips/kernel/r4k_misc.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/r4k_misc.S Mon Jul 19 19:48:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r4k_switch.S linux.ac/arch/mips/kernel/r4k_switch.S --- linux.vanilla/arch/mips/kernel/r4k_switch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/r4k_switch.S Tue Jun 22 01:25:56 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/r6000_fpu.S linux.ac/arch/mips/kernel/r6000_fpu.S --- linux.vanilla/arch/mips/kernel/r6000_fpu.S Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/r6000_fpu.S Tue Jun 22 01:26:15 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/scall_o32.S linux.ac/arch/mips/kernel/scall_o32.S --- linux.vanilla/arch/mips/kernel/scall_o32.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/scall_o32.S Tue Jun 22 01:26:15 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/setup.c linux.ac/arch/mips/kernel/setup.c --- linux.vanilla/arch/mips/kernel/setup.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/setup.c Mon Jul 19 19:48:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/signal.c linux.ac/arch/mips/kernel/signal.c --- linux.vanilla/arch/mips/kernel/signal.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/signal.c Tue Jun 22 01:28:15 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/softfp.S linux.ac/arch/mips/kernel/softfp.S --- linux.vanilla/arch/mips/kernel/softfp.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/softfp.S Tue Jun 22 01:28:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/syscall.c linux.ac/arch/mips/kernel/syscall.c --- linux.vanilla/arch/mips/kernel/syscall.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/syscall.c Tue Jun 22 01:28:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/syscalls.h linux.ac/arch/mips/kernel/syscalls.h --- linux.vanilla/arch/mips/kernel/syscalls.h Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/syscalls.h Tue Jun 22 01:28:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/sysirix.c linux.ac/arch/mips/kernel/sysirix.c --- linux.vanilla/arch/mips/kernel/sysirix.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/mips/kernel/sysirix.c Tue Jun 22 03:31:56 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/sysmips.c linux.ac/arch/mips/kernel/sysmips.c --- linux.vanilla/arch/mips/kernel/sysmips.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/kernel/sysmips.c Tue Jun 22 01:28:35 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/time.c linux.ac/arch/mips/kernel/time.c --- linux.vanilla/arch/mips/kernel/time.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/mips/kernel/time.c Mon Jul 19 03:45:42 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/traps.c linux.ac/arch/mips/kernel/traps.c --- linux.vanilla/arch/mips/kernel/traps.c Wed Jan 6 23:02:18 1999 +++ linux.ac/arch/mips/kernel/traps.c Tue Jun 22 01:28:35 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/kernel/unaligned.c linux.ac/arch/mips/kernel/unaligned.c --- linux.vanilla/arch/mips/kernel/unaligned.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/kernel/unaligned.c Tue Jun 22 01:28:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/Makefile linux.ac/arch/mips/lib/Makefile --- linux.vanilla/arch/mips/lib/Makefile Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/Makefile Tue Jun 22 01:28:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/csum_partial.S linux.ac/arch/mips/lib/csum_partial.S --- linux.vanilla/arch/mips/lib/csum_partial.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/csum_partial.S Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/csum_partial_copy.c linux.ac/arch/mips/lib/csum_partial_copy.c --- linux.vanilla/arch/mips/lib/csum_partial_copy.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/csum_partial_copy.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/floppy-std.c linux.ac/arch/mips/lib/floppy-std.c --- linux.vanilla/arch/mips/lib/floppy-std.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/lib/floppy-std.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/ide-no.c linux.ac/arch/mips/lib/ide-no.c --- linux.vanilla/arch/mips/lib/ide-no.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/ide-no.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/ide-std.c linux.ac/arch/mips/lib/ide-std.c --- linux.vanilla/arch/mips/lib/ide-std.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/ide-std.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/kbd-no.c linux.ac/arch/mips/lib/kbd-no.c --- linux.vanilla/arch/mips/lib/kbd-no.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/lib/kbd-no.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/kbd-std.c linux.ac/arch/mips/lib/kbd-std.c --- linux.vanilla/arch/mips/lib/kbd-std.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/lib/kbd-std.c Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/memcpy.S linux.ac/arch/mips/lib/memcpy.S --- linux.vanilla/arch/mips/lib/memcpy.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/memcpy.S Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/memset.S linux.ac/arch/mips/lib/memset.S --- linux.vanilla/arch/mips/lib/memset.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/memset.S Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/strlen_user.S linux.ac/arch/mips/lib/strlen_user.S --- linux.vanilla/arch/mips/lib/strlen_user.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/strlen_user.S Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/strncpy_user.S linux.ac/arch/mips/lib/strncpy_user.S --- linux.vanilla/arch/mips/lib/strncpy_user.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/strncpy_user.S Tue Jun 22 01:29:55 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/tags.c linux.ac/arch/mips/lib/tags.c --- linux.vanilla/arch/mips/lib/tags.c Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/tags.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/lib/watch.S linux.ac/arch/mips/lib/watch.S --- linux.vanilla/arch/mips/lib/watch.S Sun Nov 8 15:08:30 1998 +++ linux.ac/arch/mips/lib/watch.S Fri Jun 4 23:52:50 1999 @@ -1,6 +1,6 @@ /* * Kernel debug stuff to use the Watch registers. - * Usefull to find stack overflows, dangeling pointers etc. + * Useful to find stack overflows, dangling pointers etc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/Makefile linux.ac/arch/mips/mm/Makefile --- linux.vanilla/arch/mips/mm/Makefile Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/Makefile Tue Jun 22 01:31:04 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/andes.c linux.ac/arch/mips/mm/andes.c --- linux.vanilla/arch/mips/mm/andes.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/andes.c Tue Jun 22 01:31:04 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/fault.c linux.ac/arch/mips/mm/fault.c --- linux.vanilla/arch/mips/mm/fault.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/fault.c Tue Jun 22 01:31:04 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/init.c linux.ac/arch/mips/mm/init.c --- linux.vanilla/arch/mips/mm/init.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/init.c Tue Jun 22 01:31:32 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/loadmmu.c linux.ac/arch/mips/mm/loadmmu.c --- linux.vanilla/arch/mips/mm/loadmmu.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/loadmmu.c Tue Jun 22 01:31:48 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/r2300.c linux.ac/arch/mips/mm/r2300.c --- linux.vanilla/arch/mips/mm/r2300.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/r2300.c Tue Jun 22 01:31:48 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/r4xx0.c linux.ac/arch/mips/mm/r4xx0.c --- linux.vanilla/arch/mips/mm/r4xx0.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/r4xx0.c Tue Jun 22 01:31:48 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/r6000.c linux.ac/arch/mips/mm/r6000.c --- linux.vanilla/arch/mips/mm/r6000.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/r6000.c Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/mm/tfp.c linux.ac/arch/mips/mm/tfp.c --- linux.vanilla/arch/mips/mm/tfp.c Sun Nov 8 15:08:29 1998 +++ linux.ac/arch/mips/mm/tfp.c Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/Makefile linux.ac/arch/mips/sgi/kernel/Makefile --- linux.vanilla/arch/mips/sgi/kernel/Makefile Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/Makefile Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indyIRQ.S linux.ac/arch/mips/sgi/kernel/indyIRQ.S --- linux.vanilla/arch/mips/sgi/kernel/indyIRQ.S Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/indyIRQ.S Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indy_hpc.c linux.ac/arch/mips/sgi/kernel/indy_hpc.c --- linux.vanilla/arch/mips/sgi/kernel/indy_hpc.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/indy_hpc.c Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indy_int.c linux.ac/arch/mips/sgi/kernel/indy_int.c --- linux.vanilla/arch/mips/sgi/kernel/indy_int.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/indy_int.c Mon Jul 19 03:45:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indy_mc.c linux.ac/arch/mips/sgi/kernel/indy_mc.c --- linux.vanilla/arch/mips/sgi/kernel/indy_mc.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/indy_mc.c Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indy_sc.c linux.ac/arch/mips/sgi/kernel/indy_sc.c --- linux.vanilla/arch/mips/sgi/kernel/indy_sc.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/mips/sgi/kernel/indy_sc.c Mon Jul 19 19:48:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/indy_timer.c linux.ac/arch/mips/sgi/kernel/indy_timer.c --- linux.vanilla/arch/mips/sgi/kernel/indy_timer.c Wed Mar 24 10:55:10 1999 +++ linux.ac/arch/mips/sgi/kernel/indy_timer.c Tue Jun 22 01:32:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/promcon.c linux.ac/arch/mips/sgi/kernel/promcon.c --- linux.vanilla/arch/mips/sgi/kernel/promcon.c Thu Jan 1 01:00:00 1970 +++ linux.ac/arch/mips/sgi/kernel/promcon.c Tue Jun 22 01:32:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/reset.c linux.ac/arch/mips/sgi/kernel/reset.c --- linux.vanilla/arch/mips/sgi/kernel/reset.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/reset.c Tue Jun 22 01:32:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/setup.c linux.ac/arch/mips/sgi/kernel/setup.c --- linux.vanilla/arch/mips/sgi/kernel/setup.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/mips/sgi/kernel/setup.c Tue Jun 22 01:32:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/system.c linux.ac/arch/mips/sgi/kernel/system.c --- linux.vanilla/arch/mips/sgi/kernel/system.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/system.c Tue Jun 22 01:32:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/kernel/time.c linux.ac/arch/mips/sgi/kernel/time.c --- linux.vanilla/arch/mips/sgi/kernel/time.c Sun Nov 8 15:08:31 1998 +++ linux.ac/arch/mips/sgi/kernel/time.c Tue Jun 22 01:32:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/Makefile linux.ac/arch/mips/sgi/prom/Makefile --- linux.vanilla/arch/mips/sgi/prom/Makefile Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/Makefile Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/cmdline.c linux.ac/arch/mips/sgi/prom/cmdline.c --- linux.vanilla/arch/mips/sgi/prom/cmdline.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/cmdline.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/console.c linux.ac/arch/mips/sgi/prom/console.c --- linux.vanilla/arch/mips/sgi/prom/console.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/console.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/env.c linux.ac/arch/mips/sgi/prom/env.c --- linux.vanilla/arch/mips/sgi/prom/env.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/env.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/file.c linux.ac/arch/mips/sgi/prom/file.c --- linux.vanilla/arch/mips/sgi/prom/file.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/file.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/init.c linux.ac/arch/mips/sgi/prom/init.c --- linux.vanilla/arch/mips/sgi/prom/init.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/init.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/memory.c linux.ac/arch/mips/sgi/prom/memory.c --- linux.vanilla/arch/mips/sgi/prom/memory.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/memory.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/misc.c linux.ac/arch/mips/sgi/prom/misc.c --- linux.vanilla/arch/mips/sgi/prom/misc.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/misc.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/printf.c linux.ac/arch/mips/sgi/prom/printf.c --- linux.vanilla/arch/mips/sgi/prom/printf.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/printf.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/salone.c linux.ac/arch/mips/sgi/prom/salone.c --- linux.vanilla/arch/mips/sgi/prom/salone.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/salone.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/tags.c linux.ac/arch/mips/sgi/prom/tags.c --- linux.vanilla/arch/mips/sgi/prom/tags.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/tags.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/time.c linux.ac/arch/mips/sgi/prom/time.c --- linux.vanilla/arch/mips/sgi/prom/time.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/time.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sgi/prom/tree.c linux.ac/arch/mips/sgi/prom/tree.c --- linux.vanilla/arch/mips/sgi/prom/tree.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sgi/prom/tree.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/Makefile linux.ac/arch/mips/sni/Makefile --- linux.vanilla/arch/mips/sni/Makefile Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/Makefile Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/hw-access.c linux.ac/arch/mips/sni/hw-access.c --- linux.vanilla/arch/mips/sni/hw-access.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/hw-access.c Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/int-handler.S linux.ac/arch/mips/sni/int-handler.S --- linux.vanilla/arch/mips/sni/int-handler.S Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/int-handler.S Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/io.c linux.ac/arch/mips/sni/io.c --- linux.vanilla/arch/mips/sni/io.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/io.c Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/pci.c linux.ac/arch/mips/sni/pci.c --- linux.vanilla/arch/mips/sni/pci.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/pci.c Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/pcimt_scache.c linux.ac/arch/mips/sni/pcimt_scache.c --- linux.vanilla/arch/mips/sni/pcimt_scache.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/pcimt_scache.c Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/sni/setup.c linux.ac/arch/mips/sni/setup.c --- linux.vanilla/arch/mips/sni/setup.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/sni/setup.c Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/tools/Makefile linux.ac/arch/mips/tools/Makefile --- linux.vanilla/arch/mips/tools/Makefile Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/tools/Makefile Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/mips/tools/offset.c linux.ac/arch/mips/tools/offset.c --- linux.vanilla/arch/mips/tools/offset.c Sun Nov 8 15:08:32 1998 +++ linux.ac/arch/mips/tools/offset.c Tue Jun 22 01:32:28 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/amiga/amiints.c linux.ac/arch/ppc/amiga/amiints.c --- linux.vanilla/arch/ppc/amiga/amiints.c Sat Jan 9 21:50:36 1999 +++ linux.ac/arch/ppc/amiga/amiints.c Fri Jun 4 23:52:51 1999 @@ -108,7 +108,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/amiga/config.c linux.ac/arch/ppc/amiga/config.c --- linux.vanilla/arch/ppc/amiga/config.c Tue Dec 22 23:19:31 1998 +++ linux.ac/arch/ppc/amiga/config.c Mon Jul 19 19:48:17 1999 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/irq.c linux.ac/arch/ppc/kernel/irq.c --- linux.vanilla/arch/ppc/kernel/irq.c Tue Jun 15 16:49:46 1999 +++ linux.ac/arch/ppc/kernel/irq.c Mon Jul 19 19:48:17 1999 @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/pci.c linux.ac/arch/ppc/kernel/pci.c --- linux.vanilla/arch/ppc/kernel/pci.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/ppc/kernel/pci.c Mon Jul 19 19:48:17 1999 @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/pmac_setup.c linux.ac/arch/ppc/kernel/pmac_setup.c --- linux.vanilla/arch/ppc/kernel/pmac_setup.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/ppc/kernel/pmac_setup.c Mon Jun 21 13:15:26 1999 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/ppc-stub.c linux.ac/arch/ppc/kernel/ppc-stub.c --- linux.vanilla/arch/ppc/kernel/ppc-stub.c Sun Nov 8 15:08:33 1998 +++ linux.ac/arch/ppc/kernel/ppc-stub.c Mon Jul 19 19:48:17 1999 @@ -107,7 +107,6 @@ #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/process.c linux.ac/arch/ppc/kernel/process.c --- linux.vanilla/arch/ppc/kernel/process.c Thu May 27 22:11:50 1999 +++ linux.ac/arch/ppc/kernel/process.c Mon Jul 19 19:48:17 1999 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/setup.c linux.ac/arch/ppc/kernel/setup.c --- linux.vanilla/arch/ppc/kernel/setup.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/ppc/kernel/setup.c Mon Jul 19 19:48:17 1999 @@ -31,7 +31,6 @@ #endif #include #include -#include extern void pmac_init(unsigned long r3, unsigned long r4, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/ppc/kernel/syscalls.c linux.ac/arch/ppc/kernel/syscalls.c --- linux.vanilla/arch/ppc/kernel/syscalls.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/ppc/kernel/syscalls.c Sat Jun 12 20:10:42 1999 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/ap1000/aplib.c linux.ac/arch/sparc/ap1000/aplib.c --- linux.vanilla/arch/sparc/ap1000/aplib.c Sun Nov 8 15:08:28 1998 +++ linux.ac/arch/sparc/ap1000/aplib.c Mon Jul 19 19:48:17 1999 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/defconfig linux.ac/arch/sparc/defconfig --- linux.vanilla/arch/sparc/defconfig Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc/defconfig Wed Jun 30 19:42:48 1999 @@ -254,7 +254,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/init_task.c linux.ac/arch/sparc/kernel/init_task.c --- linux.vanilla/arch/sparc/kernel/init_task.c Sun Nov 8 15:10:06 1998 +++ linux.ac/arch/sparc/kernel/init_task.c Fri Jun 4 23:52:48 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/pcic.c linux.ac/arch/sparc/kernel/pcic.c --- linux.vanilla/arch/sparc/kernel/pcic.c Wed Mar 24 10:55:12 1999 +++ linux.ac/arch/sparc/kernel/pcic.c Mon Jul 19 19:48:17 1999 @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/process.c linux.ac/arch/sparc/kernel/process.c --- linux.vanilla/arch/sparc/kernel/process.c Thu May 27 22:11:51 1999 +++ linux.ac/arch/sparc/kernel/process.c Mon Jul 19 19:48:17 1999 @@ -37,7 +37,6 @@ #include #include #include -#include #include extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sparc-stub.c linux.ac/arch/sparc/kernel/sparc-stub.c --- linux.vanilla/arch/sparc/kernel/sparc-stub.c Sun Nov 8 15:08:26 1998 +++ linux.ac/arch/sparc/kernel/sparc-stub.c Mon Jul 19 19:48:17 1999 @@ -105,7 +105,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sparc_ksyms.c linux.ac/arch/sparc/kernel/sparc_ksyms.c --- linux.vanilla/arch/sparc/kernel/sparc_ksyms.c Wed Mar 24 10:55:12 1999 +++ linux.ac/arch/sparc/kernel/sparc_ksyms.c Mon Jul 19 19:48:17 1999 @@ -40,7 +40,6 @@ #include #endif #include -#include #include struct poll { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/kernel/sys_sunos.c linux.ac/arch/sparc/kernel/sys_sunos.c --- linux.vanilla/arch/sparc/kernel/sys_sunos.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc/kernel/sys_sunos.c Mon Jul 19 19:48:17 1999 @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/fault.c linux.ac/arch/sparc/mm/fault.c --- linux.vanilla/arch/sparc/mm/fault.c Wed Mar 24 10:55:12 1999 +++ linux.ac/arch/sparc/mm/fault.c Mon Jul 19 19:48:17 1999 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc/mm/init.c linux.ac/arch/sparc/mm/init.c --- linux.vanilla/arch/sparc/mm/init.c Wed Apr 28 19:14:25 1999 +++ linux.ac/arch/sparc/mm/init.c Tue Jun 22 03:35:46 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/config.in linux.ac/arch/sparc64/config.in --- linux.vanilla/arch/sparc64/config.in Wed Apr 28 19:14:25 1999 +++ linux.ac/arch/sparc64/config.in Mon Jun 14 13:48:03 1999 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $ +# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -235,6 +235,16 @@ bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +fi +endmenu + +mainmenu_option next_comment +comment 'Video For Linux' +tristate 'Video For Linux' CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + fi fi endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/defconfig linux.ac/arch/sparc64/defconfig --- linux.vanilla/arch/sparc64/defconfig Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc64/defconfig Wed Jun 30 19:42:48 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 @@ -292,7 +298,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c linux.ac/arch/sparc64/kernel/binfmt_aout32.c --- linux.vanilla/arch/sparc64/kernel/binfmt_aout32.c Wed Mar 24 10:55:13 1999 +++ linux.ac/arch/sparc64/kernel/binfmt_aout32.c Fri Jun 4 23:52:52 1999 @@ -57,8 +57,19 @@ * These are the only things you should do on a core-file: use only these * macros to write out all the necessary info. */ -#define DUMP_WRITE(addr,nr) \ -while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump + +static int dump_write(struct file *file, const void *addr, int nr) +{ + int r; + down(&file->f_dentry->d_inode->i_sem); + r = file->f_op->write(file, addr, nr, &file->f_pos) == nr; + up(&file->f_dentry->d_inode->i_sem); + return r; +} + +#define DUMP_WRITE(addr, nr) \ + if (!dump_write(file, (void *)(addr), (nr))) \ + goto close_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/init_task.c linux.ac/arch/sparc64/kernel/init_task.c --- linux.vanilla/arch/sparc64/kernel/init_task.c Sun Nov 8 15:08:40 1998 +++ linux.ac/arch/sparc64/kernel/init_task.c Fri Jun 4 23:52:52 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/ioctl32.c linux.ac/arch/sparc64/kernel/ioctl32.c --- linux.vanilla/arch/sparc64/kernel/ioctl32.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc64/kernel/ioctl32.c Mon Jul 19 03:26:58 1999 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -1992,11 +1992,24 @@ case BLKRASET: /* 0x09 */ - case REGISTER_DEV: - case REGISTER_DEV_NEW: - case START_MD: - case STOP_MD: - + case RAID_VERSION: + case GET_ARRAY_INFO: + case GET_DISK_INFO: + case CLEAR_ARRAY: + case ADD_NEW_DISK: + case HOT_REMOVE_DISK: + case SET_ARRAY_INFO: + case SET_DISK_INFO: + case WRITE_RAID_INFO: + case UNPROTECT_ARRAY: + case PROTECT_ARRAY: + case HOT_ADD_DISK: + case RUN_ARRAY: + case START_ARRAY: + case STOP_ARRAY: + case STOP_ARRAY_RO: + case RESTART_ARRAY_RW: + /* Big K */ case PIO_FONT: case GIO_FONT: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/psycho.c linux.ac/arch/sparc64/kernel/psycho.c --- linux.vanilla/arch/sparc64/kernel/psycho.c Wed Apr 28 19:14:25 1999 +++ linux.ac/arch/sparc64/kernel/psycho.c Mon Jul 19 19:48:17 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.1 1999/07/01 10:41:16 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -68,7 +68,6 @@ #include #include -#include #include #include #include @@ -757,13 +756,15 @@ unsigned short stmp; unsigned int itmp; +#if 0 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; } } +#endif for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -795,13 +796,14 @@ pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp); itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp); - +#if 0 /* Don't mess with the retry limit and PIO/DMA latency * 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); +#endif } } } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c linux.ac/arch/sparc64/kernel/sparc64_ksyms.c --- linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c Thu May 27 22:11:51 1999 +++ linux.ac/arch/sparc64/kernel/sparc64_ksyms.c Mon Jul 19 19:48:18 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) @@ -45,7 +45,6 @@ #include #endif #include -#include struct poll { int fd; @@ -83,6 +82,7 @@ extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); +extern void VISenter(void); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -206,6 +206,7 @@ /* Kernel thread creation. */ EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(init_mm); /* prom symbols */ EXPORT_SYMBOL(idprom); @@ -297,6 +298,9 @@ * and will always be 'void __ret_efault(void)'. */ EXPORT_SYMBOL_NOVERS(__ret_efault); +/* VISenter is defined in assembly as well. + */ +EXPORT_SYMBOL_NOVERS(VISenter); /* No version information on these, as gcc produces such symbols. */ EXPORT_SYMBOL_NOVERS(memcmp); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.ac/arch/sparc64/kernel/sys_sparc32.c --- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc64/kernel/sys_sparc32.c Mon Jul 19 19:48:18 1999 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -32,18 +31,15 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/kernel/sys_sunos32.c linux.ac/arch/sparc64/kernel/sys_sunos32.c --- linux.vanilla/arch/sparc64/kernel/sys_sunos32.c Tue Jun 15 16:49:47 1999 +++ linux.ac/arch/sparc64/kernel/sys_sunos32.c Mon Jul 19 19:48:18 1999 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/mm/init.c linux.ac/arch/sparc64/mm/init.c --- linux.vanilla/arch/sparc64/mm/init.c Thu May 27 22:11:51 1999 +++ linux.ac/arch/sparc64/mm/init.c Wed Jun 30 19:42:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/arch/sparc64/solaris/socksys.c linux.ac/arch/sparc64/solaris/socksys.c --- linux.vanilla/arch/sparc64/solaris/socksys.c Sun Nov 8 15:08:42 1998 +++ linux.ac/arch/sparc64/solaris/socksys.c Mon Jul 19 19:48:18 1999 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/Makefile linux.ac/drivers/Makefile --- linux.vanilla/drivers/Makefile Thu May 27 22:11:52 1999 +++ linux.ac/drivers/Makefile Tue Jun 22 01:35:01 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/ap1000/bif.c linux.ac/drivers/ap1000/bif.c --- linux.vanilla/drivers/ap1000/bif.c Sun Nov 8 15:08:12 1998 +++ linux.ac/drivers/ap1000/bif.c Mon Jul 19 19:48:18 1999 @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/Config.in linux.ac/drivers/block/Config.in --- linux.vanilla/drivers/block/Config.in Thu May 27 22:11:52 1999 +++ linux.ac/drivers/block/Config.in Mon Jul 19 20:31:16 1999 @@ -95,25 +95,35 @@ comment 'Additional Block Devices' +tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N +if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then + bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y +fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP if [ "$CONFIG_NET" = "y" ]; then tristate 'Network block device support' CONFIG_BLK_DEV_NBD fi bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then + bool 'Autodetect RAID partitions' CONFIG_AUTODETECT_RAID tristate ' Linear (append) mode' CONFIG_MD_LINEAR tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 -fi -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT + tristate ' Translucent mode' CONFIG_MD_TRANSLUCENT + tristate ' Logical Volume Manager support' CONFIG_MD_LVM + if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then + bool ' Boot support (linear, striped)' CONFIG_MD_BOOT + fi fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD 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 +138,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/DAC960.c linux.ac/drivers/block/DAC960.c --- linux.vanilla/drivers/block/DAC960.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/DAC960.c Mon Jul 19 20:31:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/DAC960.h linux.ac/drivers/block/DAC960.h --- linux.vanilla/drivers/block/DAC960.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/DAC960.h Mon Jul 19 20:31:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/Makefile linux.ac/drivers/block/Makefile --- linux.vanilla/drivers/block/Makefile Fri Apr 16 22:10:51 1999 +++ linux.ac/drivers/block/Makefile Mon Jul 19 20:31:17 1999 @@ -234,6 +234,30 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_LVM),y) +L_OBJS += lvm.o +else + ifeq ($(CONFIG_BLK_DEV_LVM),m) + M_OBJS += lvm.o + 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 @@ -262,10 +286,28 @@ endif ifeq ($(CONFIG_MD_RAID5),y) +LX_OBJS += xor.o L_OBJS += raid5.o else ifeq ($(CONFIG_MD_RAID5),m) + LX_OBJS += xor.o M_OBJS += raid5.o + endif +endif + +ifeq ($(CONFIG_MD_TRANSLUCENT),y) +L_OBJS += translucent.o +else + ifeq ($(CONFIG_MD_TRANSLUCENT),m) + M_OBJS += translucent.o + endif +endif + +ifeq ($(CONFIG_MD_HSM),y) +L_OBJS += hsm.o +else + ifeq ($(CONFIG_MD_HSM),m) + M_OBJS += hsm.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/README.lvm linux.ac/drivers/block/README.lvm --- linux.vanilla/drivers/block/README.lvm Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/README.lvm Wed Jun 16 14:25:39 1999 @@ -0,0 +1,8 @@ + +This is the Logical Volume Manager driver for Linux, + +Tools, library that manage logical volumes can be found +at . + +There you can obtain actual driver versions too. + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/cpqarray.c linux.ac/drivers/block/cpqarray.c --- linux.vanilla/drivers/block/cpqarray.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/cpqarray.c Mon Jul 19 03:45:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/cpqarray.h linux.ac/drivers/block/cpqarray.h --- linux.vanilla/drivers/block/cpqarray.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/cpqarray.h Mon Jul 19 21:13:31 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/genhd.c linux.ac/drivers/block/genhd.c --- linux.vanilla/drivers/block/genhd.c Fri Apr 16 22:10:51 1999 +++ linux.ac/drivers/block/genhd.c Mon Jul 19 20:35:26 1999 @@ -28,8 +28,10 @@ #include #include #include +#include #include +#include /* * Many architectures don't like unaligned accesses, which is @@ -58,6 +60,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 +70,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 +100,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 +117,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 +131,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 +145,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 +175,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 +290,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 +355,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 +402,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 +469,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 +589,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 +657,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 +716,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 +729,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 +748,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 +809,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 +821,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 +883,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 +894,6 @@ #endif #ifdef CONFIG_AMIGA_PARTITION -#include #include static __inline__ u32 @@ -923,27 +964,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 +1100,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 +1191,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 +1217,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 +1244,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 +1259,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 +1356,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 +1419,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 +1437,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 +1447,9 @@ #ifdef CONFIG_SCSI scsi_dev_init(); #endif +#ifdef CONFIG_BLK_CPQ_DA + cpqarray_init(); +#endif #ifdef CONFIG_INET net_dev_init(); #endif @@ -1364,6 +1467,9 @@ #endif rd_load(); #endif +#ifdef CONFIG_BLK_DEV_MD + autodetect_raid(); +#endif #ifdef CONFIG_MD_BOOT md_setup_drive(); #endif @@ -1373,7 +1479,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/hsm.c linux.ac/drivers/block/hsm.c --- linux.vanilla/drivers/block/hsm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/hsm.c Mon Jul 19 03:26:58 1999 @@ -0,0 +1,840 @@ +/* + hsm.c : HSM RAID driver for Linux + Copyright (C) 1998 Ingo Molnar + + HSM mode management functions. + + 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. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include + +#include +#include + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER +#define MD_PERSONALITY + + +#define DEBUG_HSM 1 + +#if DEBUG_HSM +#define dprintk(x,y...) printk(x,##y) +#else +#define dprintk(x,y...) do { } while (0) +#endif + +void print_bh(struct buffer_head *bh) +{ + dprintk("bh %p: %lx %lx %x %x %lx %p %lx %p %x %p %x %lx\n", bh, + bh->b_blocknr, bh->b_size, bh->b_dev, bh->b_rdev, + bh->b_rsector, bh->b_this_page, bh->b_state, + bh->b_next_free, bh->b_count, bh->b_data, + bh->b_list, bh->b_flushtime + ); +} + +static int check_bg (pv_t *pv, pv_block_group_t * bg) +{ + int i, free = 0; + + dprintk("checking bg ...\n"); + + for (i = 0; i < pv->pv_sb->pv_bg_size-1; i++) { + if (pv_pptr_free(bg->blocks + i)) { + free++; + if (test_bit(i, bg->used_bitmap)) { + printk("hm, bit %d set?\n", i); + } + } else { + if (!test_bit(i, bg->used_bitmap)) { + printk("hm, bit %d not set?\n", i); + } + } + } + dprintk("%d free blocks in bg ...\n", free); + return free; +} + +static void get_bg (pv_t *pv, pv_bg_desc_t *desc, int nr) +{ + unsigned int bg_pos = nr * pv->pv_sb->pv_bg_size + 2; + struct buffer_head *bh; + + dprintk("... getting BG at %u ...\n", bg_pos); + + bh = bread (pv->dev, bg_pos, HSM_BLOCKSIZE); + if (!bh) { + MD_BUG(); + return; + } + desc->bg = (pv_block_group_t *) bh->b_data; + desc->free_blocks = check_bg(pv, desc->bg); +} + +static int find_free_block (lv_t *lv, pv_t *pv, pv_bg_desc_t *desc, int nr, + unsigned int lblock, lv_lptr_t * index) +{ + int i; + + for (i = 0; i < pv->pv_sb->pv_bg_size-1; i++) { + pv_pptr_t * bptr = desc->bg->blocks + i; + if (pv_pptr_free(bptr)) { + unsigned int bg_pos = nr * pv->pv_sb->pv_bg_size + 2; + + if (test_bit(i, desc->bg->used_bitmap)) { + MD_BUG(); + continue; + } + bptr->u.used.owner.log_id = lv->log_id; + bptr->u.used.owner.log_index = lblock; + index->data.phys_nr = pv->phys_nr; + index->data.phys_block = bg_pos + i + 1; + set_bit(i, desc->bg->used_bitmap); + desc->free_blocks--; + dprintk(".....free blocks left in bg %p: %d\n", + desc->bg, desc->free_blocks); + return 0; + } + } + return -ENOSPC; +} + +static int __get_free_block (lv_t *lv, pv_t *pv, + unsigned int lblock, lv_lptr_t * index) +{ + int i; + + dprintk("trying to get free block for lblock %d ...\n", lblock); + + for (i = 0; i < pv->pv_sb->pv_block_groups; i++) { + pv_bg_desc_t *desc = pv->bg_array + i; + + dprintk("looking at desc #%d (%p)...\n", i, desc->bg); + if (!desc->bg) + get_bg(pv, desc, i); + + if (desc->bg && desc->free_blocks) + return find_free_block(lv, pv, desc, i, + lblock, index); + } + dprintk("hsm: pv %s full!\n", partition_name(pv->dev)); + return -ENOSPC; +} + +static int get_free_block (lv_t *lv, unsigned int lblock, lv_lptr_t * index) +{ + int err; + + if (!lv->free_indices) + return -ENOSPC; + + /* fix me */ + err = __get_free_block(lv, lv->vg->pv_array + 0, lblock, index); + + if (err || !index->data.phys_block) { + MD_BUG(); + return -ENOSPC; + } + + lv->free_indices--; + + return 0; +} + +/* + * fix me: wordsize assumptions ... + */ +#define INDEX_BITS 8 +#define INDEX_DEPTH (32/INDEX_BITS) +#define INDEX_MASK ((1< [.", index->data.phys_nr, + index->data.phys_block, index->cpu_addr); + + tmp = index_child(index); + for (i = 0; i < HSM_LPTRS_PER_BLOCK; i++) { + if (index_block(lv, tmp)) + dprintk("(%d->%d)", i, index_block(lv, tmp)); + tmp++; + } + dprintk(".]\n"); +} + +static int read_index_group (lv_t *lv, lv_lptr_t *index) +{ + lv_lptr_t *index_group, *tmp; + struct buffer_head *bh; + int i; + + dprintk("reading index group <%s:%d>\n", + partition_name(index_dev(lv, index)), index_block(lv, index)); + + bh = bread(index_dev(lv, index), index_block(lv, index), HSM_BLOCKSIZE); + if (!bh) { + MD_BUG(); + return -EIO; + } + if (!buffer_uptodate(bh)) + MD_BUG(); + + index_group = (lv_lptr_t *) bh->b_data; + tmp = index_group; + for (i = 0; i < HSM_LPTRS_PER_BLOCK; i++) { + if (index_block(lv, tmp)) { + dprintk("index group has BLOCK %d, non-present.\n", i); + tmp->cpu_addr = 0; + } + tmp++; + } + index->cpu_addr = ptr_to_cpuaddr(index_group); + + dprintk("have read index group %p at block %d.\n", + index_group, index_block(lv, index)); + print_index_list(lv, index); + + return 0; +} + +static int alloc_index_group (lv_t *lv, unsigned int lblock, lv_lptr_t * index) +{ + struct buffer_head *bh; + lv_lptr_t * index_group; + + if (get_free_block(lv, lblock, index)) + return -ENOSPC; + + dprintk("creating block for index group <%s:%d>\n", + partition_name(index_dev(lv, index)), index_block(lv, index)); + + bh = getblk(index_dev(lv, index), + index_block(lv, index), HSM_BLOCKSIZE); + + index_group = (lv_lptr_t *) bh->b_data; + md_clear_page(index_group); + mark_buffer_uptodate(bh, 1); + + index->cpu_addr = ptr_to_cpuaddr(index_group); + + dprintk("allocated index group %p at block %d.\n", + index_group, index_block(lv, index)); + return 0; +} + +static lv_lptr_t * alloc_fixed_index (lv_t *lv, unsigned int lblock) +{ + lv_lptr_t * index = index_child(&lv->root_index); + int idx, l; + + for (l = INDEX_DEPTH-1; l >= 0; l--) { + idx = (lblock >> (INDEX_BITS*l)) & INDEX_MASK; + index += idx; + if (!l) + break; + if (!index_present(index)) { + dprintk("no group, level %u, pos %u\n", l, idx); + if (alloc_index_group(lv, lblock, index)) + return NULL; + } + index = index_child(index); + } + if (!index_block(lv,index)) { + dprintk("no data, pos %u\n", idx); + if (get_free_block(lv, lblock, index)) + return NULL; + return index; + } + MD_BUG(); + return index; +} + +static lv_lptr_t * find_index (lv_t *lv, unsigned int lblock) +{ + lv_lptr_t * index = index_child(&lv->root_index); + int idx, l; + + for (l = INDEX_DEPTH-1; l >= 0; l--) { + idx = (lblock >> (INDEX_BITS*l)) & INDEX_MASK; + index += idx; + if (!l) + break; + if (index_free(index)) + return NULL; + if (!index_present(index)) + read_index_group(lv, index); + if (!index_present(index)) { + MD_BUG(); + return NULL; + } + index = index_child(index); + } + if (!index_block(lv,index)) + return NULL; + return index; +} + +static int read_root_index(lv_t *lv) +{ + int err; + lv_lptr_t *index = &lv->root_index; + + if (!index_block(lv, index)) { + printk("LV has no root index yet, creating.\n"); + + err = alloc_index_group (lv, 0, index); + if (err) { + printk("could not create index group, err:%d\n", err); + return err; + } + lv->vg->vg_sb->lv_array[lv->log_id].lv_root_idx = + lv->root_index.data; + } else { + printk("LV already has a root index.\n"); + printk("... at <%s:%d>.\n", + partition_name(index_dev(lv, index)), + index_block(lv, index)); + + read_index_group(lv, index); + } + return 0; +} + +static int init_pv(pv_t *pv) +{ + struct buffer_head *bh; + pv_sb_t *pv_sb; + + bh = bread (pv->dev, 0, HSM_BLOCKSIZE); + if (!bh) { + MD_BUG(); + return -1; + } + + pv_sb = (pv_sb_t *) bh->b_data; + pv->pv_sb = pv_sb; + + if (pv_sb->pv_magic != HSM_PV_SB_MAGIC) { + printk("%s is not a PV, has magic %x instead of %x!\n", + partition_name(pv->dev), pv_sb->pv_magic, + HSM_PV_SB_MAGIC); + return -1; + } + printk("%s detected as a valid PV (#%d).\n", partition_name(pv->dev), + pv->phys_nr); + printk("... created under HSM version %d.%d.%d, at %x.\n", + pv_sb->pv_major, pv_sb->pv_minor, pv_sb->pv_patch, pv_sb->pv_ctime); + printk("... total # of blocks: %d (%d left unallocated).\n", + pv_sb->pv_total_size, pv_sb->pv_blocks_left); + + printk("... block size: %d bytes.\n", pv_sb->pv_block_size); + printk("... block descriptor size: %d bytes.\n", pv_sb->pv_pptr_size); + printk("... block group size: %d blocks.\n", pv_sb->pv_bg_size); + printk("... # of block groups: %d.\n", pv_sb->pv_block_groups); + + if (pv_sb->pv_block_groups*sizeof(pv_bg_desc_t) > PAGE_SIZE) { + MD_BUG(); + return 1; + } + pv->bg_array = (pv_bg_desc_t *)__get_free_page(GFP_KERNEL); + if (!pv->bg_array) { + MD_BUG(); + return 1; + } + memset(pv->bg_array, 0, PAGE_SIZE); + + return 0; +} + +static int free_pv(pv_t *pv) +{ + struct buffer_head *bh; + + dprintk("freeing PV %d ...\n", pv->phys_nr); + + if (pv->bg_array) { + int i; + + dprintk(".... freeing BGs ...\n"); + for (i = 0; i < pv->pv_sb->pv_block_groups; i++) { + unsigned int bg_pos = i * pv->pv_sb->pv_bg_size + 2; + pv_bg_desc_t *desc = pv->bg_array + i; + + if (desc->bg) { + dprintk(".... freeing BG %d ...\n", i); + bh = getblk (pv->dev, bg_pos, HSM_BLOCKSIZE); + mark_buffer_dirty(bh, 1); + brelse(bh); + brelse(bh); + } + } + free_page((unsigned long)pv->bg_array); + } else + MD_BUG(); + + bh = getblk (pv->dev, 0, HSM_BLOCKSIZE); + if (!bh) { + MD_BUG(); + return -1; + } + mark_buffer_dirty(bh, 1); + brelse(bh); + brelse(bh); + + return 0; +} + +struct semaphore hsm_sem = MUTEX; + +#define HSM_SECTORS (HSM_BLOCKSIZE/512) + +static int hsm_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, + unsigned long *rsector, unsigned long bsectors) +{ + lv_t *lv = kdev_to_lv(dev); + lv_lptr_t *index; + unsigned int lblock = *rsector / HSM_SECTORS; + unsigned int offset = *rsector % HSM_SECTORS; + int err = -EIO; + + if (!lv) { + printk("HSM: md%d not a Logical Volume!\n", mdidx(mddev)); + goto out; + } + if (offset + bsectors > HSM_SECTORS) { + MD_BUG(); + goto out; + } + down(&hsm_sem); + index = find_index(lv, lblock); + if (!index) { + printk("no block %u yet ... allocating\n", lblock); + index = alloc_fixed_index(lv, lblock); + } + + err = 0; + + printk(" %u <%s : %ld(%ld)> -> ", lblock, + partition_name(*rdev), *rsector, bsectors); + + *rdev = index_dev(lv, index); + *rsector = index_block(lv, index) * HSM_SECTORS + offset; + + printk(" <%s : %ld> %u\n", + partition_name(*rdev), *rsector, index_block(lv, index)); + + up(&hsm_sem); +out: + return err; +} + +static void free_index (lv_t *lv, lv_lptr_t * index) +{ + struct buffer_head *bh; + + printk("tryin to get cached block for index group <%s:%d>\n", + partition_name(index_dev(lv, index)), index_block(lv, index)); + + bh = getblk(index_dev(lv, index), index_block(lv, index),HSM_BLOCKSIZE); + + printk("....FREEING "); + print_index_list(lv, index); + + if (bh) { + if (!buffer_uptodate(bh)) + MD_BUG(); + if ((lv_lptr_t *)bh->b_data != index_child(index)) { + printk("huh? b_data is %p, index content is %p.\n", + bh->b_data, index_child(index)); + } else + printk("good, b_data == index content == %p.\n", + index_child(index)); + printk("b_count == %d, writing.\n", bh->b_count); + mark_buffer_dirty(bh, 1); + brelse(bh); + brelse(bh); + printk("done.\n"); + } else { + printk("FAILED!\n"); + } + print_index_list(lv, index); + index_child(index) = NULL; +} + +static void free_index_group (lv_t *lv, int level, lv_lptr_t * index_0) +{ + char dots [3*8]; + lv_lptr_t * index; + int i, nr_dots; + + nr_dots = (INDEX_DEPTH-level)*3; + memcpy(dots,"...............",nr_dots); + dots[nr_dots] = 0; + + dprintk("%s level %d index group block:\n", dots, level); + + + index = index_0; + for (i = 0; i < HSM_LPTRS_PER_BLOCK; i++) { + if (index->data.phys_block) { + dprintk("%s block <%u,%u,%x>\n", dots, + index->data.phys_nr, + index->data.phys_block, + index->cpu_addr); + if (level && index_present(index)) { + dprintk("%s==> deeper one level\n", dots); + free_index_group(lv, level-1, + index_child(index)); + dprintk("%s freeing index group block %p ...", + dots, index_child(index)); + free_index(lv, index); + } + } + index++; + } + dprintk("%s DONE: level %d index group block.\n", dots, level); +} + +static void free_lv_indextree (lv_t *lv) +{ + dprintk("freeing LV %d ...\n", lv->log_id); + dprintk("..root index: %p\n", index_child(&lv->root_index)); + dprintk("..INDEX TREE:\n"); + free_index_group(lv, INDEX_DEPTH-1, index_child(&lv->root_index)); + dprintk("..freeing root index %p ...", index_child(&lv->root_index)); + dprintk("root block <%u,%u,%x>\n", lv->root_index.data.phys_nr, + lv->root_index.data.phys_block, lv->root_index.cpu_addr); + free_index(lv, &lv->root_index); + dprintk("..INDEX TREE done.\n"); + fsync_dev(lv->vg->pv_array[0].dev); /* fix me */ + lv->vg->vg_sb->lv_array[lv->log_id].lv_free_indices = lv->free_indices; +} + +static void print_index_group (lv_t *lv, int level, lv_lptr_t * index_0) +{ + char dots [3*5]; + lv_lptr_t * index; + int i, nr_dots; + + nr_dots = (INDEX_DEPTH-level)*3; + memcpy(dots,"...............",nr_dots); + dots[nr_dots] = 0; + + dprintk("%s level %d index group block:\n", dots, level); + + + for (i = 0; i < HSM_LPTRS_PER_BLOCK; i++) { + index = index_0 + i; + if (index->data.phys_block) { + dprintk("%s block <%u,%u,%x>\n", dots, + index->data.phys_nr, + index->data.phys_block, + index->cpu_addr); + if (level && index_present(index)) { + dprintk("%s==> deeper one level\n", dots); + print_index_group(lv, level-1, + index_child(index)); + } + } + } + dprintk("%s DONE: level %d index group block.\n", dots, level); +} + +static void print_lv (lv_t *lv) +{ + dprintk("printing LV %d ...\n", lv->log_id); + dprintk("..root index: %p\n", index_child(&lv->root_index)); + dprintk("..INDEX TREE:\n"); + print_index_group(lv, INDEX_DEPTH-1, index_child(&lv->root_index)); + dprintk("..INDEX TREE done.\n"); +} + +static int map_lv (lv_t *lv) +{ + kdev_t dev = lv->dev; + unsigned int nr = MINOR(dev); + mddev_t *mddev = lv->vg->mddev; + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return -1; + } + if (kdev_to_mddev(dev)) { + MD_BUG(); + return -1; + } + md_hd_struct[nr].start_sect = 0; + md_hd_struct[nr].nr_sects = md_size[mdidx(mddev)] << 1; + md_size[nr] = md_size[mdidx(mddev)]; + add_mddev_mapping(mddev, dev, lv); + + return 0; +} + +static int unmap_lv (lv_t *lv) +{ + kdev_t dev = lv->dev; + unsigned int nr = MINOR(dev); + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return -1; + } + md_hd_struct[nr].start_sect = 0; + md_hd_struct[nr].nr_sects = 0; + md_size[nr] = 0; + del_mddev_mapping(lv->vg->mddev, dev); + + return 0; +} + +static int init_vg (vg_t *vg) +{ + int i; + lv_t *lv; + kdev_t dev; + vg_sb_t *vg_sb; + struct buffer_head *bh; + lv_descriptor_t *lv_desc; + + /* + * fix me: read all PVs and compare the SB + */ + dev = vg->pv_array[0].dev; + bh = bread (dev, 1, HSM_BLOCKSIZE); + if (!bh) { + MD_BUG(); + return -1; + } + + vg_sb = (vg_sb_t *) bh->b_data; + vg->vg_sb = vg_sb; + + if (vg_sb->vg_magic != HSM_VG_SB_MAGIC) { + printk("%s is not a valid VG, has magic %x instead of %x!\n", + partition_name(dev), vg_sb->vg_magic, + HSM_VG_SB_MAGIC); + return -1; + } + + vg->nr_lv = 0; + for (i = 0; i < HSM_MAX_LVS_PER_VG; i++) { + unsigned int id; + lv_desc = vg->vg_sb->lv_array + i; + + id = lv_desc->lv_id; + if (!id) { + printk("... LV desc %d empty\n", i); + continue; + } + if (id >= HSM_MAX_LVS_PER_VG) { + MD_BUG(); + continue; + } + + lv = vg->lv_array + id; + if (lv->vg) { + MD_BUG(); + continue; + } + lv->log_id = id; + lv->vg = vg; + lv->max_indices = lv_desc->lv_max_indices; + lv->free_indices = lv_desc->lv_free_indices; + lv->root_index.data = lv_desc->lv_root_idx; + lv->dev = MKDEV(MD_MAJOR, lv_desc->md_id); + + vg->nr_lv++; + + map_lv(lv); + if (read_root_index(lv)) { + vg->nr_lv--; + unmap_lv(lv); + memset(lv, 0, sizeof(*lv)); + } + } + if (vg->nr_lv != vg_sb->nr_lvs) + MD_BUG(); + + return 0; +} + +static int hsm_run (mddev_t *mddev) +{ + int i; + vg_t *vg; + mdk_rdev_t *rdev; + + MOD_INC_USE_COUNT; + + vg = kmalloc (sizeof (*vg), GFP_KERNEL); + if (!vg) + goto out; + memset(vg, 0, sizeof(*vg)); + mddev->private = vg; + vg->mddev = mddev; + + if (md_check_ordering(mddev)) { + printk("hsm: disks are not ordered, aborting!\n"); + goto out; + } + + set_blocksize (mddev_to_kdev(mddev), HSM_BLOCKSIZE); + + vg->nr_pv = mddev->nb_dev; + ITERATE_RDEV_ORDERED(mddev,rdev,i) { + pv_t *pv = vg->pv_array + i; + + pv->dev = rdev->dev; + fsync_dev (pv->dev); + set_blocksize (pv->dev, HSM_BLOCKSIZE); + pv->phys_nr = i; + if (init_pv(pv)) + goto out; + } + + init_vg(vg); + + return 0; + +out: + if (vg) { + kfree(vg); + mddev->private = NULL; + } + MOD_DEC_USE_COUNT; + + return 1; +} + +static int hsm_stop (mddev_t *mddev) +{ + lv_t *lv; + vg_t *vg; + int i; + + vg = mddev_to_vg(mddev); + + for (i = 0; i < HSM_MAX_LVS_PER_VG; i++) { + lv = vg->lv_array + i; + if (!lv->log_id) + continue; + print_lv(lv); + free_lv_indextree(lv); + unmap_lv(lv); + } + for (i = 0; i < vg->nr_pv; i++) + free_pv(vg->pv_array + i); + + kfree(vg); + + MOD_DEC_USE_COUNT; + + return 0; +} + + +static int hsm_status (char *page, mddev_t *mddev) +{ + int sz = 0, i; + lv_t *lv; + vg_t *vg; + + vg = mddev_to_vg(mddev); + + for (i = 0; i < HSM_MAX_LVS_PER_VG; i++) { + lv = vg->lv_array + i; + if (!lv->log_id) + continue; + sz += sprintf(page+sz, " ", lv->log_id, + lv->max_indices - lv->free_indices, lv->max_indices); + } + return sz; +} + + +static mdk_personality_t hsm_personality= +{ + "hsm", + hsm_map, + NULL, + NULL, + hsm_run, + hsm_stop, + hsm_status, + NULL, + 0, + NULL, + NULL, + NULL, + NULL +}; + +#ifndef MODULE + +md__initfunc(void hsm_init (void)) +{ + register_md_personality (HSM, &hsm_personality); +} + +#else + +int init_module (void) +{ + return (register_md_personality (HSM, &hsm_personality)); +} + +void cleanup_module (void) +{ + unregister_md_personality (HSM); +} + +#endif + +/* + * This Linus-trick catches bugs via the linker. + */ + +extern void __BUG__in__hsm_dot_c_1(void); +extern void __BUG__in__hsm_dot_c_2(void); +extern void __BUG__in__hsm_dot_c_3(void); +extern void __BUG__in__hsm_dot_c_4(void); +extern void __BUG__in__hsm_dot_c_5(void); +extern void __BUG__in__hsm_dot_c_6(void); +extern void __BUG__in__hsm_dot_c_7(void); + +void bugcatcher (void) +{ + if (sizeof(pv_block_group_t) != HSM_BLOCKSIZE) + __BUG__in__hsm_dot_c_1(); + if (sizeof(lv_index_block_t) != HSM_BLOCKSIZE) + __BUG__in__hsm_dot_c_2(); + + if (sizeof(pv_sb_t) != HSM_BLOCKSIZE) + __BUG__in__hsm_dot_c_4(); + if (sizeof(lv_sb_t) != HSM_BLOCKSIZE) + __BUG__in__hsm_dot_c_3(); + if (sizeof(vg_sb_t) != HSM_BLOCKSIZE) + __BUG__in__hsm_dot_c_6(); + + if (sizeof(lv_lptr_t) != 16) + __BUG__in__hsm_dot_c_5(); + if (sizeof(pv_pptr_t) != 16) + __BUG__in__hsm_dot_c_6(); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ida_cmd.h linux.ac/drivers/block/ida_cmd.h --- linux.vanilla/drivers/block/ida_cmd.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/ida_cmd.h Mon Jul 19 21:13:31 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ida_ioctl.h linux.ac/drivers/block/ida_ioctl.h --- linux.vanilla/drivers/block/ida_ioctl.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/ida_ioctl.h Mon Jul 19 21:13:31 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-cd.c linux.ac/drivers/block/ide-cd.c --- linux.vanilla/drivers/block/ide-cd.c Fri Apr 16 22:10:51 1999 +++ linux.ac/drivers/block/ide-cd.c Mon Jul 19 03:24:24 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-floppy.c linux.ac/drivers/block/ide-floppy.c --- linux.vanilla/drivers/block/ide-floppy.c Mon Dec 28 23:09:41 1998 +++ linux.ac/drivers/block/ide-floppy.c Mon Jul 5 05:01:32 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide-tape.c linux.ac/drivers/block/ide-tape.c --- linux.vanilla/drivers/block/ide-tape.c Sat Jan 9 21:50:36 1999 +++ linux.ac/drivers/block/ide-tape.c Mon Jul 5 05:01:32 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ide.c linux.ac/drivers/block/ide.c --- linux.vanilla/drivers/block/ide.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/block/ide.c Mon Jul 19 03:26:58 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/linear.c linux.ac/drivers/block/linear.c --- linux.vanilla/drivers/block/linear.c Sun Nov 8 15:07:37 1998 +++ linux.ac/drivers/block/linear.c Mon Jul 19 03:26:58 1999 @@ -1,4 +1,3 @@ - /* linear.c : Multiple Devices driver for Linux Copyright (C) 1994-96 Marc ZYNGIER @@ -19,186 +18,207 @@ #include -#include +#include #include -#include -#include "linear.h" +#include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY -static int linear_run (int minor, struct md_dev *mddev) +static int linear_run (mddev_t *mddev) { - int cur=0, i, size, dev0_size, nb_zone; - struct linear_data *data; - - MOD_INC_USE_COUNT; - - mddev->private=kmalloc (sizeof (struct linear_data), GFP_KERNEL); - data=(struct linear_data *) mddev->private; - - /* - Find out the smallest device. This was previously done - at registry time, but since it violates modularity, - I moved it here... Any comment ? ;-) - */ - - data->smallest=mddev->devices; - for (i=1; inb_dev; i++) - if (data->smallest->size > mddev->devices[i].size) - data->smallest=mddev->devices+i; - - nb_zone=data->nr_zones= - md_size[minor]/data->smallest->size + - (md_size[minor]%data->smallest->size ? 1 : 0); - - data->hash_table=kmalloc (sizeof (struct linear_hash)*nb_zone, GFP_KERNEL); - - size=mddev->devices[cur].size; + linear_conf_t *conf; + struct linear_hash *table; + mdk_rdev_t *rdev; + int size, i, j, nb_zone; + unsigned int curr_offset; + + MOD_INC_USE_COUNT; + + conf = kmalloc (sizeof (*conf), GFP_KERNEL); + if (!conf) + goto out; + mddev->private = conf; + + if (md_check_ordering(mddev)) { + printk("linear: disks are not ordered, aborting!\n"); + goto out; + } + /* + * Find the smallest device. + */ + + conf->smallest = NULL; + curr_offset = 0; + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + dev_info_t *disk = conf->disks + j; + + disk->dev = rdev->dev; + disk->size = rdev->size; + disk->offset = curr_offset; + + curr_offset += disk->size; + + if (!conf->smallest || (disk->size < conf->smallest->size)) + conf->smallest = disk; + } + + nb_zone = conf->nr_zones = + md_size[mdidx(mddev)] / conf->smallest->size + + ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); + + conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, + GFP_KERNEL); + if (!conf->hash_table) + goto out; + + /* + * Here we generate the linear hash table + */ + table = conf->hash_table; + i = 0; + size = 0; + for (j = 0; j < mddev->nb_dev; j++) { + dev_info_t *disk = conf->disks + j; + + if (size < 0) { + table->dev1 = disk; + table++; + } + size += disk->size; + + while (size) { + table->dev0 = disk; + size -= conf->smallest->size; + if (size < 0) + break; + table->dev1 = NULL; + table++; + } + } + table->dev1 = NULL; + + return 0; + +out: + if (conf) + kfree(conf); + MOD_DEC_USE_COUNT; + return 1; +} + +static int linear_stop (mddev_t *mddev) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + + kfree(conf->hash_table); + kfree(conf); - i=0; - while (curnb_dev) - { - data->hash_table[i].dev0=mddev->devices+cur; + MOD_DEC_USE_COUNT; - if (size>=data->smallest->size) /* If we completely fill the slot */ - { - data->hash_table[i++].dev1=NULL; - size-=data->smallest->size; - - if (!size) - { - if (++cur==mddev->nb_dev) continue; - size=mddev->devices[cur].size; - } - - continue; - } - - if (++cur==mddev->nb_dev) /* Last dev, set dev1 as NULL */ - { - data->hash_table[i].dev1=NULL; - continue; - } - - dev0_size=size; /* Here, we use a 2nd dev to fill the slot */ - size=mddev->devices[cur].size; - data->hash_table[i++].dev1=mddev->devices+cur; - size-=(data->smallest->size - dev0_size); - } - - return 0; -} - -static int linear_stop (int minor, struct md_dev *mddev) -{ - struct linear_data *data=(struct linear_data *) mddev->private; - - kfree (data->hash_table); - kfree (data); - - MOD_DEC_USE_COUNT; - - return 0; + return 0; } -static int linear_map (struct md_dev *mddev, kdev_t *rdev, +static int linear_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, unsigned long *rsector, unsigned long size) { - struct linear_data *data=(struct linear_data *) mddev->private; - struct linear_hash *hash; - struct real_dev *tmp_dev; - long block; - - block=*rsector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - if (block >= (hash->dev0->size + hash->dev0->offset)) - { - if (!hash->dev1) - { - printk ("linear_map : hash->dev1==NULL for block %ld\n", block); - return (-1); - } - - tmp_dev=hash->dev1; - } - else - tmp_dev=hash->dev0; + linear_conf_t *conf = mddev_to_conf(mddev); + struct linear_hash *hash; + dev_info_t *tmp_dev; + long block; + + block = *rsector >> 1; + hash = conf->hash_table + (block / conf->smallest->size); + + if (block >= (hash->dev0->size + hash->dev0->offset)) + { + if (!hash->dev1) + { + printk ("linear_map : hash->dev1==NULL for block %ld\n", + block); + return -1; + } + tmp_dev = hash->dev1; + } else + tmp_dev = hash->dev0; - if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) - printk ("Block %ld out of bounds on dev %s size %d offset %d\n", - block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); + if (block >= (tmp_dev->size + tmp_dev->offset) + || block < tmp_dev->offset) + printk ("Block %ld out of bounds on dev %s size %d offset %d\n", + block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); - *rdev=tmp_dev->dev; - *rsector=(block-(tmp_dev->offset)) << 1; + *rdev = tmp_dev->dev; + *rsector = (block - tmp_dev->offset) << 1; - return (0); + return 0; } -static int linear_status (char *page, int minor, struct md_dev *mddev) +static int linear_status (char *page, mddev_t *mddev) { - int sz=0; + int sz=0; #undef MD_DEBUG #ifdef MD_DEBUG - int j; - struct linear_data *data=(struct linear_data *) mddev->private; + int j; + linear_conf_t *conf = mddev_to_conf(mddev); - sz+=sprintf (page+sz, " "); - for (j=0; jnr_zones; j++) - { - sz+=sprintf (page+sz, "[%s", - partition_name (data->hash_table[j].dev0->dev)); - - if (data->hash_table[j].dev1) - sz+=sprintf (page+sz, "/%s] ", - partition_name(data->hash_table[j].dev1->dev)); - else - sz+=sprintf (page+sz, "] "); - } - - sz+=sprintf (page+sz, "\n"); + sz += sprintf(page+sz, " "); + for (j = 0; j < conf->nr_zones; j++) + { + sz += sprintf(page+sz, "[%s", + partition_name(conf->hash_table[j].dev0->dev)); + + if (conf->hash_table[j].dev1) + sz += sprintf(page+sz, "/%s] ", + partition_name(conf->hash_table[j].dev1->dev)); + else + sz += sprintf(page+sz, "] "); + } + sz += sprintf(page+sz, "\n"); #endif - sz+=sprintf (page+sz, " %dk rounding", 1<param.chunk_size/1024); + return sz; } -static struct md_personality linear_personality= +static mdk_personality_t linear_personality= { - "linear", - linear_map, - NULL, - NULL, - linear_run, - linear_stop, - linear_status, - NULL, /* no ioctls */ - 0 + "linear", + linear_map, + NULL, + NULL, + linear_run, + linear_stop, + linear_status, + NULL, + 0, + NULL, + NULL, + NULL, + NULL }; - #ifndef MODULE -__initfunc(void linear_init (void)) +md__initfunc(void linear_init (void)) { - register_md_personality (LINEAR, &linear_personality); + register_md_personality (LINEAR, &linear_personality); } #else int init_module (void) { - return (register_md_personality (LINEAR, &linear_personality)); + return (register_md_personality (LINEAR, &linear_personality)); } void cleanup_module (void) { - unregister_md_personality (LINEAR); + unregister_md_personality (LINEAR); } #endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/linear.h linux.ac/drivers/block/linear.h --- linux.vanilla/drivers/block/linear.h Sun Nov 8 15:07:37 1998 +++ linux.ac/drivers/block/linear.h Mon Jul 19 03:26:58 1999 @@ -1,16 +0,0 @@ -#ifndef _LINEAR_H -#define _LINEAR_H - -struct linear_hash -{ - struct real_dev *dev0, *dev1; -}; - -struct linear_data -{ - struct linear_hash *hash_table; /* Dynamically allocated */ - struct real_dev *smallest; - int nr_zones; -}; - -#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/ll_rw_blk.c linux.ac/drivers/block/ll_rw_blk.c --- linux.vanilla/drivers/block/ll_rw_blk.c Wed Mar 24 10:55:15 1999 +++ linux.ac/drivers/block/ll_rw_blk.c Mon Jul 19 20:31:54 1999 @@ -21,9 +21,16 @@ #include #include #include +#include #include +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) +#include + int ( *lvm_map_ptr) ( int, kdev_t *, unsigned long *, + unsigned long, int) = NULL; +#endif + /* * The request-struct contains all necessary data * to load a nr of sectors into memory @@ -51,6 +58,11 @@ spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED; /* + * per-major idle-IO detection + */ +unsigned long io_events[MAX_BLKDEV] = {0, }; + +/* * used to wait on when there are no free requests */ struct wait_queue * wait_for_request = NULL; @@ -108,6 +120,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 +132,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 +290,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 +315,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 +377,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 +392,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; @@ -391,21 +436,28 @@ /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ lock_buffer(bh); + if (!buffer_lowprio(bh)) + io_events[major]++; if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; 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 +489,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 +503,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 @@ -461,7 +514,8 @@ if (!req) { /* MD and loop can't handle plugging without deadlocking */ if (major != MD_MAJOR && major != LOOP_MAJOR && - major != DDV_MAJOR && major != NBD_MAJOR) + major != DDV_MAJOR && major != NBD_MAJOR && + major != LVM_BLK_MAJOR) plug_device(blk_dev + major); /* is atomic */ } else switch (major) { case IDE0_MAJOR: /* same as HD_MAJOR */ @@ -483,7 +537,7 @@ * entry may be busy being processed and we thus can't change it. */ if (req == blk_dev[major].current_request) - req = req->next; + req = req->next; if (!req) break; /* fall through */ @@ -497,6 +551,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 +579,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 +631,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; @@ -611,13 +694,37 @@ /* Md remaps blocks now */ bh[i]->b_rdev = bh[i]->b_dev; bh[i]->b_rsector=bh[i]->b_blocknr*(bh[i]->b_size >> 9); +#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) + major = MAJOR(bh[i]->b_dev); + if ( major == LVM_BLK_MAJOR) { + int ret; + + if ( lvm_map_ptr == NULL) { + printk ( KERN_ERR + "Bad lvm_map_ptr in ll_rw_block\n"); + goto sorry; + } + if ( ( ret = ( lvm_map_ptr) ( MINOR ( bh[i]->b_dev), + &bh[i]->b_rdev, + &bh[i]->b_rsector, + bh[i]->b_size >> 9, + rw)) != 0) { + printk ( KERN_ERR + "Bad lvm_map in ll_rw_block\n"); + goto sorry; + } + /* remap major too ... */ + major = MAJOR(bh[i]->b_rdev); + } +#endif #ifdef CONFIG_BLK_DEV_MD if (major==MD_MAJOR && - md_map (MINOR(bh[i]->b_dev), &bh[i]->b_rdev, - &bh[i]->b_rsector, bh[i]->b_size >> 9)) { - printk (KERN_ERR + /* changed v to allow LVM to remap */ + md_map (bh[i]->b_rdev, &bh[i]->b_rdev, + &bh[i]->b_rsector, bh[i]->b_size >> 9)) { + printk (KERN_ERR "Bad md_map in ll_rw_block\n"); - goto sorry; + goto sorry; } #endif } @@ -632,8 +739,10 @@ if (bh[i]) { set_bit(BH_Req, &bh[i]->b_state); #ifdef CONFIG_BLK_DEV_MD - if (MAJOR(bh[i]->b_dev) == MD_MAJOR) { - md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]); + /* changed v to allow LVM to remap */ + if (MAJOR(bh[i]->b_rdev) == MD_MAJOR) { + /* changed for LVM to remap v */ + md_make_request(bh[i], rw); continue; } #endif @@ -716,10 +825,10 @@ for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) { dev->request_fn = NULL; - dev->queue = NULL; + dev->queue = NULL; dev->current_request = NULL; dev->plug.rq_status = RQ_INACTIVE; - dev->plug.cmd = -1; + dev->plug.cmd = -1; dev->plug.next = NULL; dev->plug_tq.sync = 0; dev->plug_tq.routine = &unplug_device; @@ -800,7 +909,7 @@ sbpcd_init(); #endif CONFIG_SBPCD #ifdef CONFIG_AZTCD - aztcd_init(); + aztcd_init(); #endif CONFIG_AZTCD #ifdef CONFIG_CDU535 sony535_init(); @@ -817,6 +926,9 @@ #ifdef CONFIG_SJCD sjcd_init(); #endif CONFIG_SJCD +#ifdef CONFIG_BLK_DEV_LVM + lvm_init(); +#endif #ifdef CONFIG_BLK_DEV_MD md_init(); #endif CONFIG_BLK_DEV_MD diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/loop.c linux.ac/drivers/block/loop.c --- linux.vanilla/drivers/block/loop.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/block/loop.c Wed Jul 7 07:04:23 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/lvm.c linux.ac/drivers/block/lvm.c --- linux.vanilla/drivers/block/lvm.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/lvm.c Mon Jul 5 18:05:40 1999 @@ -0,0 +1,1997 @@ +/* + * kernel/lvm.c + * + * Copyright (C) 1997 - 1999 Heinz Mauelshagen, Germany + * + * February-November 1997 + * April-May,July-August,November 1998 + * January,February 1999 + * + * Changes : + * Marcelo Tosatti + * #ifdef minor fixes + * + * + * LVM driver 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. + * + * LVM driver 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT + * and VG_STATUS_GET_NAMELIST + * 18/01/1998 - change lvm_chr_open/close lock handling + * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and + * - added LV_STATUS_BYINDEX ioctl + * - used lvm_status_byname_req_t and + * lvm_status_byindex_req_t vars + * 04/05/1998 - added multiple device support + * 08/05/1998 - added support to set/clear extendable flag in volume group + * 09/05/1998 - changed output of lvm_proc_get_info() because of + * support for free (eg. longer) logical volume names + * 12/05/1998 - added spin_locks (thanks to Pascal van Dam + * ) + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 26/05/1998 - reactivated verify_area by access_ok + * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go + * beyond 128/256 KB max allocation limit per call + * - #ifdef blocked spin_lock calls to avoid compile errors + * with 2.0.x + * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open() + * and use of LVM_VERSION_CODE instead of my own macros + * (thanks to Michael Marxmeier ) + * 07/07/1998 - added statistics in lvm_map() + * 08/07/1998 - saved statistics in do_lv_extend_reduce() + * 25/07/1998 - used __initfunc macro + * 02/08/1998 - changes for official char/block major numbers + * 07/08/1998 - avoided init_module() and cleanup_module() to be static + * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters + * to sum of LVs open (no matter how often each is) + * 01/09/1998 - fixed lvm_gendisk.part[] index error + * 07/09/1998 - added copying of lv_current_pe-array + * in LV_STATUS_BYINDEX ioctl + * 17/11/1998 - added KERN_* levels to printk + * 13/01/1999 - fixed LV index bug in do_lv_create() which hit lvrename + * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET + * by moving spinlock code from lvm_chr_open() + * to lvm_chr_ioctl() + * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl() + * - allowed LVM_RESET and retrieval commands to go ahead; + * only other update ioctls are blocked now + * - fixed pv->pe to NULL for pv_status + * - using lv_req structure in lvm_chr_ioctl() now + * - fixed NULL ptr reference bug in do_lv_extend_reduce() + * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) + * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_char_ioctl() to + * handle lgoical volume private read ahead sector + * - implemented LV read_ahead handling with lvm_blk_read() + * and lvm_blk_write() + * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name() + * to be used in drivers/block/genhd.c by disk_name() + * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO + * - enhanced gendisk insert/remove handling + * 16/02/1999 - changed to dynamic block minor number allocation to + * have as much as 99 volume groups with 256 logical volumes + * as the grand total; this allows having 1 volume group with + * up to 256 logical volumes in it + * 21/02/1999 - added LV open count information to proc filesystem + * - substituted redundant LVM_RESET code by calls + * to do_vg_remove() + * 22/02/1999 - used schedule_timeout() to be more responsive + * in case of do_vg_remove() with lots of logical volumes + * + */ + +/* + * TODO + * + * - implement special handling of unavailable physical volumes + * - implement RAID1/5,10/50 + * + */ + +char *lvm_version = "LVM version 0.6 by Heinz Mauelshagen (26/02/1999)\n"; +char *lvm_short_version = "version 0.6 (26/02/1999)"; + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define LVM_CORRECT_READ_AHEAD( a) \ + if ( a < LVM_MIN_READ_AHEAD || \ + a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; + +#define suser() ( current->uid == 0 && current->euid == 0) + + +/* + * External function prototypes + */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#else +extern int lvm_init(void); +#endif + +static void lvm_dummy_device_request(void); +static int lvm_blk_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); +static int lvm_blk_open(struct inode *, struct file *); + +static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *); +static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *); + +static int lvm_chr_open(struct inode *, struct file *); + +static int lvm_chr_close(struct inode *, struct file *); +static int lvm_blk_close(struct inode *, struct file *); + +static int lvm_chr_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); + +#if defined(CONFIG_LVM_PROC_FS) && defined(CONFIG_PROC_FS) +static int lvm_proc_get_info(char *, char **, off_t, int, int); +#endif + +void lvm_hd_name(char *, struct gendisk *, int); + +/* End external function prototypes */ + +/* + * Internal function prototypes + */ +static void lvm_init_vars(void); +extern int (*lvm_map_ptr) (int, kdev_t *, unsigned long *, + unsigned long, int); +static int lvm_map(int, kdev_t *, unsigned long *, unsigned long, int); +static int do_vg_create(int, void *); +static int do_vg_remove(int); +static int do_lv_create(int, char *, lv_t *, struct inode *); +static int do_lv_remove(int, char *); +static int do_lv_extend_reduce(int, char *, lv_t *, struct inode *); +static void lvm_geninit(struct gendisk *); +static struct inode *lvm_get_inode(int); +inline int lvm_strlen(char *); +inline void lvm_memcpy(char *, char *, int); +inline int lvm_strcmp(char *, char *); +inline char *lvm_strrchr(char *, char c); +/* END Internal function prototypes */ + + +/* volume group descriptor area pointers */ +static vg_t *vg[ABS_MAX_VG + 1]; +static pv_t *pvp = NULL; +static lv_t *lvp = NULL; +static pe_t *pep = NULL; +static pe_t *pep1 = NULL; + +/* map from block minor number to VG and LV numbers */ +typedef struct { + int vg_number; + int lv_number; +} vg_lv_map_t; +static vg_lv_map_t vg_lv_map[ABS_MAX_LV]; + +/* Request structures (lvm_chr_ioctl()) */ +static pv_change_req_t pv_change_req; +static pv_flush_req_t pv_flush_req; +static pv_status_req_t pv_status_req; +static pe_lock_req_t pe_lock_req; +static le_remap_req_t le_remap_req; +static lv_req_t lv_req; + +#ifdef LVM_TOTAL_RESET +static int lvm_reset_spindown = 0; +#endif + +static char pv_name[NAME_LEN]; +static uint lv_open = 0; +static const char *const lvm_name = LVM_NAME; +static int lock = 0; +static int loadtime = 0; +static uint vg_count = 0; +static long lvm_chr_open_count = 0; +static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; +struct wait_queue *lvm_wait = NULL; +struct wait_queue *lvm_map_wait = NULL; + +#if defined(CONFIG_LVM_PROC_FS) && defined(CONFIG_PROC_FS) + +static struct proc_dir_entry lvm_proc_entry = +{ + 0, 3, LVM_NAME, S_IFREG | S_IRUGO, + 1, 0, 0, 0, + NULL, + lvm_proc_get_info, + NULL, NULL, NULL, NULL, NULL, +}; +#endif + +static struct file_operations lvm_chr_fops = +{ + NULL, /* No lseek */ + NULL, /* No read */ + NULL, /* No write */ + NULL, /* No readdir */ + NULL, /* No select */ + lvm_chr_ioctl, + NULL, /* No mmap */ + lvm_chr_open, + NULL, /* No flush */ + lvm_chr_close, + NULL, /* No fsync */ + NULL, /* No fasync */ + NULL, /* No check_media_change */ + NULL, /* No revalidate */ + NULL, /* No lock */ +}; + +static struct file_operations lvm_blk_fops = +{ + NULL, /* No lseek */ + lvm_blk_read, /* read */ + lvm_blk_write, /* write */ + NULL, /* No readdir */ + NULL, /* No select */ + lvm_blk_ioctl, + NULL, /* No mmap */ + lvm_blk_open, + NULL, /* No flush */ + lvm_blk_close, + block_fsync, /* fsync */ + NULL, /* No fasync */ + NULL, /* No check_media_change */ + NULL, /* No revalidate */ + NULL /* No lock */ +}; + + +/* gendisk structures */ +static struct hd_struct lvm_hd_struct[MAX_LV]; +static int lvm_blocksizes[MAX_LV] = +{0,}; +static int lvm_size[MAX_LV] = +{0,}; + +static struct gendisk lvm_gendisk = +{ + LVM_BLOCK_MAJOR, /* major # */ + LVM_NAME, /* name of major */ + 0, /* number of times minor is shifted + to get real minor */ + 1, /* maximum partitions per device */ + MAX_LV, /* maximum number of real devices */ + lvm_geninit, /* initialization called before we + do other things */ + lvm_hd_struct, /* partition table */ + lvm_size, /* device size in blocks, copied + to block_size[] */ + MAX_LV, /* number or real devices */ + NULL, /* internal */ + NULL, /* pointer to next gendisk struct (internal) */ +}; + + +#ifdef MODULE +/* + * Module initialization... + */ +int __init init_module(void) +#else +/* + * Driver initialization... + */ +int __init lvm_init(void) +#endif /* #ifdef MODULE */ +{ + struct gendisk *gendisk_ptr = NULL; + + lvm_init_vars(); + + if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { + printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); + return -EIO; + } + if (register_blkdev(LVM_BLOCK_MAJOR, lvm_name, &lvm_blk_fops) < 0) { + printk("%s -- register_blkdev failed\n", lvm_name); + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + return -EIO; + } + +#if defined(CONFIG_LVM_PROC_FS) && defined(CONFIG_PROC_FS) + proc_register(&proc_root, &lvm_proc_entry); +#endif + +#ifdef DEBUG + printk(KERN_INFO "%s -- registered\n", lvm_name); +#endif + + blk_dev[LVM_BLOCK_MAJOR].request_fn = lvm_dummy_device_request; + blk_dev[LVM_BLOCK_MAJOR].current_request = NULL; + + /* insert our gendisk at the corresponding major */ + lvm_geninit(&lvm_gendisk); + gendisk_ptr = gendisk_head; + while (gendisk_ptr->next != NULL && gendisk_ptr->major > lvm_gendisk.major) + gendisk_ptr = gendisk_ptr->next; + lvm_gendisk.next = gendisk_ptr->next; + gendisk_ptr->next = &lvm_gendisk; + + /* reference from ll_rw_blk */ + lvm_map_ptr = lvm_map; + + printk(KERN_INFO + "%s%s -- " +#ifdef MODULE + "Module" +#else + "Driver" +#endif + " successfully initialized\n", + lvm_version, lvm_name); + + return 0; +} /* init_module () / lvm_init () */ + + +#ifdef MODULE +/* + * Module cleanup... + */ +void cleanup_module(void) +{ + struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; + + gendisk_ptr = gendisk_ptr_prev = gendisk_head; + while (gendisk_ptr != &lvm_gendisk && gendisk_ptr != NULL) { + gendisk_ptr_prev = gendisk_ptr; + gendisk_ptr = gendisk_ptr->next; + } + /* delete our gendisk from chain */ + gendisk_ptr_prev->next = gendisk_ptr->next; + + blk_size[LVM_BLOCK_MAJOR] = NULL; + blksize_size[LVM_BLOCK_MAJOR] = NULL; + +#if defined(CONFIG_LVM_PROC_FS) && defined(CONFIG_PROC_FS) + proc_unregister(&proc_root, lvm_proc_entry.low_ino); +#endif + + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + } + if (unregister_blkdev(LVM_BLOCK_MAJOR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); + } + /* reference from linux/drivers/block/ll_rw_blk.c */ + lvm_map_ptr = NULL; + + blk_dev[LVM_BLOCK_MAJOR].request_fn = NULL; + blk_dev[LVM_BLOCK_MAJOR].current_request = NULL; + + printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); + + return; +} /* void cleanup_module () */ +#endif /* #ifdef MODULE */ + + +/* + * support function to initialize lvm variables + */ +static void __init lvm_init_vars(void) +{ + int v; + + loadtime = CURRENT_TIME; + + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = \ + pe_lock_req.data.pv_dev = \ + pe_lock_req.data.pv_offset = 0; + + /* Initialize VG pointers */ + for (v = 0; v <= ABS_MAX_VG; v++) + vg[v] = NULL; + + /* Initialize LV -> VG association */ + for (v = 0; v < ABS_MAX_LV; v++) { + /* index ABS_MAX_VG never used for real VG */ + vg_lv_map[v].vg_number = ABS_MAX_VG; + vg_lv_map[v].lv_number = -1; + } + + return; +} /* lvm_init_vars () */ + + +/******************************************************************** + * + * Character device functions + * + ********************************************************************/ + +/* + * character device open routine + */ +static int lvm_chr_open(struct inode *inode, struct file *file) { + int minor = MINOR(inode->i_rdev); + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", + lvm_name, minor, VG_CHR(minor), file->f_mode, lock); +#endif + + /* super user validation */ + if (!suser()) + return -EACCES; + + /* Group special file open */ + if (VG_CHR(minor) > MAX_VG) + return -ENXIO; + + MOD_INC_USE_COUNT; + lvm_chr_open_count++; + return 0; +} /* lvm_chr_open () *//* + * character device i/o-control routine + * + * Only one changing process can ioctl at one time, others will block. + * + */ +static int lvm_chr_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) { + int minor = MINOR(inode->i_rdev); + int extendable; + ulong l, le, p, v; + ulong size; + void *arg = (void *) a; + lv_t lv; +#ifdef LVM_GET_INODE + struct inode *inode_sav; +#endif + lv_status_byname_req_t lv_status_byname_req; + lv_status_byindex_req_t lv_status_byindex_req; + spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " + "VG#: %d mode: 0x%X\n", + lvm_name, command, minor, VG_CHR(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EACCES; +#endif + + + /* Main command switch */ + switch (command) { + /* lock the LVM */ + case LVM_LOCK_LVM: + lock_try_again: + spin_lock(&lvm_lock); + if (lock != 0 && lock != current->pid) { +#ifdef DEBUG_IOCTL + printk(KERN_INFO "lvm_chr_ioctl: %s is locked by pid %d ...\n", + lvm_name, lock); +#endif + spin_unlock(&lvm_lock); + interruptible_sleep_on(&lvm_wait); + if (signal_pending(current)) + return -EINTR; +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EACCES; +#endif + goto lock_try_again; + } + lock = current->pid; + spin_unlock(&lvm_lock); + + return 0; + + + /* check lvm version to ensure driver/tools+lib interoperability */ + case LVM_GET_IOP_VERSION: + if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort))) + return -EFAULT; + return 0; + + + /* lock/unlock i/o to a physical extent to move it to another + physical volume (move's done in user space's pvmove) */ + case PE_LOCK_UNLOCK: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&pe_lock_req, arg, sizeof(pe_lock_req_t))) + return -EFAULT; + + switch (pe_lock_req.lock) { + case LOCK_PE: + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] != NULL && + pe_lock_req.data.pv_dev == vg[VG_CHR(minor)]->pv[p]->pv_dev) + break; + } + + if (p == vg[VG_CHR(minor)]->pv_max) + return -ENXIO; + pe_lock_req.lock = UNLOCK_PE; + fsync_dev(pe_lock_req.data.lv_dev); + pe_lock_req.lock = LOCK_PE; + break; + + case UNLOCK_PE: + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = 0; + pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.pv_offset = 0; + wake_up(&lvm_map_wait); + break; + + default: + return -EINVAL; + } + + return 0; + + + /* remap a logical extent (after moving the physical extent) */ + case LE_REMAP: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&le_remap_req, arg, sizeof(le_remap_req_t))) + return -EFAULT; + + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (vg[VG_CHR(minor)]->lv[l] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->lv[l]->lv_name, + le_remap_req.lv_name) == 0) { + for (le = 0; le < vg[VG_CHR(minor)]->lv[l]->lv_allocated_le; le++) { + if (vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev == le_remap_req.old_dev && + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].pe == le_remap_req.old_pe) { + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev = le_remap_req.new_dev; + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].pe = le_remap_req.new_pe; + return 0; + } + } + return -EINVAL; + } + } + return -ENXIO; + + /* create a VGDA */ + case VG_CREATE: + return do_vg_create(minor, arg); + + /* remove an inactive VGDA */ + case VG_REMOVE: + return do_vg_remove(minor); + + /* extend a volume group */ + case VG_EXTEND: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (vg[VG_CHR(minor)]->pv_cur < vg[VG_CHR(minor)]->pv_max) { + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] == NULL) { + if ((vg[VG_CHR(minor)]->pv[p] = vmalloc(sizeof(pv_t))) == NULL) { + printk(KERN_WARNING "%s -- VG_EXTEND: vmalloc error PV\n", lvm_name); + return -ENOMEM; + } + if (copy_from_user(vg[VG_CHR(minor)]->pv[p], arg, + sizeof(pv_t))) + return -EFAULT; + + vg[VG_CHR(minor)]->pv[p]->pv_status = PV_ACTIVE; + /* We don't need the PE list + in kernel space like LVs pe_t list */ + vg[VG_CHR(minor)]->pv[p]->pe = NULL; + vg[VG_CHR(minor)]->pv_cur++; + vg[VG_CHR(minor)]->pv_act++; + vg[VG_CHR(minor)]->pe_total += vg[VG_CHR(minor)]->pv[p]->pe_total; +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + vg[VG_CHR(minor)]->pv[p]->inode = lvm_get_inode(vg[VG_CHR(minor)]->pv[p]->pv_dev); +#endif + return 0; + } + } + } + return -EPERM; + + + /* reduce a volume group */ + case VG_REDUCE: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(pv_name, arg, sizeof(pv_name))) + return -EFAULT; + + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->pv[p]->pv_name, pv_name) == 0) { + if (vg[VG_CHR(minor)]->pv[p]->lv_cur > 0) + return -EPERM; + vg[VG_CHR(minor)]->pe_total -= vg[VG_CHR(minor)]->pv[p]->pe_total; + vg[VG_CHR(minor)]->pv_cur--; + vg[VG_CHR(minor)]->pv_act--; +#ifdef DEBUG_VFREE + printk(KERN_DEBUG + "%s -- vfree %d\n", lvm_name, __LINE__); +#endif +#ifdef LVM_GET_INODE + clear_inode(vg[VG_CHR(minor)]->pv[p]->inode); +#endif + vfree(vg[VG_CHR(minor)]->pv[p]); + /* Make PV pointer array contiguous */ + for (; p < vg[VG_CHR(minor)]->pv_max - 1; p++) + vg[VG_CHR(minor)]->pv[p] = vg[VG_CHR(minor)]->pv[p + 1]; + vg[VG_CHR(minor)]->pv[p + 1] = NULL; + return 0; + } + } + return -ENXIO; + + + /* set/clear extendability flag of volume group */ + case VG_SET_EXTENDABLE: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&extendable, arg, sizeof(extendable))) + return -EFAULT; + + if (extendable == VG_EXTENDABLE || extendable == ~VG_EXTENDABLE) { + if (extendable == VG_EXTENDABLE) + vg[VG_CHR(minor)]->vg_status |= VG_EXTENDABLE; + else + vg[VG_CHR(minor)]->vg_status &= ~VG_EXTENDABLE; + } else + return -EINVAL; + return 0; + + + /* get volume group data (only the vg_t struct) */ + case VG_STATUS: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_to_user(arg, vg[VG_CHR(minor)], sizeof(vg_t))) + return -EFAULT; + return 0; + + /* get volume group count */ + case VG_STATUS_GET_COUNT: + if (copy_to_user(arg, &vg_count, sizeof(vg_count))) + return -EFAULT; + return 0; + + + /* get volume group count */ + case VG_STATUS_GET_NAMELIST: + for (l = v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) + if (copy_to_user(arg + l++ * NAME_LEN, vg[v]->vg_name, NAME_LEN)) + return -EFAULT; + } + return 0; + + + /* create, remove, extend or reduce a logical volume */ + case LV_CREATE: + case LV_REMOVE: + case LV_EXTEND: + case LV_REDUCE: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&lv_req, arg, sizeof(lv_req))) + return -EFAULT; + + if (command != LV_REMOVE) { + if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t))) + return -EFAULT; + } + switch (command) { + case LV_CREATE: + return do_lv_create(minor, lv_req.lv_name, &lv, inode); + + case LV_REMOVE: + return do_lv_remove(minor, lv_req.lv_name); + + case LV_EXTEND: + case LV_REDUCE: + return do_lv_extend_reduce(minor, lv_req.lv_name, &lv, inode); + } + + + /* get status of a logical volume by name */ + case LV_STATUS_BYNAME: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&lv_status_byname_req, arg, + sizeof(lv_status_byname_req_t))) + return -EFAULT; + + if (lv_status_byname_req.lv == NULL) + return -EINVAL; + + if (copy_from_user(&lv, lv_status_byname_req.lv, sizeof(lv_t))) + return -EFAULT; + + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (vg[VG_CHR(minor)]->lv[l] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->lv[l]->lv_name, lv_status_byname_req.lv_name) == 0) { + if (copy_to_user(lv_status_byname_req.lv, vg[VG_CHR(minor)]->lv[l], sizeof(lv_t))) + return -EFAULT; + if (lv.lv_current_pe != NULL) { + size = vg[VG_CHR(minor)]->lv[l]->lv_allocated_le * sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, vg[VG_CHR(minor)]->lv[l]->lv_current_pe, size)) + return -EFAULT; + } + return 0; + } + } + return -ENXIO; + + /* get status of a logical volume by index */ + case LV_STATUS_BYINDEX: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&lv_status_byindex_req, arg, sizeof(lv_status_byindex_req))) + return -EFAULT; + + if ((lvp = lv_status_byindex_req.lv) == NULL) + return -EINVAL; + l = lv_status_byindex_req.lv_index; + if (vg[VG_CHR(minor)]->lv[l] == NULL) + return -ENXIO; + + if (copy_from_user(&lv, lvp, sizeof(lv_t))) + return -EFAULT; + if (copy_to_user(lvp, vg[VG_CHR(minor)]->lv[l], sizeof(lv_t))) + return -EFAULT; + + if (lv.lv_current_pe != NULL) { + size = vg[VG_CHR(minor)]->lv[l]->lv_allocated_le * sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, vg[VG_CHR(minor)]->lv[l]->lv_current_pe, size)) + return -EFAULT; + } + return 0; + + + /* change a physical volume */ + case PV_CHANGE: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&pv_change_req, arg, sizeof(pv_change_req))) + return -EFAULT; + + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->pv[p]->pv_name, + pv_change_req.pv_name) == 0) { +#ifdef LVM_GET_INODE + inode_sav = vg[VG_CHR(minor)]->pv[p]->inode; +#endif + copy_from_user(vg[VG_CHR(minor)]->pv[p], pv_change_req.pv, sizeof(pv_t)); + /* We don't need the PE list + in kernel space as with LVs pe_t list */ + vg[VG_CHR(minor)]->pv[p]->pe = NULL; +#ifdef LVM_GET_INODE + vg[VG_CHR(minor)]->pv[p]->inode = inode_sav; +#endif + return 0; + } + } + return -ENXIO; + + + /* get physical volume data (pv_t structure only) */ + case PV_STATUS: + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; + if (copy_from_user(&pv_status_req, arg, sizeof(pv_status_req))) + return -EFAULT; + + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] != NULL) { + if (lvm_strcmp(vg[VG_CHR(minor)]->pv[p]->pv_name, pv_status_req.pv_name) == 0) { + if (copy_to_user(pv_status_req.pv, vg[VG_CHR(minor)]->pv[p], sizeof(pv_t))) + return -EFAULT; + return 0; + } + } + } + return -ENXIO; + + + /* physical volume buffer flush/invalidate */ + case PV_FLUSH: + if (copy_from_user(&pv_flush_req, arg, sizeof(pv_flush_req))) + return -EFAULT; + + for (v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] == NULL) + continue; + for (p = 0; p < vg[v]->pv_max; p++) { + if (vg[v]->pv[p] != NULL && lvm_strcmp(vg[v]->pv[p]->pv_name, pv_flush_req.pv_name) == 0) { + fsync_dev(vg[v]->pv[p]->pv_dev); + invalidate_buffers(vg[v]->pv[p]->pv_dev); + return 0; + } + } + } + return 0; + + default: + return -EINVAL; + } + return 0; +} /* lvm_chr_ioctl */ + + +/* + * character device close routine + */ + +static int lvm_chr_close(struct inode *inode, struct file *file) { +#ifdef DEBUG + int minor = MINOR(inode->i_rdev); + printk(KERN_DEBUG + "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor)); +#endif + + MOD_DEC_USE_COUNT; + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) { + lvm_reset_spindown = 0; + lvm_chr_open_count = 1; + } +#endif /* if (lvm_chr_open_count > 0) */ lvm_chr_open_count--; + if (lock == current->pid) { + lock = 0; /* release lock */ + wake_up_interruptible(&lvm_wait); + } + return 0; +} /* lvm_chr_close () */ + + + +/******************************************************************** + * + * Block device functions + * + ********************************************************************/ + +/* + * block device open routine + */ +static int lvm_blk_open(struct inode *inode, struct file *file) { + int minor = MINOR(inode->i_rdev); + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EPERM; +#endif + + if (vg[VG_BLK(minor)] != NULL && + (vg[VG_BLK(minor)]->vg_status & VG_ACTIVE) && + vg[VG_BLK(minor)]->lv[LV_BLK(minor)] != NULL && + LV_BLK(minor) >= 0 && + LV_BLK(minor) < vg[VG_BLK(minor)]->lv_max) { + /* Check parallel LV spindown (LV remove) */ + if (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_status & LV_SPINDOWN) + return -EPERM; + + /* Check inactive LV and open for read/write */ + if (file->f_mode & O_RDWR) { + if (!(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_status & LV_ACTIVE)) + return -EPERM; + if (!(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_access & LV_WRITE)) + return -EACCES; + } + if (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_open == 0) + vg[VG_BLK(minor)]->lv_open++; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_open++; + MOD_INC_USE_COUNT; + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_size); +#endif + + return 0; + } + return -ENXIO; +} /* lvm_blk_open () */ + + +/* + * block device read + */ +static ssize_t lvm_blk_read(struct file *file, char *buffer, + size_t size, loff_t * offset) { + int major = MAJOR(file->f_dentry->d_inode->i_rdev); + int minor = MINOR(file->f_dentry->d_inode->i_rdev); + + read_ahead[major] = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; + return block_read(file, buffer, size, offset); +} /* + * block device write + */ +static ssize_t lvm_blk_write(struct file *file, const char *buffer, + size_t size, loff_t * offset) { + int major = MAJOR(file->f_dentry->d_inode->i_rdev); + int minor = MINOR(file->f_dentry->d_inode->i_rdev); + + read_ahead[major] = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; + return block_write(file, buffer, size, offset); +} /* + * block device i/o-control routine + */ +static int lvm_blk_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) { + int minor = MINOR(inode->i_rdev); + void *arg = (void *) a; + struct hd_geometry *hd = (struct hd_geometry *) a; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " + "VG#:%dl LV#: %d\n", + lvm_name, minor, command, (ulong) arg, + VG_BLK(minor), LV_BLK(minor)); +#endif + + switch (command) { + /* return device size */ + case BLKGETSIZE: + if (copy_to_user((long *) arg, &vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_size, + sizeof(vg[VG_BLK(minor)]-> \ + lv[LV_BLK(minor)]->lv_size))) + return -EFAULT; + break; + + + /* flush buffer cache */ + case BLKFLSBUF: + fsync_dev(inode->i_rdev); + break; + + /* set read ahead for block device */ + case BLKRASET: + if (!suser()) + return -EACCES; + if ((long) arg < LVM_MIN_READ_AHEAD || + (long) arg > LVM_MAX_READ_AHEAD) + return -EINVAL; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead = (long) arg; + break; + + /* get current read ahead setting */ + case BLKRAGET: + if (copy_to_user((long *) arg, + &vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead, + sizeof(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead))) + return -EFAULT; + break; + + /* get disk geometry */ + case HDIO_GETGEO: + if (hd == NULL) + return -EINVAL; + { + unsigned char heads = 64; + unsigned char sectors = 32; + long start = 0; + short cylinders = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_size / + heads / sectors; + + copy_to_user((char *) &hd->heads, &heads, sizeof(heads)); + copy_to_user((char *) &hd->sectors, §ors, sizeof(sectors)); + copy_to_user((short *) &hd->cylinders, &cylinders, sizeof(cylinders)); + copy_to_user((long *) &hd->start, &start, sizeof(start)); + } + break; + + + /* set access flags of a logical volume */ + case LV_SET_ACCESS: + if (!suser()) + return -EACCES; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_access = (ulong) arg; + break; + + /* set status flags of a logical volume */ + case LV_SET_STATUS: + if (!suser()) + return -EACCES; + if (!((ulong) arg & LV_ACTIVE) && vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_open > 1) + return -EPERM; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_status = (ulong) arg; + break; + + + /* set allocation flags of a logical volume */ + case LV_SET_ALLOCATION: + if (!suser()) + return -EACCES; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_allocation = (ulong) arg; + break; + + + default: + printk(KERN_WARNING + "%s -- lvm_blk_ioctl: unknown command %d\n", + lvm_name, command); + return -EINVAL; + } + + return 0; +} /* lvm_blk_ioctl () */ + + +/* + * block device close routine + */ +static int lvm_blk_close(struct inode *inode, struct file *file) { + int minor = MINOR(inode->i_rdev); + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor)); +#endif + + sync_dev(inode->i_rdev); + if (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_open == 1) + vg[VG_BLK(minor)]->lv_open--; + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_open--; + + MOD_DEC_USE_COUNT; + + return 0; +} /* lvm_blk_close () */ +#if defined(CONFIG_LVM_PROC_FS) && defined(CONFIG_PROC_FS) /* + * Support function /proc-Filesystem + */ +#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) + +static int lvm_proc_get_info(char *page, char **start, off_t pos, int count, int whence) { + int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, lv_open_total, pe_t_bytes, seconds; + static off_t sz; + off_t sz_last; + char allocation_flag, inactive_flag, rw_flag, stripes_flag; + char *lv_name = NULL; + static char *buf = NULL; + static char dummy_buf[160]; /* sized for 2 lines */ + +#ifdef DEBUG_LVM_PROC_GET_INFO + printk(KERN_DEBUG + "%s - lvm_proc_get_info CALLED pos: %lu count: %d whence: %d\n", + lvm_name, pos, count, whence); +#endif + if (pos == 0 || buf == NULL) { + sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = lv_open_total = pe_t_bytes = 0; + /* search for activity */ + for (v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) { + vg_counter++; + pv_counter += vg[v]->pv_cur; + lv_counter += vg[v]->lv_cur; + if (vg[v]->lv_cur > 0) { + for (l = 0; l < vg[v]->lv_max; l++) { + if (vg[v]->lv[l] != NULL) { + pe_t_bytes += vg[v]->lv[l]->lv_allocated_le; + if (vg[v]->lv[l]->lv_open > 0) { + lv_open_counter++; + lv_open_total += vg[v]->lv[l]->lv_open; + } + } + } + } + } + } + pe_t_bytes *= sizeof(pe_t); + + if (buf != NULL) { +#ifdef DEBUG_VFREE + printk(KERN_DEBUG + "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(buf); + buf = NULL; + } + /* 2 times: first to get size to allocate buffer, + 2nd to fill the vmalloced buffer */ + for (i = 0; i < 2; i++) { + sz = 0; + sz += sprintf(LVM_PROC_BUF, "LVM " +#ifdef MODULE + "module" +#else + "driver" +#endif + " %s\n\n" + "Total: %d VG%s %d PV%s %d LV%s ", + lvm_short_version, + vg_counter, vg_counter == 1 ? "" : "s", + pv_counter, pv_counter == 1 ? "" : "s", + lv_counter, lv_counter == 1 ? "" : "s"); + sz += sprintf(LVM_PROC_BUF, + "(%d LV%s open", + lv_open_counter, + lv_open_counter == 1 ? "" : "s"); + if (lv_open_total > 0) + sz += sprintf(LVM_PROC_BUF, + " %d times)\n", + lv_open_total); + else + sz += sprintf(LVM_PROC_BUF, ")"); + + sz += sprintf(LVM_PROC_BUF, + "\nGlobal: %lu bytes vmalloced IOP version: %d ", + vg_counter * sizeof(vg_t) + + pv_counter * sizeof(pv_t) + + lv_counter * sizeof(lv_t) + + pe_t_bytes + sz_last, + lvm_iop_version); + + seconds = CURRENT_TIME - loadtime; + if (seconds < 0) + loadtime = CURRENT_TIME + seconds; + if (seconds / 86400 > 0) { + sz += sprintf(LVM_PROC_BUF, "%d day%s ", + seconds / 86400, + seconds / 86400 == 0 || + seconds / 86400 > 1 ? "s" : ""); + } + sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", + (seconds % 86400) / 3600, + (seconds % 3600) / 60, + seconds % 60); + + if (vg_counter > 0) { + for (v = 0; v < ABS_MAX_VG; v++) { + /* volume group */ + if (vg[v] != NULL) { + inactive_flag = ' '; + if (!(vg[v]->vg_status & VG_ACTIVE)) + inactive_flag = 'I'; + sz += sprintf(LVM_PROC_BUF, + "\nVG: %c%s [%d PV, %d LV/%d open] " + " PE Size: %d KB\n" + " Usage [KB/PE]: %d /%d total " + "%d /%d used %d /%d free", + inactive_flag, + vg[v]->vg_name, + vg[v]->pv_cur, + vg[v]->lv_cur, + vg[v]->lv_open, + vg[v]->pe_size >> 1, + vg[v]->pe_size * vg[v]->pe_total >> 1, + vg[v]->pe_total, + vg[v]->pe_allocated * vg[v]->pe_size >> 1, + vg[v]->pe_allocated, + (vg[v]->pe_total - vg[v]->pe_allocated) * + vg[v]->pe_size >> 1, + vg[v]->pe_total - vg[v]->pe_allocated); + + /* physical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n PV%s ", + vg[v]->pv_cur == 1 ? ": " : "s:"); + c = 0; + for (p = 0; p < vg[v]->pv_max; p++) { + if (vg[v]->pv[p] != NULL) { + inactive_flag = 'A'; + if (!(vg[v]->pv[p]->pv_status & PV_ACTIVE)) + inactive_flag = 'I'; + allocation_flag = 'A'; + if (!(vg[v]->pv[p]->pv_allocatable & PV_ALLOCATABLE)) + allocation_flag = 'N'; + sz += sprintf(LVM_PROC_BUF, + "[%c%c] %-21s %8d /%-6d " + "%8d /%-6d %8d /%-6d", + inactive_flag, + allocation_flag, + vg[v]->pv[p]->pv_name, + vg[v]->pv[p]->pe_total * + vg[v]->pv[p]->pe_size >> 1, + vg[v]->pv[p]->pe_total, + vg[v]->pv[p]->pe_allocated * + vg[v]->pv[p]->pe_size >> 1, + vg[v]->pv[p]->pe_allocated, + (vg[v]->pv[p]->pe_total - + vg[v]->pv[p]->pe_allocated) * + vg[v]->pv[p]->pe_size >> 1, + vg[v]->pv[p]->pe_total - + vg[v]->pv[p]->pe_allocated); + c++; + if (c < vg[v]->pv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + + /* logical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n LV%s ", + vg[v]->lv_cur == 1 ? ": " : "s:"); + c = 0; + for (l = 0; l < vg[v]->lv_max; l++) { + if (vg[v]->lv[l] != NULL) { + inactive_flag = 'A'; + if (!(vg[v]->lv[l]->lv_status & LV_ACTIVE)) + inactive_flag = 'I'; + rw_flag = 'R'; + if (vg[v]->lv[l]->lv_access & LV_WRITE) + rw_flag = 'W'; + allocation_flag = 'D'; + if (vg[v]->lv[l]->lv_allocation & LV_CONTIGUOUS) + allocation_flag = 'C'; + stripes_flag = 'L'; + if (vg[v]->lv[l]->lv_stripes > 1) + stripes_flag = 'S'; + sz += sprintf(LVM_PROC_BUF, + "[%c%c%c%c", + inactive_flag, + rw_flag, + allocation_flag, + stripes_flag); + if (vg[v]->lv[l]->lv_stripes > 1) + sz += sprintf(LVM_PROC_BUF, "%-2d", + vg[v]->lv[l]->lv_stripes); + else + sz += sprintf(LVM_PROC_BUF, " "); + lv_name = lvm_strrchr(vg[v]->lv[l]->lv_name, '/'); + if (lv_name != NULL) + lv_name++; + else + lv_name = vg[v]->lv[l]->lv_name; + sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name); + if (lvm_strlen(lv_name) > 25) + sz += sprintf(LVM_PROC_BUF, + "\n "); + sz += sprintf(LVM_PROC_BUF, "%9d /%-6d ", + vg[v]->lv[l]->lv_size >> 1, + vg[v]->lv[l]->lv_size / vg[v]->pe_size); + + if (vg[v]->lv[l]->lv_open == 0) + sz += sprintf(LVM_PROC_BUF, "close"); + else + sz += sprintf(LVM_PROC_BUF, "%dx open", vg[v]->lv[l]->lv_open); + c++; + if (c < vg[v]->lv_cur) + sz += sprintf(LVM_PROC_BUF, "\n "); + } + } + if (vg[v]->lv_cur == 0) + sz += sprintf(LVM_PROC_BUF, "none"); + sz += sprintf(LVM_PROC_BUF, "\n"); + } + } + } + if (buf == NULL) { + if ((buf = vmalloc(sz)) == NULL) { + sz = 0; + return sprintf(page, "%s - vmalloc error at line %d\n", + lvm_name, __LINE__); + } + } + sz_last = sz; + } + } + if (pos > sz - 1) { + vfree(buf); + buf = NULL; + return -1; + } + *start = &buf[pos]; + + if (sz - pos < count) + return sz - pos; + else + return count; +} /* lvm_proc_get_info () */ +#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */ + + +/* + * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c + * (see init_module/lvm_init) + */ +static int lvm_map(int minor, kdev_t * rdev, + ulong * rsector, ulong size, int rw) { + ulong index; + ulong rsector_sav; + kdev_t rdev_sav; + + if (!(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_status & LV_ACTIVE)) { + printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", + lvm_name, vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_name); + return -1; + } + if (rw == WRITE && + !(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_access & LV_WRITE)) { + printk(KERN_CRIT + "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", + lvm_name, vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_name); + return -1; + } +#ifdef DEBUG_MAP_SIZE + if (size != 2) + printk(KERN_DEBUG + "%s - lvm_map minor:%d size:%lu ", lvm_name, minor, size); +#endif + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " + "size:%lu\n", + lvm_name, minor, + MAJOR(*rdev), + MINOR(*rdev), + *rsector, size); +#endif + + if (*rsector + size > vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_size) { + printk(KERN_ALERT + "%s - lvm_map *rsector: %lu + size: %lu too large for" + " %02d:%02d\n", lvm_name, *rsector, size, + VG_BLK(minor), LV_BLK(minor)); + return -1; + } + rsector_sav = *rsector; + rdev_sav = *rdev; + + lvm_second_remap: + + /* linear mapping */ + if (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes < 2) { + index = *rsector / vg[VG_BLK(minor)]->pe_size; /* get the index */ + *rsector = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].pe + + (*rsector % vg[VG_BLK(minor)]->pe_size); + *rdev = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].dev; +#ifdef DEBUG_MAP + printk(KERN_DEBUG "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", + index, vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].pe, + MAJOR(*rdev), MINOR(*rdev), *rsector); +#endif + + /* striped mapping */ + } else { + ulong stripe_index; + ulong stripe_length; + + stripe_length = vg[VG_BLK(minor)]->pe_size * vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes; + stripe_index = *rsector % stripe_length / vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripesize; + index = *rsector / stripe_length + (stripe_index % vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes) * + (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_allocated_le / + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes); + *rsector = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].pe + (*rsector % stripe_length) - + stripe_index % vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes * vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripesize - + stripe_index / vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes * (vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripes - 1) * + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_stripesize; + *rdev = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].dev; + } + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" + "stripe_length: %ld stripe_index: %ld\n", + index, vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].pe, MAJOR(*rdev), MINOR(*rdev), *rsector, stripe_length, stripe_index); +#endif + + /* handle physical extents on the move */ + if (pe_lock_req.lock == LOCK_PE) { + if (*rdev == pe_lock_req.data.pv_dev && + *rsector >= pe_lock_req.data.pv_offset && + *rsector < (pe_lock_req.data.pv_offset + vg[VG_BLK(minor)]->pe_size)) { + sleep_on(&lvm_map_wait); + *rsector = rsector_sav; + *rdev = rsector_sav; + goto lvm_second_remap; + } + } + /* statistic */ + if (rw == WRITE || rw == WRITEA) + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].writes++; + else + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_current_pe[index].reads++; + + return 0; +} /* lvm_map () */ + + +/* + * internal support functions + */ + +/* + * generate "hard disk" name + */ +void lvm_hd_name(char *buf, struct gendisk *gendisk, int minor) { + int len = 0; + + if (vg[VG_BLK(minor)] == NULL) + return; + if (vg[VG_BLK(minor)]->lv[LV_BLK(minor)] == NULL) + return; + len = lvm_strlen(vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_name) - 5; + lvm_memcpy(buf, &vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_name[5], len); + buf[len] = 0; + return; +} /* + * this one never should be called... + */ +static void lvm_dummy_device_request(void) { + printk(KERN_EMERG "%s -- oops, got lvm request?\n", lvm_name); + return; +} /* + * character device support function VGDA create + */ +int do_vg_create(int minor, void *arg) { + int error; + ulong l, p; + ulong size; + + if (vg[VG_CHR(minor)] != NULL) + return -EPERM; + + if ((vg[VG_CHR(minor)] = vmalloc(sizeof(vg_t))) == NULL) { + printk(KERN_CRIT "%s -- VG_CREATE: vmalloc error VG\n", lvm_name); + return -ENOMEM; + } + /* get the volume group structure */ if (copy_from_user(vg[VG_CHR(minor)], arg, sizeof(vg_t))) + return -EFAULT; + + /* we are not that active so far... */ + vg[VG_CHR(minor)]->vg_status &= ~VG_ACTIVE; + + error = FALSE; + if (vg[VG_CHR(minor)]->pv_max > ABS_MAX_PV) { + printk(KERN_WARNING "%s -- Can't activate VG: ABS_MAX_PV too small\n", lvm_name); + error = TRUE; + } + if (vg[VG_CHR(minor)]->lv_max > ABS_MAX_LV) { + printk(KERN_WARNING "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", lvm_name, vg[VG_CHR(minor)]->lv_max); + error = TRUE; + } + if (error == TRUE) { +#ifdef DEBUG_VFREE + printk(KERN_DEBUG + "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(vg[VG_CHR(minor)]); + vg[VG_CHR(minor)] = NULL; + return -EPERM; + } + /* get the physical volume structures */ + vg[VG_CHR(minor)]->pv_act = vg[VG_CHR(minor)]->pv_cur = 0; + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + /* user space address */ + if ((pvp = vg[VG_CHR(minor)]->pv[p]) != NULL) { + vg[VG_CHR(minor)]->pv[p] = vmalloc(sizeof(pv_t)); + if (vg[VG_CHR(minor)]->pv[p] == NULL) { + printk(KERN_CRIT "%s -- VG_CREATE: vmalloc error PV\n", lvm_name); + for (; p < vg[VG_CHR(minor)]->pv_max; p++) + vg[VG_CHR(minor)]->pv[p] = NULL; + do_vg_remove(minor); + return -ENOMEM; + } + if (copy_from_user(vg[VG_CHR(minor)]->pv[p], pvp, sizeof(pv_t))) + return -EFAULT; + /* We don't need the PE list + in kernel space as with LVs pe_t list (see below) */ + vg[VG_CHR(minor)]->pv[p]->pe = NULL; + vg[VG_CHR(minor)]->pv[p]->pv_status = PV_ACTIVE; + vg[VG_CHR(minor)]->pv_act++; + vg[VG_CHR(minor)]->pv_cur++; + +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + vg[VG_CHR(minor)]->pv[p]->inode = lvm_get_inode(vg[VG_CHR(minor)]->pv[p]->pv_dev); +#endif + } + } + + /* get the logical volume structures */ + vg[VG_CHR(minor)]->lv_cur = 0; + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + /* user space address */ + if ((lvp = vg[VG_CHR(minor)]->lv[l]) != NULL) { + if ((vg[VG_CHR(minor)]->lv[l] = vmalloc(sizeof(lv_t))) == NULL) { + printk(KERN_ERR "%s -- VG_CREATE: vmalloc error LV\n", lvm_name); + do_vg_remove(minor); + return -ENOMEM; + } + copy_from_user(vg[VG_CHR(minor)]->lv[l], lvp, sizeof(lv_t)); + vg[VG_CHR(minor)]->lv_cur++; + LVM_CORRECT_READ_AHEAD(vg[VG_CHR(minor)]->lv[l]->lv_read_ahead); + + if (vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].vg_number != ABS_MAX_VG) { + do_vg_remove(minor); + return -ENXIO; + } + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].nr_sects = vg[VG_CHR(minor)]->lv[l]->lv_size; + lvm_size[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)] = vg[VG_CHR(minor)]->lv[l]->lv_size >> 1; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].vg_number = vg[VG_CHR(minor)]->vg_number; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].lv_number = vg[VG_CHR(minor)]->lv[l]->lv_number; + +#ifdef DEBUG_VG_CREATE + printk(KERN_DEBUG + "%s -- VG_CREATE: lvm_size[%d]: %d\n", + lvm_name, + minor + l + 1, + lvm_size[minor + l + 1]); +#endif + + /* Get the lv_current_pe list for device mapping */ + /* user address */ + if ((pep = vg[VG_CHR(minor)]->lv[l]->lv_current_pe) != NULL) { + size = vg[VG_CHR(minor)]->lv[l]->lv_allocated_le * sizeof(pe_t); + if ((vg[VG_CHR(minor)]->lv[l]->lv_current_pe = vmalloc(size)) == NULL) { + printk(KERN_ERR "%s -- VG_CREATE: vmalloc error LV_CURRENT_PE\n", + lvm_name); + for (; l < ABS_MAX_LV + 1; l++) + vg[VG_CHR(minor)]->lv[l] = NULL; + do_vg_remove(minor); + return -ENOMEM; + } + copy_from_user(vg[VG_CHR(minor)]->lv[l]->lv_current_pe, pep, size); + } else { + do_vg_remove(minor); + return -ENXIO; + } + } + } + vg_count++; + + /* let's go active */ + vg[VG_CHR(minor)]->vg_status |= VG_ACTIVE; + + MOD_INC_USE_COUNT; + return 0; +} + + +/* + * character device support function VGDA remove + */ +static int do_vg_remove(int minor) { + int l, p; + + if (vg[VG_CHR(minor)] == NULL) + return -ENXIO; +#ifdef LVM_TOTAL_RESET + if (vg[VG_CHR(minor)]->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (vg[VG_CHR(minor)]->lv_open > 0) +#endif + return -EPERM; + + /* let's go inactive */ + vg[VG_CHR(minor)]->vg_status &= ~VG_ACTIVE; + + /* Free LVs */ + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (vg[VG_CHR(minor)]->lv[l] != NULL) { + do_lv_remove(minor, vg[VG_CHR(minor)]->lv[l]->lv_name); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + } /* Free PVs */ + for (p = 0; p < vg[VG_CHR(minor)]->pv_max; p++) { + if (vg[VG_CHR(minor)]->pv[p] != NULL) { +#ifdef DEBUG_VFREE + printk(KERN_DEBUG + "%s -- vfree %d\n", lvm_name, __LINE__); +#endif +#ifdef LVM_GET_INODE + clear_inode(vg[VG_CHR(minor)]->pv[p]->inode); +#endif + vfree(vg[VG_CHR(minor)]->pv[p]); + vg[VG_CHR(minor)]->pv[p] = NULL; + } + } + +#ifdef DEBUG_VFREE + printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(vg[VG_CHR(minor)]); + vg[VG_CHR(minor)] = NULL; + vg_count--; + + MOD_DEC_USE_COUNT; + return 0; +} /* do_vg_remove () */ + + +/* + * character device support function logical volume create + */ +static int do_lv_create(int minor, char *lv_name, lv_t * lv, + struct inode *inode) { + int l, le, l_new, p, size; + ulong lv_status_save; + + if ((pep = lv->lv_current_pe) == NULL) + return -EINVAL; + + l_new = -1; + /* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */ + if (vg[VG_CHR(minor)]->lv[lv->lv_number] == NULL) + l_new = lv->lv_number; + else { + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (lvm_strcmp(vg[VG_CHR(minor)]->lv[l]->lv_name, lv_name) == 0) + return -EEXIST; + if (vg[VG_CHR(minor)]->lv[l] == NULL) + if (l_new == -1) + l_new = l; + } + } + if (l_new == -1) + return -EPERM; + l = l_new; + + if ((vg[VG_CHR(minor)]->lv[l] = vmalloc(sizeof(lv_t))) == NULL) { + printk(KERN_ERR "%s -- LV_CREATE: vmalloc error LV\n", lvm_name); + return -ENOMEM; + } + /* copy preloaded LV */ + lvm_memcpy((char *) vg[VG_CHR(minor)]->lv[l], + (char *) lv, sizeof(lv_t)); + lv_status_save = vg[VG_CHR(minor)]->lv[l]->lv_status; + vg[VG_CHR(minor)]->lv[l]->lv_status &= ~LV_ACTIVE; + + /* get the PE structures from user space */ + size = vg[VG_CHR(minor)]->lv[l]->lv_allocated_le * sizeof(pe_t); + if ((vg[VG_CHR(minor)]->lv[l]->lv_current_pe = vmalloc(size)) == NULL) { + printk(KERN_CRIT "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte\n", lvm_name, size); +#ifdef DEBUG_VFREE + printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(vg[VG_CHR(minor)]->lv[l]); + vg[VG_CHR(minor)]->lv[l] = NULL; + return -ENOMEM; + } + copy_from_user(vg[VG_CHR(minor)]->lv[l]->lv_current_pe, pep, size); + vg[VG_CHR(minor)]->lv_cur++; + + /* correct the PE count in PVs */ + for (le = 0; le < vg[VG_CHR(minor)]->lv[l]->lv_allocated_le; le++) { + vg[VG_CHR(minor)]->pe_allocated++; + for (p = 0; p < vg[VG_CHR(minor)]->pv_cur; p++) { + if (vg[VG_CHR(minor)]->pv[p]->pv_dev == + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev) + vg[VG_CHR(minor)]->pv[p]->pe_allocated++; + } + } + + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].nr_sects = vg[VG_CHR(minor)]->lv[l]->lv_size; + lvm_size[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)] = vg[VG_CHR(minor)]->lv[l]->lv_size >> 1; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].vg_number = vg[VG_CHR(minor)]->vg_number; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].lv_number = vg[VG_CHR(minor)]->lv[l]->lv_number; + + vg[VG_CHR(minor)]->lv[l]->lv_status = lv_status_save; + LVM_CORRECT_READ_AHEAD(vg[VG_CHR(minor)]->lv[l]->lv_read_ahead); + + return 0; +} /* do_lv_create () */ + + +/* + * character device support function logical volume remove + */ +static int do_lv_remove(int minor, char *lv_name) { + uint l, le, p; + + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (vg[VG_CHR(minor)]->lv[l] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->lv[l]->lv_name, lv_name) == 0) { +#ifdef LVM_TOTAL_RESET + if (vg[VG_CHR(minor)]->lv[l]->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (vg[VG_CHR(minor)]->lv[l]->lv_open > 0) +#endif + return -EBUSY; +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- fsync_dev and " + "invalidate_buffers for %s [%s] in %s\n", + lvm_name, vg[VG_CHR(minor)]->lv[l]->lv_name, + kdevname(vg[VG_CHR(minor)]->lv[l]->lv_dev), + vg[VG_CHR(minor)]->vg_name); +#endif + vg[VG_CHR(minor)]->lv[l]->lv_status |= LV_SPINDOWN; + fsync_dev(vg[VG_CHR(minor)]->lv[l]->lv_dev); + vg[VG_CHR(minor)]->lv[l]->lv_status &= ~LV_ACTIVE; + invalidate_buffers(vg[VG_CHR(minor)]->lv[l]->lv_dev); + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].start_sect = \ + -1; + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].nr_sects = 0; + lvm_size[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)] = 0; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].vg_number = + ABS_MAX_VG; + vg_lv_map[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].lv_number = -1; + + for (le = 0; le < vg[VG_CHR(minor)]->lv[l]->lv_allocated_le; le++) { + vg[VG_CHR(minor)]->pe_allocated--; + for (p = 0; p < vg[VG_CHR(minor)]->pv_cur; p++) { + if (vg[VG_CHR(minor)]->pv[p]->pv_dev == + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev) + vg[VG_CHR(minor)]->pv[p]->pe_allocated--; + } + } +#ifdef DEBUG_VFREE + printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(vg[VG_CHR(minor)]->lv[l]->lv_current_pe); + +#ifdef DEBUG_VFREE + printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + vfree(vg[VG_CHR(minor)]->lv[l]); + vg[VG_CHR(minor)]->lv[l] = NULL; + vg[VG_CHR(minor)]->lv_cur--; + return 0; + } + } + return -ENXIO; +} /* do_lv_remove () */ + + +/* + * character device support function logical volume extend / reduce + */ +static int do_lv_extend_reduce(int minor, char *lv_name, lv_t * lv, + struct inode *inode) { + int l, le, p, size; + uint32_t end, lv_status_save; + pe_t *pe; + + if ((pep = lv->lv_current_pe) == NULL) + return -EINVAL; + + for (l = 0; l < vg[VG_CHR(minor)]->lv_max; l++) { + if (vg[VG_CHR(minor)]->lv[l] != NULL && + lvm_strcmp(vg[VG_CHR(minor)]->lv[l]->lv_name, lv_name) == 0) + break; + } + if (l == vg[VG_CHR(minor)]->lv_max) + return -ENXIO; + + if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) { + printk(KERN_CRIT + "%s -- do_lv_extend_reduce: vmalloc error LV_CURRENT_PE " + "of %d Byte\n", lvm_name, size); + return -ENOMEM; + } + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- fsync_dev and " + "invalidate_buffers for %s [%s] in %s\n", + lvm_name, vg[VG_CHR(minor)]->lv[l]->lv_name, + kdevname(vg[VG_CHR(minor)]->lv[l]->lv_dev), + vg[VG_CHR(minor)]->vg_name); +#endif + + vg[VG_CHR(minor)]->lv[l]->lv_status |= LV_SPINDOWN; + fsync_dev(vg[VG_CHR(minor)]->lv[l]->lv_dev); + vg[VG_CHR(minor)]->lv[l]->lv_status &= ~LV_ACTIVE; + invalidate_buffers(vg[VG_CHR(minor)]->lv[l]->lv_dev); + + /* reduce allocation counters on PV(s) */ + for (le = 0; le < vg[VG_CHR(minor)]->lv[l]->lv_allocated_le; le++) { + vg[VG_CHR(minor)]->pe_allocated--; + for (p = 0; p < vg[VG_CHR(minor)]->pv_cur; p++) { + if (vg[VG_CHR(minor)]->pv[p]->pv_dev == + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev) { + vg[VG_CHR(minor)]->pv[p]->pe_allocated--; + break; + } + } + } + +#ifdef DEBUG_VFREE + printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__); +#endif + + /* save pointer to "old" lv/pe pointer array */ + pep1 = vg[VG_CHR(minor)]->lv[l]->lv_current_pe; + end = vg[VG_CHR(minor)]->lv[l]->lv_current_le; + + lv_open = vg[VG_CHR(minor)]->lv[l]->lv_open; + + /* copy preloaded LV */ + lvm_memcpy((char *) vg[VG_CHR(minor)]->lv[l], (char *) lv, sizeof(lv_t)); + lv_status_save = vg[VG_CHR(minor)]->lv[l]->lv_status; + vg[VG_CHR(minor)]->lv[l]->lv_status |= LV_SPINDOWN; + vg[VG_CHR(minor)]->lv[l]->lv_status &= ~LV_ACTIVE; + vg[VG_CHR(minor)]->lv[l]->lv_current_pe = pe; + + /* get the PE structures from user space */ + copy_from_user(vg[VG_CHR(minor)]->lv[l]->lv_current_pe, pep, size); + + vg[VG_CHR(minor)]->lv[l]->lv_open = lv_open; + + /* Check what last LE shall be used */ + if (end > vg[VG_CHR(minor)]->lv[l]->lv_current_le) + end = vg[VG_CHR(minor)]->lv[l]->lv_current_le; + + /* save availiable i/o statistic data */ + for (le = 0; le < end; le++) { + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].reads = pep1[le].reads; + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].writes = pep1[le].writes; + } + vfree(pep1); + pep1 = NULL; + + + /* extend the PE count in PVs */ + for (le = 0; le < vg[VG_CHR(minor)]->lv[l]->lv_allocated_le; le++) { + vg[VG_CHR(minor)]->pe_allocated++; + for (p = 0; p < vg[VG_CHR(minor)]->pv_cur; p++) { + if (vg[VG_CHR(minor)]->pv[p]->pv_dev == + vg[VG_CHR(minor)]->lv[l]->lv_current_pe[le].dev) { + vg[VG_CHR(minor)]->pv[p]->pe_allocated++; + break; + } + } + } + + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)].nr_sects = + vg[VG_CHR(minor)]->lv[l]->lv_size; + lvm_size[MINOR(vg[VG_CHR(minor)]->lv[l]->lv_dev)] = + vg[VG_CHR(minor)]->lv[l]->lv_size >> 1; + /* vg_lv_map array doesn't have to be changed here */ + + vg[VG_CHR(minor)]->lv[l]->lv_status = lv_status_save; + LVM_CORRECT_READ_AHEAD(vg[VG_CHR(minor)]->lv[l]->lv_read_ahead); + + return 0; +} /* do_lv_extend_reduce () */ + + +/* + * support function initialize gendisk variables + */ + +static void __init lvm_geninit(struct gendisk *lvm_gdisk) { + int i = 0; + +#ifdef DEBUG_GENDISK + printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name); +#endif + + for (i = 0; i < MAX_LV; i++) { + lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */ + lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0; + lvm_blocksizes[i] = BLOCK_SIZE; + } + blksize_size[LVM_BLOCK_MAJOR] = lvm_blocksizes; + blk_size[LVM_BLOCK_MAJOR] = lvm_size; + + return; +} /* lvm_gen_init () */ + + +#ifdef LVM_GET_INODE +/* + * support function to get an empty inode + * + * Gets an empty inode to be inserted into the inode hash, + * so that a physical volume can't be mounted. + * This is analog to drivers/block/md.c + * + * Is this the real thing? + * + */ +struct inode *lvm_get_inode(int dev) { + struct inode *inode_this = NULL; + + /* Lock the device by inserting a dummy inode. */ + inode_this = get_empty_inode(); + inode_this->i_dev = dev; + insert_inode_hash(inode_this); + return inode_this; +} +#endif + +/* my strlen */ + +inline int lvm_strlen(char *s1) +{ + int len = 0; + + while (s1[len] != 0) + len++; + return len; +} + +/* my strcmp */ +inline int lvm_strcmp(char *s1, char *s2) { + while (*s1 != 0 && *s2 != 0) { + if (*s1 != *s2) + return -1; + s1++; + s2++; + } + if (*s1 == 0 && *s2 == 0) + return 0; + return -1; +} + + +/* my strrchr */ +inline char *lvm_strrchr(char *s1, char c) { + char *s2 = NULL; + + while (*s1 != 0) { + if (*s1 == c) + s2 = s1; + s1++; + } + return s2; +} + + +/* my memcpy */ +inline void lvm_memcpy(char *dest, char *source, int size) { + for (; size > 0; size--) + *dest++ = *source++; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/lvm_old.c linux.ac/drivers/block/lvm_old.c --- linux.vanilla/drivers/block/lvm_old.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/lvm_old.c Mon Jul 19 03:26:58 1999 @@ -0,0 +1,729 @@ + +/* + lvm.c : Logical Volume Manager for Linux + Copyright (C) 1998 Ingo Molnar + + LVM management functions. + + 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. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#define MAJOR_NR LVM_MAJOR +#define LVM_DRIVER + +#include + +lvdev_t lv_devs[MAX_LVM_DEV]; + +static LVM_LIST_HEAD(lvm_managed_devices); + +static lvm_rdisk_t * find_rdisk_all (kdev_t dev) +{ + struct lvm_list_head *tmp; + lvm_rdisk_t *rdisk; + + tmp = lvm_managed_devices.next; + while (tmp != &lvm_managed_devices) { + rdisk = lvm_list_entry(tmp, lvm_rdisk_t, lvm_managed); + if (rdisk->dev == dev) + return rdisk; + tmp = tmp->next; + } + return NULL; +} + +/* + * Prevent the device from being mounted or otherwise reused + * in the LVM (or any other kernel subsystem), by adding a + * dummy inode. + */ +static void lock_rdisk (lvm_rdisk_t *rdisk) +{ + /* + * Insert dummy inode to 'lock' the device + */ + rdisk->inode = get_empty_inode(); + /* + * we dont care about other fields + */ + rdisk->inode->i_dev = rdisk->dev; + insert_inode_hash(rdisk->inode); +} + +static void unlock_rdisk (lvm_rdisk_t *rdisk) +{ + clear_inode(rdisk->inode); +} + +#define NO_SB KERN_ERR \ +"lvm: skipping device %s, could not read superblock.\n" + +#define BAD_MAGIC KERN_ERR \ +"lvm: invalid LVM superblock magic on %s\n" + +#define OUT_OF_MEM KERN_ALERT \ +"lvm: out of memory.\n" + +#define BAD_CSUM KERN_WARNING \ +"lvm: invalid superblock checksum on %s\n" + +static int alloc_rdisk_sb (lvm_rdisk_t * rdisk) +{ + if (rdisk->sb) + LVM_BUG(); + + rdisk->sb = (lvm_super_t *) __get_free_page(GFP_KERNEL); + if (!rdisk->sb) { + printk (OUT_OF_MEM); + return -EINVAL; + } + lvm_clear_page((unsigned long)rdisk->sb); + + return 0; +} + +static void free_rdisk_sb (lvm_rdisk_t * rdisk) +{ + if (rdisk->sb) { + free_page((unsigned long) rdisk->sb); + rdisk->sb = NULL; + rdisk->size = 0; + } else { + if (!rdisk->faulty) + LVM_BUG(); + } +} + +static unsigned int calc_sb_csum (lvm_super_t * sb) +{ + unsigned int disk_csum, csum; + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + csum = csum_partial((void *)sb, LVM_SB_BYTES, 0); + sb->sb_csum = disk_csum; + return csum; +} + +/* + * Check one LVM superblock for generic plausibility + */ + +static int check_rdisk_sb (lvm_rdisk_t * rdisk) +{ + lvm_super_t *sb; + int ret = -EINVAL; + + sb = rdisk->sb; + if (!sb) { + LVM_BUG(); + goto abort; + } + + if (sb->lvm_magic != LVM_SB_MAGIC) { + printk (BAD_MAGIC, partition_name(rdisk->dev)); + goto abort; + } + + if (calc_sb_csum(sb) != sb->sb_csum) + printk(BAD_CSUM, partition_name(rdisk->dev)); + ret = 0; +abort: + return ret; +} + +static int read_rdisk_sb (lvm_rdisk_t * rdisk) +{ + int ret = -EINVAL; + struct buffer_head *bh = NULL; + kdev_t dev = rdisk->dev; + lvm_super_t *sb; + + if (!rdisk->sb) { + LVM_BUG(); + goto abort; + } + + /* + * Read the superblock, it's at the beginning of the disk + */ + set_blocksize (dev, LVM_SB_BYTES); + bh = bread (dev, 0, LVM_SB_BYTES); + + if (bh) { + sb = (lvm_super_t *) bh->b_data; + memcpy (rdisk->sb, sb, LVM_SB_BYTES); + } else { + printk (NO_SB,partition_name(rdisk->dev)); + goto abort; + } + ret = 0; +abort: + if (bh) + brelse (bh); + return ret; +} + +#undef BAD_CSUM +#undef BAD_MAGIC +#undef OUT_OF_MEM +#undef NO_SB + + +#define GETBLK_FAILED KERN_ERR \ +"lvm: getblk failed for device %s\n" + +static int write_rdisk_sb(lvm_rdisk_t * rdisk) +{ + struct buffer_head *bh; + kdev_t dev; + lvm_super_t *sb; + + if (!rdisk->sb) { + LVM_BUG(); + return -1; + } + if (rdisk->sb->lvm_magic != LVM_SB_MAGIC) { + LVM_BUG(); + return -1; + } + + dev = rdisk->dev; + + printk("(write) %s\n", partition_name(dev)); + set_blocksize(dev, LVM_SB_BYTES); + bh = getblk(dev, 0, LVM_SB_BYTES); + if (!bh) { + printk(GETBLK_FAILED, partition_name(dev)); + return 1; + } + memset(bh->b_data,0,bh->b_size); + sb = (lvm_super_t *) bh->b_data; + memcpy(sb, rdisk->sb, LVM_SB_BYTES); + + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 1); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + brelse(bh); + fsync_dev(dev); + return 0; +} +#undef GETBLK_FAILED KERN_ERR + +/* + * Import a device, sanity check the superblock + */ +static int lvm_import_device (kdev_t newdev) +{ + int err = 0; + lvm_rdisk_t *rdisk; + unsigned int size; + + if (find_rdisk_all(newdev)) + return -EEXIST; + + rdisk = (lvm_rdisk_t *) kmalloc(sizeof(*rdisk), GFP_KERNEL); + if (!rdisk) { + printk("could not alloc mem for %s!\n", partition_name(newdev)); + return -ENOMEM; + } + memset(rdisk, 0, sizeof(*rdisk)); + + if (!fs_may_mount(newdev)) { + printk("lvm: can not import %s, has active inodes!\n", + partition_name(newdev)); + err = -EBUSY; + goto abort_free; + } + + if ((err = alloc_rdisk_sb(rdisk))) + goto abort_free; + + rdisk->dev = newdev; + lock_rdisk(rdisk); + + size = blk_size[MAJOR(newdev)][MINOR(newdev)]; + if (!size) { + printk("lvm: %s has zero size, marking faulty!\n", + partition_name(newdev)); + rdisk->faulty = 1; + goto out_faulty; + } + + if ((err = read_rdisk_sb(rdisk))) { + printk("lvm: %s has zero size,marking faulty!\n", + partition_name(newdev)); + rdisk->faulty = 1; + goto out_faulty; + } + if ((err = check_rdisk_sb(rdisk))) { + printk("lvm: %s has invalid sb, skipping!\n", + partition_name(newdev)); + rdisk->faulty = 1; + goto out_faulty; + } + + rdisk->old_dev = MKDEV(rdisk->sb->this_major, + rdisk->sb->this_minor); + +out_faulty: + lvm_list_add(&rdisk->lvm_managed, &lvm_managed_devices); + if (rdisk->faulty && rdisk->sb) + free_rdisk_sb(rdisk); + return 0; + +abort_free: + kfree(rdisk); + return err; +} + +/* + * Searches all registered partitions for LVM devices + * at boot time. + */ +lvm__initfunc(void autodetect_lvm(void)) +{ + struct gendisk *disk; + int i; + + printk(KERN_INFO "autodetecting LVM devices\n"); + + for (disk = gendisk_head ; disk ; disk = disk->next) + for (i = 0; i < disk->max_p*disk->max_nr; i++) { + kdev_t dev = MKDEV(disk->major,i); + + if (disk->part[i].type == LINUX_LVM_PARTITION) { + printk(KERN_INFO "found raw LVM partition %s\n", + partition_name(dev)); + lvm_import_device(dev); + } + } +} + +static void do_lvm_request (void) +{ + printk(KERN_ALERT "Got LVM request, not good..."); + return; +} + +int lvm_size[MAX_LVM_DEV] = {0, }; +static struct hd_struct lvm_hd_struct[MAX_LVM_DEV]; +static int lvm_blocksizes[MAX_LVM_DEV]; +static int lvm_maxreadahead[MAX_LVM_DEV]; + +static void lvm_geninit (struct gendisk *); + +static struct gendisk lvm_gendisk= +{ + LVM_MAJOR, + "lvm", + 0, + 1, + MAX_LVM_DEV, + lvm_geninit, + lvm_hd_struct, + lvm_size, + MAX_LVM_DEV, + NULL, + NULL +}; + +static void lvm_geninit (struct gendisk *gdisk) +{ + int i; + + for(i = 0; i < MAX_LVM_DEV; i++) { + lvm_blocksizes[i] = 1024; + lvm_maxreadahead[i] = 128; + lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */ + lvm_gendisk.part[i].nr_sects = 0; + } + + blksize_size[LVM_MAJOR] = lvm_blocksizes; + lvm_set_global_readahead(lvm_maxreadahead); +} + +static int get_version (void * arg) +{ + lvm_version_t ver; + + ver.major = LVM_MAJOR_VERSION; + ver.minor = LVM_MINOR_VERSION; + ver.patchlevel = LVM_PATCHLEVEL_VERSION; + + if (md_copy_to_user(arg, &ver, sizeof(ver))) + return -EFAULT; + + return 0; +} + +static int lvm_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor; + int err = 0; + struct hd_geometry *loc = (struct hd_geometry *) arg; + + if (!lvm_capable_admin()) + return -EACCES; + + minor = MINOR(inode->i_rdev); + if (minor >= MAX_LVM_DEV) + return -EINVAL; + + switch (cmd) + { + case LVM_VERSION: + err = get_version((void *)arg); + break; + + case BLKGETSIZE: /* Return device size */ + if (!arg) { + err = -EINVAL; + break; + } + err = lvm_put_user(lvm_hd_struct[ + MINOR(inode->i_rdev)].nr_sects, (long *) arg); + break; + + case BLKFLSBUF: + fsync_dev (inode->i_rdev); + invalidate_buffers (inode->i_rdev); + break; + + case BLKRASET: + if (arg > 0xff) + err = -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + break; + + case BLKRAGET: + if (!arg) + err = -EINVAL; + err = lvm_put_user (read_ahead[ + MAJOR(inode->i_rdev)], (long *) arg); + break; + /* + * We have a problem here : there is no easy way to give a CHS + * virtual geometry. We currently pretend that we have a 2 heads + * 4 sectors (with a BIG number of cylinders...). This drives + * dosfs just mad... ;-) + */ + case HDIO_GETGEO: + if (!loc) { + err = -EINVAL; + break; + } + err = lvm_put_user (2, (char *) &loc->heads); + if (err) + break; + err = lvm_put_user (4, (char *) &loc->sectors); + if (err) + break; + err = lvm_put_user (lvm_hd_struct[minor].nr_sects/8, + (short *) &loc->cylinders); + if (err) + break; + err = lvm_put_user (lvm_hd_struct[MINOR(inode->i_rdev) + ].start_sect, (long *) &loc->start); + break; + + default: + printk(KERN_WARNING "%s(pid %d) used obsolete LVM ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); + err = -EINVAL; + } + return err; +} + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) + +static int lvm_open (struct inode *inode, struct file *file) +{ + /* + * Always succeed + */ + return (0); +} + +static void lvm_release (struct inode *inode, struct file *file) +{ + sync_dev(inode->i_rdev); +} + + +static int lvm_read (struct inode *inode, struct file *file, + char *buf, int count) +{ + if (!kdev_to_lvdev(LVM_FILE_TO_INODE(file)->i_rdev)->running) + return -ENXIO; + + return block_read (inode, file, buf, count); +} + +static int lvm_write (struct inode *inode, struct file *file, + const char *buf, int count) +{ + if (!kdev_to_lvdev(LVM_FILE_TO_INODE(file)->i_rdev)->running) + return -ENXIO; + + return block_write (inode, file, buf, count); +} + +static struct file_operations lvm_fops= +{ + NULL, + lvm_read, + lvm_write, + NULL, + NULL, + lvm_ioctl, + NULL, + lvm_open, + lvm_release, + block_fsync +}; + +#else + +static int lvm_open (struct inode *inode, struct file *file) +{ + /* + * Always succeed + */ + return (0); +} + +static int lvm_release (struct inode *inode, struct file *file) +{ + sync_dev(inode->i_rdev); + return 0; +} + +static ssize_t lvm_read (struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + if (!kdev_to_lvdev(LVM_FILE_TO_INODE(file)->i_rdev)->running) + return -ENXIO; + + return block_read(file, buf, count, ppos); +} + +static ssize_t lvm_write (struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + if (!kdev_to_lvdev(LVM_FILE_TO_INODE(file)->i_rdev)->running) + return -ENXIO; + + return block_write(file, buf, count, ppos); +} + +static struct file_operations lvm_fops= +{ + NULL, + lvm_read, + lvm_write, + NULL, + NULL, + lvm_ioctl, + NULL, + lvm_open, + NULL, + lvm_release, + block_fsync +}; + +#endif + +static void extend_index_space (lvdev_t *lv) +{ +#warning not yet +} + +static inline unsigned int __get_free_block (pvdev_t *pv) +{ + if (pv->first_free_block == pv->max_blocks) { + printk("lvm: pv %s full!\n", partition_name(pv->rdev->dev)); + return 0; + } + return pv->first_free_block++; +} + +static unsigned int get_free_block (lvdev_t *lv) +{ + unsigned int idx; + + while (!lv->free_indices) + extend_index_space(lv); + + idx = __get_free_block(&lv->pv); + if (!idx) + LVM_BUG(); + + return idx; +} + +static inline lvm_lptr_t * __get_free_index (lvdev_t *lv) +{ +#warning not yet + return 0; +} + +static lvm_lptr_t * get_free_index (lvdev_t *lv) +{ + lvm_lptr_t *index; + + if (!lv->free_indices) + extend_index_space(lv); + + index = __get_free_index(lv); + if (!index) + LVM_BUG(); + + return index; +} + + +static unsigned int index_to_idx (lvm_lptr_t *index) +{ +#warning not yet + return 0; +} + +static void bind_block_to_index (lvm_lptr_t *index, + unsigned int block, lvdev_t *lv) +{ + index->data.phys_block = block; +} + +unsigned int alloc_index (kdev_t dev) +{ + lvdev_t *lv = kdev_to_lvdev(dev); + lvm_lptr_t *index; + unsigned int block; + + index = get_free_index(lv); + if (!index) { + LVM_BUG(); + return 0; + } + block = get_free_block(lv); + bind_block_to_index(index,block,lv); + + return index_to_idx(index); +} + +#define INDEX_BITS 8 +#define INDEX_DEPTH (32/INDEX_BITS) +#define INDEX_MASK ((1<root_index; + unsigned int idx, l; + + for (l = 0; l < INDEX_DEPTH; l++) { + idx = lblock & INDEX_MASK; + index += idx; + index = (lvm_lptr_t *) (index->cpu_addr); + if (!index) { + return NULL; + } + lblock >>= INDEX_BITS; + } + return index; +} + +static int lvm_map (kdev_t dev, kdev_t *rdev, + unsigned long *rsector, int bsize_bits) +{ + lvdev_t *lv = kdev_to_lvdev(dev); + lvm_lptr_t *index; + unsigned int lblock = *rsector >> bsize_bits; + int err = -EIO; + + index = find_index(lv, lblock); + if (!index) { + printk("no block %u yet ...\n", lblock); + goto out; + } + + err = 0; +out: + return err; +} + +lvm__initfunc(void lvm_init(void)) +{ + printk (KERN_INFO "Logical Volume Manager for Linux %d.%d.%d\n", + LVM_MAJOR_VERSION, LVM_MINOR_VERSION, LVM_PATCHLEVEL_VERSION); + if (register_blkdev (LVM_MAJOR, "lvm", &lvm_fops)) + { + printk (KERN_ALERT "Unable to get LVM major %d\n", LVM_MAJOR); + return; + } + + blk_dev[LVM_MAJOR].request_fn = DEVICE_REQUEST; + blk_dev[LVM_MAJOR].current_request = NULL; + read_ahead[LVM_MAJOR] = INT_MAX; + lvm_gendisk.next = gendisk_head; + + gendisk_head = &lvm_gendisk; +} + +void lvm_print_devices (void) +{ + struct lvm_list_head *tmp; + lvm_rdisk_t *rdisk; + + printk("\n"); + printk(" **********************************\n"); + printk(" * *\n"); + printk(" **********************************\n"); + + tmp = lvm_managed_devices.next; + while (tmp != &lvm_managed_devices) { + rdisk = lvm_list_entry(tmp, lvm_rdisk_t, lvm_managed); + printk("LVM device: <%s>\n", partition_name(rdisk->dev)); + tmp = tmp->next; + } + + printk(" **********************************\n"); + printk("\n"); +} + +/* + * This Linus-trick catches bugs via the linker. + */ + +extern void __BUG__in__lvm_dot_c_1(void); +extern void __BUG__in__lvm_dot_c_2(void); +extern void __BUG__in__lvm_dot_c_3(void); +extern void __BUG__in__lvm_dot_c_4(void); +extern void __BUG__in__lvm_dot_c_5(void); + +void bugcatcher (void) +{ + if (sizeof(lvm_block_group_t) != LVM_BLOCKSIZE) + __BUG__in__lvm_dot_c_1(); + if (sizeof(lvm_index_block_t) != LVM_BLOCKSIZE) + __BUG__in__lvm_dot_c_2(); + if (sizeof(lv_header_t) != LVM_BLOCKSIZE) + __BUG__in__lvm_dot_c_3(); + if (sizeof(lvm_super_t) != LVM_BLOCKSIZE) + __BUG__in__lvm_dot_c_4(); + if (sizeof(lvm_lptr_t) != 16) + __BUG__in__lvm_dot_c_5(); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/md.c linux.ac/drivers/block/md.c --- linux.vanilla/drivers/block/md.c Sun Nov 8 15:10:09 1998 +++ linux.ac/drivers/block/md.c Mon Jul 19 19:48:18 1999 @@ -1,21 +1,17 @@ - /* md.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - + Copyright (C) 1998 Ingo Molnar - A lot of inspiration came from hd.c ... + completely rewritten, based on the MD driver code from Marc Zyngier - kerneld support by Boris Tobotras - boot support for linear and striped mode by Harald Hoyer + Changes: - RAID-1/RAID-5 extensions by: - Ingo Molnar, Miguel de Icaza, Gadi Oxman + - RAID-1/RAID-5 extensions by Miguel de Icaza, Gadi Oxman, Ingo Molnar + - boot support for linear and striped mode by Harald Hoyer + - kerneld support by Boris Tobotras + - kmod support by: Cyrus Durgin + - RAID0 bugfixes: Mark Anthony Lisher - Changes for kmod by: - Cyrus Durgin - 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) @@ -26,807 +22,2972 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - * Current RAID-1,4,5 parallel reconstruction speed limit is 1024 KB/sec, so - * the extra system load does not show up that much. Increase it if your - * system can take more. - */ -#define SPEED_LIMIT 1024 - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + #ifdef CONFIG_KMOD #include #endif -#include -#include #define __KERNEL_SYSCALLS__ #include +#include + +extern asmlinkage int sys_sched_yield(void); +extern asmlinkage int sys_setsid(void); + +extern unsigned long io_events[MAX_BLKDEV]; + #define MAJOR_NR MD_MAJOR #define MD_DRIVER #include -#include -#include -#include #ifdef CONFIG_MD_BOOT -extern kdev_t name_to_kdev_t(char *line) __init; +extern kdev_t name_to_kdev_t(char *line) md__init; #endif -static struct hd_struct md_hd_struct[MAX_MD_DEV]; -static int md_blocksizes[MAX_MD_DEV]; -int md_maxreadahead[MAX_MD_DEV]; -#if SUPPORT_RECONSTRUCTION -static struct md_thread *md_sync_thread = NULL; -#endif /* SUPPORT_RECONSTRUCTION */ +static mdk_personality_t *pers[MAX_PERSONALITY] = {NULL, }; + +/* + * these have to be allocated separately because external + * subsystems want to have a pre-defined structure + */ +struct hd_struct md_hd_struct[MAX_MD_DEVS]; +static int md_blocksizes[MAX_MD_DEVS]; +static int md_maxreadahead[MAX_MD_DEVS]; +static mdk_thread_t *md_recovery_thread = NULL; -int md_size[MAX_MD_DEV]={0, }; +int md_size[MAX_MD_DEVS] = {0, }; static void md_geninit (struct gendisk *); static struct gendisk md_gendisk= { - MD_MAJOR, - "md", - 0, - 1, - MAX_MD_DEV, - md_geninit, - md_hd_struct, - md_size, - MAX_MD_DEV, - NULL, - NULL + MD_MAJOR, + "md", + 0, + 1, + MAX_MD_DEVS, + md_geninit, + md_hd_struct, + md_size, + MAX_MD_DEVS, + NULL, + NULL }; -static struct md_personality *pers[MAX_PERSONALITY]={NULL, }; -struct md_dev md_dev[MAX_MD_DEV]; - -int md_thread(void * arg); +/* + * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' + * is 100 KB/sec, so the extra system load does not show up that much. + * Increase it if you want to have more _guaranteed_ speed. Note that + * the RAID driver will use the maximum available bandwith if the IO + * subsystem is idle. + * + * you can change it via /proc/sys/dev/speed-limit + */ -static struct gendisk *find_gendisk (kdev_t dev) -{ - struct gendisk *tmp=gendisk_head; +static int sysctl_speed_limit = 100; - while (tmp != NULL) - { - if (tmp->major==MAJOR(dev)) - return (tmp); - - tmp=tmp->next; - } +static struct ctl_table_header *md_table_header; - return (NULL); -} +static ctl_table md_table[] = { + {DEV_MD_SPEED_LIMIT, "speed-limit", + &sysctl_speed_limit, sizeof(int), 0644, NULL, &proc_dointvec}, + {0} +}; -char *partition_name (kdev_t dev) -{ - static char name[40]; /* This should be long - enough for a device name ! */ - struct gendisk *hd = find_gendisk (dev); +static ctl_table md_dir_table[] = { + {DEV_MD, "md", NULL, 0, 0555, md_table}, + {0} +}; - if (!hd) - { - sprintf (name, "[dev %s]", kdevname(dev)); - return (name); - } +static ctl_table md_root_table[] = { + {CTL_DEV, "dev", NULL, 0, 0555, md_dir_table}, + {0} +}; - return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ +static void md_register_sysctl(void) +{ + md_table_header = register_sysctl_table(md_root_table, 1); } -static int legacy_raid_sb (int minor, int pnum) +void md_unregister_sysctl(void) { - int i, factor; + unregister_sysctl_table(md_table_header); +} - factor = 1 << FACTOR_SHIFT(FACTOR((md_dev+minor))); +/* + * The mapping between kdev and mddev is not necessary a simple + * one! Eg. HSM uses several sub-devices to implement Logical + * Volumes. All these sub-devices map to the same mddev. + */ +dev_mapping_t mddev_map [MAX_MD_DEVS] = { {NULL, 0}, }; - /***** - * do size and offset calculations. - */ - for (i=0; i> PERSONALITY_SHIFT) - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD * md_dev[minor].nb_dev; - return 0; + if (mddev_map[minor].mddev != NULL) { + MD_BUG(); + return; + } + mddev_map[minor].mddev = mddev; + mddev_map[minor].data = data; } -static void free_sb (struct md_dev *mddev) +void del_mddev_mapping (mddev_t * mddev, kdev_t dev) { - int i; - struct real_dev *realdev; + unsigned int minor = MINOR(dev); - if (mddev->sb) { - free_page((unsigned long) mddev->sb); - mddev->sb = NULL; + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return; } - for (i = 0; i nb_dev; i++) { - realdev = mddev->devices + i; - if (realdev->sb) { - free_page((unsigned long) realdev->sb); - realdev->sb = NULL; - } + if (mddev_map[minor].mddev != mddev) { + MD_BUG(); + return; } + mddev_map[minor].mddev = NULL; + mddev_map[minor].data = NULL; } /* - * Check one RAID superblock for generic plausibility + * Enables to iterate over all existing md arrays */ +static MD_LIST_HEAD(all_mddevs); -#define BAD_MAGIC KERN_ERR \ -"md: %s: invalid raid superblock magic (%x) on block %u\n" +static mddev_t * alloc_mddev (kdev_t dev) +{ + mddev_t * mddev; -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return 0; + } + mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); + if (!mddev) + return NULL; + + memset(mddev, 0, sizeof(*mddev)); -#define NO_DEVICE KERN_ERR \ -"md: disabled device %s\n" + mddev->__minor = MINOR(dev); + mddev->reconfig_sem = MUTEX; + mddev->recovery_sem = MUTEX; + mddev->resync_sem = MUTEX; + MD_INIT_LIST_HEAD(&mddev->disks); + /* + * The 'base' mddev is the one with data NULL. + * personalities can create additional mddevs + * if necessary. + */ + add_mddev_mapping(mddev, dev, 0); + md_list_add(&mddev->all_mddevs, &all_mddevs); -#define SUCCESS 0 -#define FAILURE -1 + return mddev; +} -static int analyze_one_sb (struct real_dev * rdev) +static void free_mddev (mddev_t *mddev) { - int ret = FAILURE; - struct buffer_head *bh; - kdev_t dev = rdev->dev; - md_superblock_t *sb; + if (!mddev) { + MD_BUG(); + return; + } /* - * Read the superblock, it's at the end of the disk + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) */ - rdev->sb_offset = MD_NEW_SIZE_BLOCKS (blk_size[MAJOR(dev)][MINOR(dev)]); - set_blocksize (dev, MD_SB_BYTES); - bh = bread (dev, rdev->sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - - if (bh) { - sb = (md_superblock_t *) bh->b_data; - if (sb->md_magic != MD_SB_MAGIC) { - printk (BAD_MAGIC, kdevname(dev), - sb->md_magic, rdev->sb_offset); - goto abort; - } - rdev->sb = (md_superblock_t *) __get_free_page(GFP_KERNEL); - if (!rdev->sb) { - printk (OUT_OF_MEM); - goto abort; - } - memcpy (rdev->sb, bh->b_data, MD_SB_BYTES); + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); - rdev->size = sb->size; - } else - printk (NO_DEVICE,kdevname(rdev->dev)); - ret = SUCCESS; -abort: - if (bh) - brelse (bh); - return ret; + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); } -#undef SUCCESS -#undef FAILURE - -#undef BAD_MAGIC -#undef OUT_OF_MEM -#undef NO_DEVICE -/* - * Check a full RAID array for plausibility - */ +struct gendisk * find_gendisk (kdev_t dev) +{ + struct gendisk *tmp = gendisk_head; -#define INCONSISTENT KERN_ERR \ -"md: superblock inconsistency -- run ckraid\n" + while (tmp != NULL) { + if (tmp->major == MAJOR(dev)) + return (tmp); + tmp = tmp->next; + } + return (NULL); +} -#define OUT_OF_DATE KERN_ERR \ -"md: superblock update time inconsistenty -- using the most recent one\n" +mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; -#define OLD_VERSION KERN_ALERT \ -"md: %s: unsupported raid array version %d.%d.%d\n" + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == nr) + return rdev; + } + return NULL; +} -#define NOT_CLEAN KERN_ERR \ -"md: %s: raid array is not clean -- run ckraid\n" +mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; -#define NOT_CLEAN_IGNORE KERN_ERR \ -"md: %s: raid array is not clean -- reconstructing parity\n" + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->dev == dev) + return rdev; + } + return NULL; +} -#define UNKNOWN_LEVEL KERN_ERR \ -"md: %s: unsupported raid level %d\n" +static MD_LIST_HEAD(device_names); -static int analyze_sbs (int minor, int pnum) +char * partition_name (kdev_t dev) { - struct md_dev *mddev = md_dev + minor; - int i, N = mddev->nb_dev, out_of_date = 0; - struct real_dev * disks = mddev->devices; - md_superblock_t *sb, *freshest = NULL; + struct gendisk *hd; + static char nomem [] = ""; + dev_name_t *dname; + struct md_list_head *tmp = device_names.next; - /* - * RAID-0 and linear don't use a RAID superblock - */ - if (pnum == RAID0 >> PERSONALITY_SHIFT || - pnum == LINEAR >> PERSONALITY_SHIFT) - return legacy_raid_sb (minor, pnum); + while (tmp != &device_names) { + dname = md_list_entry(tmp, dev_name_t, list); + if (dname->dev == dev) + return dname->name; + tmp = tmp->next; + } + + dname = (dev_name_t *) kmalloc(sizeof(*dname), GFP_KERNEL); + if (!dname) + return nomem; /* - * Verify the RAID superblock on each real device + * ok, add this new device name to the list */ - for (i = 0; i < N; i++) - if (analyze_one_sb(disks+i)) - goto abort; + hd = find_gendisk (dev); + + if (!hd) + sprintf (dname->name, "[dev %s]", kdevname(dev)); + else + disk_name (hd, MINOR(dev), dname->name); + + dname->dev = dev; + md_list_add(&dname->list, &device_names); + + return dname->name; +} + +static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, + int persistent) +{ + unsigned int size = 0; + + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + if (persistent) + size = MD_NEW_SIZE_BLOCKS(size); + return size; +} + +static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) +{ + unsigned int size; + + size = calc_dev_sboffset(dev, mddev, persistent); + if (!mddev->sb) { + MD_BUG(); + return size; + } + if (mddev->sb->chunk_size) + size &= ~(mddev->sb->chunk_size/1024 - 1); + return size; +} + +/* + * We check wether all devices are numbered from 0 to nb_dev-1. The + * order is guaranteed even after device name changes. + * + * Some personalities (raid0, linear) use this. Personalities that + * provide data have to be able to deal with loss of individual + * disks, so they do their checking themselves. + */ +int md_check_ordering (mddev_t *mddev) +{ + int i, c; + mdk_rdev_t *rdev; + struct md_list_head *tmp; /* - * The superblock constant part has to be the same - * for all disks in the array. + * First, all devices must be fully functional */ - sb = NULL; - for (i = 0; i < N; i++) { - if (!disks[i].sb) - continue; - if (!sb) { - sb = disks[i].sb; - continue; - } - if (memcmp(sb, - disks[i].sb, MD_SB_GENERIC_CONSTANT_WORDS * 4)) { - printk (INCONSISTENT); + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + printk("md: md%d's device %s faulty, aborting.\n", + mdidx(mddev), partition_name(rdev->dev)); goto abort; } } - /* - * OK, we have all disks and the array is ready to run. Let's - * find the freshest superblock, that one will be the superblock - * that represents the whole array. - */ - if ((sb = mddev->sb = (md_superblock_t *) __get_free_page (GFP_KERNEL)) == NULL) + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + c++; + } + if (c != mddev->nb_dev) { + MD_BUG(); goto abort; - freshest = NULL; - for (i = 0; i < N; i++) { - if (!disks[i].sb) - continue; - if (!freshest) { - freshest = disks[i].sb; - continue; - } - /* - * Find the newest superblock version - */ - if (disks[i].sb->utime != freshest->utime) { - out_of_date = 1; - if (disks[i].sb->utime > freshest->utime) - freshest = disks[i].sb; - } } - if (out_of_date) - printk(OUT_OF_DATE); - memcpy (sb, freshest, sizeof(*freshest)); - - /* - * Check if we can support this RAID array - */ - if (sb->major_version != MD_MAJOR_VERSION || - sb->minor_version > MD_MINOR_VERSION) { - - printk (OLD_VERSION, kdevname(MKDEV(MD_MAJOR, minor)), - sb->major_version, sb->minor_version, - sb->patch_version); + if (mddev->nb_dev != mddev->sb->raid_disks) { + printk("md: md%d, array needs %d disks, has %d, aborting.\n", + mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); goto abort; } - /* - * We need to add this as a superblock option. + * Now the numbering check */ -#if SUPPORT_RECONSTRUCTION - if (sb->state != (1 << MD_SB_CLEAN)) { - if (sb->level == 1) { - printk (NOT_CLEAN, kdevname(MKDEV(MD_MAJOR, minor))); + for (i = 0; i < mddev->nb_dev; i++) { + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == i) + c++; + } + if (c == 0) { + printk("md: md%d, missing disk #%d, aborting.\n", + mdidx(mddev), i); goto abort; - } else - printk (NOT_CLEAN_IGNORE, kdevname(MKDEV(MD_MAJOR, minor))); - } -#else - if (sb->state != (1 << MD_SB_CLEAN)) { - printk (NOT_CLEAN, kdevname(MKDEV(MD_MAJOR, minor))); - goto abort; - } -#endif /* SUPPORT_RECONSTRUCTION */ - - switch (sb->level) { - case 1: - md_size[minor] = sb->size; - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD; - break; - case 4: - case 5: - md_size[minor] = sb->size * (sb->raid_disks - 1); - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD * (sb->raid_disks - 1); - break; - default: - printk (UNKNOWN_LEVEL, kdevname(MKDEV(MD_MAJOR, minor)), - sb->level); + } + if (c > 1) { + printk("md: md%d, too many disks #%d, aborting.\n", + mdidx(mddev), i); goto abort; + } } return 0; abort: - free_sb(mddev); return 1; } -#undef INCONSISTENT -#undef OUT_OF_DATE -#undef OLD_VERSION -#undef NOT_CLEAN -#undef OLD_LEVEL - -int md_update_sb(int minor) +static unsigned int zoned_raid_size (mddev_t *mddev) { - struct md_dev *mddev = md_dev + minor; - struct buffer_head *bh; - md_superblock_t *sb = mddev->sb; - struct real_dev *realdev; - kdev_t dev; - int i; - u32 sb_offset; + unsigned int mask; + mdk_rdev_t * rdev; + struct md_list_head *tmp; - sb->utime = CURRENT_TIME; - for (i = 0; i < mddev->nb_dev; i++) { - realdev = mddev->devices + i; - if (!realdev->sb) - continue; - dev = realdev->dev; - sb_offset = realdev->sb_offset; - set_blocksize(dev, MD_SB_BYTES); - printk("md: updating raid superblock on device %s, sb_offset == %u\n", kdevname(dev), sb_offset); - bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (bh) { - sb = (md_superblock_t *) bh->b_data; - memcpy(sb, mddev->sb, MD_SB_BYTES); - memcpy(&sb->descriptor, sb->disks + realdev->sb->descriptor.number, MD_SB_DESCRIPTOR_WORDS * 4); - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - } else - printk(KERN_ERR "md: getblk failed for device %s\n", kdevname(dev)); + if (!mddev->sb) { + MD_BUG(); + return -EINVAL; + } + /* + * do size and offset calculations. + */ + mask = ~(mddev->sb->chunk_size/1024 - 1); +printk("mask %08x\n", mask); + + ITERATE_RDEV(mddev,rdev,tmp) { +printk(" rdev->size: %d\n", rdev->size); + rdev->size &= mask; +printk(" masked rdev->size: %d\n", rdev->size); + md_size[mdidx(mddev)] += rdev->size; +printk(" new md_size: %d\n", md_size[mdidx(mddev)]); } return 0; } -static int do_md_run (int minor, int repart) +static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) { - int pnum, i, min, factor, err; + if (disk_active(disk)) { + sb->working_disks--; + } else { + if (disk_spare(disk)) { + sb->spare_disks--; + sb->working_disks--; + } else { + sb->failed_disks--; + } + } + sb->nr_disks--; + disk->major = 0; + disk->minor = 0; + mark_disk_removed(disk); +} - if (!md_dev[minor].nb_dev) - return -EINVAL; - - if (md_dev[minor].pers) - return -EBUSY; +#define BAD_MAGIC KERN_ERR \ +"md: invalid raid superblock magic on %s\n" - md_dev[minor].repartition=repart; - - if ((pnum=PERSONALITY(&md_dev[minor]) >> (PERSONALITY_SHIFT)) - >= MAX_PERSONALITY) - return -EINVAL; - - /* Only RAID-1 and RAID-5 can have MD devices as underlying devices */ - if (pnum != (RAID1 >> PERSONALITY_SHIFT) && pnum != (RAID5 >> PERSONALITY_SHIFT)){ - for (i = 0; i < md_dev [minor].nb_dev; i++) - if (MAJOR (md_dev [minor].devices [i].dev) == MD_MAJOR) - return -EINVAL; - } - if (!pers[pnum]) - { -#ifdef CONFIG_KMOD - char module_name[80]; - sprintf (module_name, "md-personality-%d", pnum); - request_module (module_name); - if (!pers[pnum]) -#endif - return -EINVAL; - } - - factor = min = 1 << FACTOR_SHIFT(FACTOR((md_dev+minor))); - - for (i=0; irun (minor, md_dev+minor))) - { - md_dev[minor].pers=NULL; - free_sb(md_dev + minor); - return (err); - } - - if (pnum != RAID0 >> PERSONALITY_SHIFT && pnum != LINEAR >> PERSONALITY_SHIFT) - { - md_dev[minor].sb->state &= ~(1 << MD_SB_CLEAN); - md_update_sb(minor); - } - - /* FIXME : We assume here we have blocks - that are twice as large as sectors. - THIS MAY NOT BE TRUE !!! */ - md_hd_struct[minor].start_sect=0; - md_hd_struct[minor].nr_sects=md_size[minor]<<1; - - read_ahead[MD_MAJOR] = 128; - return (0); -} +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_SB KERN_ERR \ +"md: disabled device %s, could not read superblock.\n" -static int do_md_stop (int minor, struct inode *inode) +#define BAD_CSUM KERN_WARNING \ +"md: invalid superblock checksum on %s\n" + +static int alloc_array_sb (mddev_t * mddev) { - int i; - - if (inode->i_count>1 || md_dev[minor].busy>1) { - /* - * ioctl : one open channel - */ - printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", - minor, inode->i_count, md_dev[minor].busy); - return -EBUSY; - } - - if (md_dev[minor].pers) { - /* - * It is safe to call stop here, it only frees private - * data. Also, it tells us if a device is unstoppable - * (eg. resyncing is in progress) - */ - if (md_dev[minor].pers->stop (minor, md_dev+minor)) - return -EBUSY; - /* - * The device won't exist anymore -> flush it now - */ - fsync_dev (inode->i_rdev); - invalidate_buffers (inode->i_rdev); - if (md_dev[minor].sb) { - md_dev[minor].sb->state |= 1 << MD_SB_CLEAN; - md_update_sb(minor); - } + if (mddev->sb) { + MD_BUG(); + return 0; } - - /* Remove locks. */ - if (md_dev[minor].sb) - free_sb(md_dev + minor); - for (i=0; isb = (mdp_super_t *) __get_free_page (GFP_KERNEL); + if (!mddev->sb) + return -ENOMEM; + md_clear_page((unsigned long)mddev->sb); + return 0; } -static int do_md_add (int minor, kdev_t dev) +static int alloc_disk_sb (mdk_rdev_t * rdev) { - int i; - int hot_add=0; - struct real_dev *realdev; + if (rdev->sb) + MD_BUG(); - if (md_dev[minor].nb_dev==MAX_REAL) + rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); + if (!rdev->sb) { + printk (OUT_OF_MEM); return -EINVAL; + } + md_clear_page((unsigned long)rdev->sb); - if (!fs_may_mount (dev)) - return -EBUSY; + return 0; +} - if (blk_size[MAJOR(dev)] == NULL || blk_size[MAJOR(dev)][MINOR(dev)] == 0) { - printk("md_add(): zero device size, huh, bailing out.\n"); - return -EINVAL; +static void free_disk_sb (mdk_rdev_t * rdev) +{ + if (rdev->sb) { + free_page((unsigned long) rdev->sb); + rdev->sb = NULL; + rdev->sb_offset = 0; + rdev->size = 0; + } else { + if (!rdev->faulty) + MD_BUG(); } +} - if (md_dev[minor].pers) { - /* - * The array is already running, hot-add the drive, or - * bail out: - */ - if (!md_dev[minor].pers->hot_add_disk) - return -EBUSY; - else - hot_add=1; +static void mark_rdev_faulty (mdk_rdev_t * rdev) +{ + unsigned long flags; + + if (!rdev) { + MD_BUG(); + return; } + save_flags(flags); + cli(); + free_disk_sb(rdev); + rdev->faulty = 1; + restore_flags(flags); +} + +static int read_disk_sb (mdk_rdev_t * rdev) +{ + int ret = -EINVAL; + struct buffer_head *bh = NULL; + kdev_t dev = rdev->dev; + mdp_super_t *sb; + u32 sb_offset; + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + /* - * Careful. We cannot increase nb_dev for a running array. + * Calculate the position of the superblock, + * it's at the end of the disk */ - i=md_dev[minor].nb_dev; - realdev = &md_dev[minor].devices[i]; - realdev->dev=dev; - - /* Lock the device by inserting a dummy inode. This doesn't - smell very good, but I need to be consistent with the - mount stuff, specially with fs_may_mount. If someone have - a better idea, please help ! */ - - realdev->inode=get_empty_inode (); - realdev->inode->i_dev=dev; /* don't care about other fields */ - insert_inode_hash (realdev->inode); - - /* Sizes are now rounded at run time */ - -/* md_dev[minor].devices[i].size=gen_real->sizes[MINOR(dev)]; HACKHACK*/ + sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); + rdev->sb_offset = sb_offset; + printk("(read) %s's sb offset: %d", partition_name(dev), + sb_offset); + fsync_dev(dev); + set_blocksize (dev, MD_SB_BYTES); + bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + + if (bh) { + sb = (mdp_super_t *) bh->b_data; + memcpy (rdev->sb, sb, MD_SB_BYTES); + } else { + printk (NO_SB,partition_name(rdev->dev)); + goto abort; + } + printk(" [events: %08lx]\n", (unsigned long)get_unaligned(&rdev->sb->events)); + ret = 0; +abort: + if (bh) + brelse (bh); + return ret; +} + +static unsigned int calc_sb_csum (mdp_super_t * sb) +{ + unsigned int disk_csum, csum; + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + csum = csum_partial((void *)sb, MD_SB_BYTES, 0); + sb->sb_csum = disk_csum; + return csum; +} + +/* + * Check one RAID superblock for generic plausibility + */ + +static int check_disk_sb (mdk_rdev_t * rdev) +{ + mdp_super_t *sb; + int ret = -EINVAL; + + sb = rdev->sb; + if (!sb) { + MD_BUG(); + goto abort; + } + + if (sb->md_magic != MD_SB_MAGIC) { + printk (BAD_MAGIC, partition_name(rdev->dev)); + goto abort; + } + + if (sb->md_minor >= MAX_MD_DEVS) { + printk (BAD_MINOR, partition_name(rdev->dev), + sb->md_minor); + goto abort; + } + + if (calc_sb_csum(sb) != sb->sb_csum) + printk(BAD_CSUM, partition_name(rdev->dev)); + ret = 0; +abort: + return ret; +} + +static kdev_t dev_unit(kdev_t dev) +{ + unsigned int mask; + struct gendisk *hd = find_gendisk(dev); + + if (!hd) + return 0; + mask = ~((1 << hd->minor_shift) - 1); + + return MKDEV(MAJOR(dev), MINOR(dev) & mask); +} + +static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev,rdev,tmp) + if (dev_unit(rdev->dev) == dev_unit(dev)) + return rdev; + + return NULL; +} + +static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev1,rdev,tmp) + if (match_dev_unit(mddev2, rdev->dev)) + return 1; + + return 0; +} + +static MD_LIST_HEAD(all_raid_disks); +static MD_LIST_HEAD(pending_raid_disks); + +static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) +{ + mdk_rdev_t *same_pdev; + + if (rdev->mddev) { + MD_BUG(); + return; + } + same_pdev = match_dev_unit(mddev, rdev->dev); + if (same_pdev) + printk( KERN_WARNING +"md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" +" protection against single-disk failure might be compromised.\n", + mdidx(mddev), partition_name(rdev->dev), + partition_name(same_pdev->dev)); + + md_list_add(&rdev->same_set, &mddev->disks); + rdev->mddev = mddev; + mddev->nb_dev++; + printk("bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); +} + +static void unbind_rdev_from_array (mdk_rdev_t * rdev) +{ + if (!rdev->mddev) { + MD_BUG(); + return; + } + md_list_del(&rdev->same_set); + MD_INIT_LIST_HEAD(&rdev->same_set); + rdev->mddev->nb_dev--; + printk("unbind<%s,%d>\n", partition_name(rdev->dev), + rdev->mddev->nb_dev); + rdev->mddev = NULL; +} + +/* + * prevent the device from being mounted, repartitioned or + * otherwise reused by a RAID array (or any other kernel + * subsystem), by opening the device. [simply getting an + * inode is not enough, the SCSI module usage code needs + * an explicit open() on the device] + */ +static void lock_rdev (mdk_rdev_t *rdev) +{ + int err = 0; + + /* + * First insert a dummy inode. + */ + rdev->inode = get_empty_inode(); + /* + * we dont care about any other fields + */ + rdev->inode->i_dev = rdev->inode->i_rdev = rdev->dev; + insert_inode_hash(rdev->inode); + + memset(&rdev->filp, 0, sizeof(rdev->filp)); + rdev->filp.f_mode = 3; /* read write */ + err = blkdev_open(rdev->inode, &rdev->filp); + if (err) + printk("blkdev_open() failed: %d\n", err); +} + +static void unlock_rdev (mdk_rdev_t *rdev) +{ + blkdev_release(rdev->inode); +} + +static void export_rdev (mdk_rdev_t * rdev) +{ + printk("export_rdev(%s)\n",partition_name(rdev->dev)); + if (rdev->mddev) + MD_BUG(); + unlock_rdev(rdev); + free_disk_sb(rdev); + md_list_del(&rdev->all); + MD_INIT_LIST_HEAD(&rdev->all); + if (rdev->pending.next != &rdev->pending) { + printk("(%s was pending)\n",partition_name(rdev->dev)); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + rdev->dev = 0; + rdev->faulty = 0; + kfree(rdev); +} + +static void kick_rdev_from_array (mdk_rdev_t * rdev) +{ + unbind_rdev_from_array(rdev); + export_rdev(rdev); +} + +static void export_array (mddev_t *mddev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + mdp_super_t *sb = mddev->sb; + + if (mddev->sb) { + mddev->sb = NULL; + free_page((unsigned long) sb); + } + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!rdev->mddev) { + MD_BUG(); + continue; + } + kick_rdev_from_array(rdev); + } + if (mddev->nb_dev) + MD_BUG(); +} + +#undef BAD_CSUM +#undef BAD_MAGIC +#undef OUT_OF_MEM +#undef NO_SB + +static void print_desc(mdp_disk_t *desc) +{ + printk(" DISK\n", desc->number, + partition_name(MKDEV(desc->major,desc->minor)), + desc->major,desc->minor,desc->raid_disk,desc->state); +} + +static void print_sb(mdp_super_t *sb) +{ + int i; + + printk(" SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", + sb->major_version, sb->minor_version, sb->patch_version, + sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, + sb->ctime); + printk(" L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, + sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, + sb->layout, sb->chunk_size); + printk(" UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", + sb->utime, sb->state, sb->active_disks, sb->working_disks, + sb->failed_disks, sb->spare_disks, + sb->sb_csum, (unsigned long)get_unaligned(&sb->events)); + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + + desc = sb->disks + i; + printk(" D %2d: ", i); + print_desc(desc); + } + printk(" THIS: "); + print_desc(&sb->this_disk); + +} + +static void print_rdev(mdk_rdev_t *rdev) +{ + printk(" rdev %s: O:%s, SZ:%08d F:%d DN:%d ", + partition_name(rdev->dev), partition_name(rdev->old_dev), + rdev->size, rdev->faulty, rdev->desc_nr); + if (rdev->sb) { + printk("rdev superblock:\n"); + print_sb(rdev->sb); + } else + printk("no rdev superblock!\n"); +} + +void md_print_devices (void) +{ + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev; + mddev_t *mddev; + + printk("\n"); + printk(" **********************************\n"); + printk(" * *\n"); + printk(" **********************************\n"); + ITERATE_MDDEV(mddev,tmp) { + printk("md%d: ", mdidx(mddev)); + + ITERATE_RDEV(mddev,rdev,tmp2) + printk("<%s>", partition_name(rdev->dev)); + + if (mddev->sb) { + printk(" array superblock:\n"); + print_sb(mddev->sb); + } else + printk(" no array superblock.\n"); + + ITERATE_RDEV(mddev,rdev,tmp2) + print_rdev(rdev); + } + printk(" **********************************\n"); + printk("\n"); +} + +static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) +{ + int ret; + mdp_super_t *tmp1, *tmp2; + + tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL); + tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL); + + if (!tmp1 || !tmp2) { + ret = 0; + goto abort; + } + + *tmp1 = *sb1; + *tmp2 = *sb2; + + /* + * nr_disks is not constant + */ + tmp1->nr_disks = 0; + tmp2->nr_disks = 0; + + if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4)) + ret = 0; + else + ret = 1; + +abort: + if (tmp1) + kfree(tmp1); + if (tmp2) + kfree(tmp2); + + return ret; +} + +static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) +{ + if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && + (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && + (rdev1->sb->set_uuid2 == rdev2->sb->set_uuid2) && + (rdev1->sb->set_uuid3 == rdev2->sb->set_uuid3)) + + return 1; + + return 0; +} + +static mdk_rdev_t * find_rdev_all (kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + tmp = all_raid_disks.next; + while (tmp != &all_raid_disks) { + rdev = md_list_entry(tmp, mdk_rdev_t, all); + if (rdev->dev == dev) + return rdev; + tmp = tmp->next; + } + return NULL; +} + +#define GETBLK_FAILED KERN_ERR \ +"md: getblk failed for device %s\n" + +static int write_disk_sb(mdk_rdev_t * rdev) +{ + struct buffer_head *bh; + kdev_t dev; + u32 sb_offset, size; + mdp_super_t *sb; + + if (!rdev->sb) { + MD_BUG(); + return -1; + } + if (rdev->faulty) { + MD_BUG(); + return -1; + } + if (rdev->sb->md_magic != MD_SB_MAGIC) { + MD_BUG(); + return -1; + } + + dev = rdev->dev; + sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); + if (rdev->sb_offset != sb_offset) { + printk("%s's sb offset has changed from %d to %d, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); + goto skip; + } + /* + * If the disk went offline meanwhile and it's just a spare, then + * it's size has changed to zero silently, and the MD code does + * not yet know that it's faulty. + */ + size = calc_dev_size(dev, rdev->mddev, 1); + if (size != rdev->size) { + printk("%s's size has changed from %d to %d since import, skipping\n", partition_name(dev), rdev->size, size); + goto skip; + } + + printk("(write) %s's sb offset: %d\n", partition_name(dev), sb_offset); + fsync_dev(dev); + set_blocksize(dev, MD_SB_BYTES); + bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + if (!bh) { + printk(GETBLK_FAILED, partition_name(dev)); + return 1; + } + memset(bh->b_data,0,bh->b_size); + sb = (mdp_super_t *) bh->b_data; + memcpy(sb, rdev->sb, MD_SB_BYTES); + + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 1); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + brelse(bh); + fsync_dev(dev); +skip: + return 0; +} +#undef GETBLK_FAILED KERN_ERR + +static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) +{ + int i, ok = 0; + mdp_disk_t *desc; + + for (i = 0; i < MD_SB_DISKS; i++) { + desc = mddev->sb->disks + i; +#if 0 + if (disk_faulty(desc)) { + if (MKDEV(desc->major,desc->minor) == rdev->dev) + ok = 1; + continue; + } +#endif + if (MKDEV(desc->major,desc->minor) == rdev->dev) { + rdev->sb->this_disk = *desc; + rdev->desc_nr = desc->number; + ok = 1; + break; + } + } + + if (!ok) { + MD_BUG(); + } +} + +static int sync_sbs(mddev_t * mddev) +{ + mdk_rdev_t *rdev; + mdp_super_t *sb; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + sb = rdev->sb; + *sb = *mddev->sb; + set_this_disk(mddev, rdev); + sb->sb_csum = calc_sb_csum(sb); + } + return 0; +} + +int md_update_sb(mddev_t * mddev) +{ + int first, err, count = 100; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + __u64 ev; + +repeat: + mddev->sb->utime = CURRENT_TIME; + ev = get_unaligned(&mddev->sb->events); + ++ev; + put_unaligned(ev,&mddev->sb->events); + if (ev == (__u64)0) { + /* + * oops, this 64-bit counter should never wrap. + * Either we are in around ~1 trillion A.C., assuming + * 1 reboot per second, or we have a bug: + */ + MD_BUG(); + --ev; + put_unaligned(ev,&mddev->sb->events); + } + sync_sbs(mddev); + + /* + * do not write anything to disk if using + * nonpersistent superblocks + */ + if (mddev->sb->not_persistent) + return 0; + + printk(KERN_INFO "md: updating md%d RAID superblock on device\n", + mdidx(mddev)); + + first = 1; + err = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (!first) { + first = 0; + printk(", "); + } + if (rdev->faulty) + printk("(skipping faulty "); + printk("%s ", partition_name(rdev->dev)); + if (!rdev->faulty) { + printk("[events: %08lx]", + (unsigned long)get_unaligned(&rdev->sb->events)); + err += write_disk_sb(rdev); + } else + printk(")\n"); + } + printk(".\n"); + if (err) { + printk("errors occured during superblock update, repeating\n"); + if (--count) + goto repeat; + printk("excessive errors occured during superblock update, exiting\n"); + } + return 0; +} + +/* + * Import a device. If 'on_disk', then sanity check the superblock + * + * mark the device faulty if: + * + * - the device is nonexistent (zero size) + * - the device has no valid superblock + * + * a faulty rdev _never_ has rdev->sb set. + */ +static int md_import_device (kdev_t newdev, int on_disk) +{ + int err; + mdk_rdev_t *rdev; + unsigned int size; + + if (find_rdev_all(newdev)) + return -EEXIST; + + rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + printk("could not alloc mem for %s!\n", partition_name(newdev)); + return -ENOMEM; + } + memset(rdev, 0, sizeof(*rdev)); + + if (!fs_may_mount(newdev)) { + printk("md: can not import %s, has active inodes!\n", + partition_name(newdev)); + err = -EBUSY; + goto abort_free; + } + + if ((err = alloc_disk_sb(rdev))) + goto abort_free; + + rdev->dev = newdev; + lock_rdev(rdev); + rdev->desc_nr = -1; + rdev->faulty = 0; + + size = 0; + if (blk_size[MAJOR(newdev)]) + size = blk_size[MAJOR(newdev)][MINOR(newdev)]; + if (!size) { + printk("md: %s has zero size, marking faulty!\n", + partition_name(newdev)); + err = -EINVAL; + goto abort_free; + } + + if (on_disk) { + if ((err = read_disk_sb(rdev))) { + printk("md: could not read %s's sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + if ((err = check_disk_sb(rdev))) { + printk("md: %s has invalid sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + + rdev->old_dev = MKDEV(rdev->sb->this_disk.major, + rdev->sb->this_disk.minor); + rdev->desc_nr = rdev->sb->this_disk.number; + } + md_list_add(&rdev->all, &all_raid_disks); + MD_INIT_LIST_HEAD(&rdev->pending); + + if (rdev->faulty && rdev->sb) + free_disk_sb(rdev); + return 0; + +abort_free: + if (rdev->sb) + free_disk_sb(rdev); + kfree(rdev); + return err; +} + +/* + * Check a full RAID array for plausibility + */ + +#define INCONSISTENT KERN_ERR \ +"md: fatal superblock inconsistency in %s -- removing from array\n" + +#define OUT_OF_DATE KERN_ERR \ +"md: superblock update time inconsistency -- using the most recent one\n" + +#define OLD_VERSION KERN_ALERT \ +"md: md%d: unsupported raid array version %d.%d.%d\n" + +#define NOT_CLEAN_IGNORE KERN_ERR \ +"md: md%d: raid array is not clean -- starting background reconstruction\n" + +#define UNKNOWN_LEVEL KERN_ERR \ +"md: md%d: unsupported raid level %d\n" + +static int analyze_sbs (mddev_t * mddev) +{ + int out_of_date = 0, i; + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev, *rdev2, *freshest; + mdp_super_t *sb; + + /* + * Verify the RAID superblock on each real device + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + MD_BUG(); + goto abort; + } + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + if (check_disk_sb(rdev)) + goto abort; + } + + /* + * The superblock constant part has to be the same + * for all disks in the array. + */ + sb = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!sb) { + sb = rdev->sb; + continue; + } + if (!sb_equal(sb, rdev->sb)) { + printk (INCONSISTENT, partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * OK, we have all disks and the array is ready to run. Let's + * find the freshest superblock, that one will be the superblock + * that represents the whole array. + */ + if (!mddev->sb) + if (alloc_array_sb(mddev)) + goto abort; + sb = mddev->sb; + freshest = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2; + /* + * if the checksum is invalid, use the superblock + * only as a last resort. (decrease it's age by + * one event) + */ + if (calc_sb_csum(rdev->sb) != rdev->sb->sb_csum) { + __u64 ev = get_unaligned(&rdev->sb->events); + if (ev != (__u64)0) { + --ev; + put_unaligned(ev,&rdev->sb->events); + } + } + + printk("%s's event counter: %08lx\n", partition_name(rdev->dev), + (unsigned long)get_unaligned(&rdev->sb->events)); + if (!freshest) { + freshest = rdev; + continue; + } + /* + * Find the newest superblock version + */ + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&freshest->sb->events); + if (ev1 != ev2) { + out_of_date = 1; + if (ev1 > ev2) + freshest = rdev; + } + } + if (out_of_date) { + printk(OUT_OF_DATE); + printk("freshest: %s\n", partition_name(freshest->dev)); + } + memcpy (sb, freshest->sb, sizeof(*sb)); + + /* + * at this point we have picked the 'best' superblock + * from all available superblocks. + * now we validate this superblock and kick out possibly + * failed disks. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + /* + * Kick all non-fresh devices faulty + */ + __u64 ev1, ev2; + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&sb->events); + ++ev1; + if (ev1 < ev2) { + printk("md: kicking non-fresh %s from array!\n", + partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * Fix up changed device names ... but only if this disk has a + * recent update time. Use faulty checksum ones too. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2, ev3; + if (rdev->faulty) { /* REMOVEME */ + MD_BUG(); + goto abort; + } + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&sb->events); + ev3 = ev2; + --ev3; + if ((rdev->dev != rdev->old_dev) && + ((ev1 == ev2) || (ev1 == ev3))) { + mdp_disk_t *desc; + + printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev)); + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + desc = &sb->disks[rdev->desc_nr]; + if (rdev->old_dev != MKDEV(desc->major, desc->minor)) { + MD_BUG(); + goto abort; + } + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + desc = &rdev->sb->this_disk; + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + } + } + + /* + * Remove unavailable and faulty devices ... + * + * note that if an array becomes completely unrunnable due to + * missing devices, we do not write the superblock back, so the + * administrator has a chance to fix things up. The removal thus + * only happens if it's nonfatal to the contents of the array. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + int found; + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + /* + * We kick faulty devices/descriptors immediately. + */ + if (disk_faulty(desc)) { + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr != desc->number) + continue; + printk("md%d: kicking faulty %s!\n", + mdidx(mddev),partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + found = 1; + break; + } + if (!found) { + if (dev == MKDEV(0,0)) + continue; + printk("md%d: removing former faulty %s!\n", + mdidx(mddev), partition_name(dev)); + } + remove_descriptor(desc, sb); + continue; + } + + if (dev == MKDEV(0,0)) + continue; + /* + * Is this device present in the rdev ring? + */ + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == desc->number) { + found = 1; + break; + } + } + if (found) + continue; + + printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); + remove_descriptor(desc, sb); + } + + /* + * Double check wether all devices mentioned in the + * superblock are in the rdev ring. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + + if (disk_faulty(desc)) { + MD_BUG(); + goto abort; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + } + + /* + * Do a final reality check. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + /* + * is the desc_nr unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->desc_nr == rdev->desc_nr)) { + MD_BUG(); + goto abort; + } + } + /* + * is the device unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->dev == rdev->dev)) { + MD_BUG(); + goto abort; + } + } + } + + /* + * Check if we can support this RAID array + */ + if (sb->major_version != MD_MAJOR_VERSION || + sb->minor_version > MD_MINOR_VERSION) { + + printk (OLD_VERSION, mdidx(mddev), sb->major_version, + sb->minor_version, sb->patch_version); + goto abort; + } + + if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || + (sb->level == 4) || (sb->level == 5))) + printk (NOT_CLEAN_IGNORE, mdidx(mddev)); + + return 0; +abort: + return 1; +} + +#undef INCONSISTENT +#undef OUT_OF_DATE +#undef OLD_VERSION +#undef OLD_LEVEL + +static int device_size_calculation (mddev_t * mddev) +{ + int data_disks = 0, persistent; + unsigned int readahead; + mdp_super_t *sb = mddev->sb; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + /* + * Do device size calculation. Bail out if too small. + * (we have to do this after having validated chunk_size, + * because device size has to be modulo chunk_size) + */ + persistent = !mddev->sb->not_persistent; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + if (rdev->size) { + MD_BUG(); + continue; + } + rdev->size = calc_dev_size(rdev->dev, mddev, persistent); + if (rdev->size < sb->chunk_size / 1024) { + printk (KERN_WARNING + "Dev %s smaller than chunk_size: %dk < %dk\n", + partition_name(rdev->dev), + rdev->size, sb->chunk_size / 1024); + return -EINVAL; + } + } + + switch (sb->level) { + case -3: + data_disks = 1; + break; + case -2: + data_disks = 1; + break; + case -1: + zoned_raid_size(mddev); + data_disks = 1; + break; + case 0: + zoned_raid_size(mddev); + data_disks = sb->raid_disks; + break; + case 1: + data_disks = 1; + break; + case 4: + case 5: + data_disks = sb->raid_disks-1; + break; + default: + printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); + goto abort; + } + if (!md_size[mdidx(mddev)]) + md_size[mdidx(mddev)] = sb->size * data_disks; + + readahead = MD_READAHEAD; + if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) + readahead = mddev->sb->chunk_size * 4 * data_disks; + if (readahead < data_disks * MAX_SECTORS*512*2) + readahead = data_disks * MAX_SECTORS*512*2; + else { + if (sb->level == -3) + readahead = 0; + } + md_maxreadahead[mdidx(mddev)] = readahead; + + printk(KERN_INFO "md%d: max total readahead window set to %dk\n", + mdidx(mddev), readahead/1024); + + printk(KERN_INFO + "md%d: %d data-disks, max readahead per data-disk: %dk\n", + mdidx(mddev), data_disks, readahead/data_disks/1024); + return 0; +abort: + return 1; +} + + +#define TOO_BIG_CHUNKSIZE KERN_ERR \ +"too big chunk_size: %d > %d\n" + +#define TOO_SMALL_CHUNKSIZE KERN_ERR \ +"too small chunk_size: %d < %ld\n" + +#define BAD_CHUNKSIZE KERN_ERR \ +"no chunksize specified, see 'man raidtab'\n" + +static int do_md_run (mddev_t * mddev) +{ + int pnum, err; + int chunk_size; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + + if (!mddev->nb_dev) { + MD_BUG(); + return -EINVAL; + } + + if (mddev->pers) + return -EBUSY; + + /* + * Resize disks to align partitions size on a given + * chunk size. + */ + md_size[mdidx(mddev)] = 0; + + /* + * Analyze all RAID superblock(s) + */ + if (analyze_sbs(mddev)) { + MD_BUG(); + return -EINVAL; + } + + chunk_size = mddev->sb->chunk_size; + pnum = level_to_pers(mddev->sb->level); + + mddev->param.chunk_size = chunk_size; + mddev->param.personality = pnum; + + if (chunk_size > MAX_CHUNK_SIZE) { + printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); + return -EINVAL; + } + /* + * chunk-size has to be a power of 2 and multiples of PAGE_SIZE + */ + if ( (1 << ffz(~chunk_size)) != chunk_size) { + MD_BUG(); + return -EINVAL; + } + if (chunk_size < PAGE_SIZE) { + printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); + return -EINVAL; + } + + if (pnum >= MAX_PERSONALITY) { + MD_BUG(); + return -EINVAL; + } + + if ((pnum != RAID1) && (pnum != LINEAR) && !chunk_size) { + /* + * 'default chunksize' in the old md code used to + * be PAGE_SIZE, baaad. + * we abort here to be on the safe side. We dont + * want to continue the bad practice. + */ + printk(BAD_CHUNKSIZE); + return -EINVAL; + } + + if (!pers[pnum]) + { +#ifdef CONFIG_KMOD + char module_name[80]; + sprintf (module_name, "md-personality-%d", pnum); + request_module (module_name); + if (!pers[pnum]) +#endif + return -EINVAL; + } + + if (device_size_calculation(mddev)) + return -EINVAL; + + /* + * Drop all container device buffers, from now on + * the only valid external interface is through the md + * device. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + fsync_dev(rdev->dev); + invalidate_buffers(rdev->dev); + } + + mddev->pers = pers[pnum]; + + err = mddev->pers->run(mddev); + if (err) { + printk("pers->run() failed ...\n"); + mddev->pers = NULL; + return -EINVAL; + } + + mddev->sb->state &= ~(1 << MD_SB_CLEAN); + md_update_sb(mddev); + + /* + * md_size has units of 1K blocks, which are + * twice as large as sectors. + */ + md_hd_struct[mdidx(mddev)].start_sect = 0; + md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; + + read_ahead[MD_MAJOR] = 1024; + return (0); +} + +#undef TOO_BIG_CHUNKSIZE +#undef BAD_CHUNKSIZE + +#define OUT(x) do { err = (x); goto out; } while (0) + +static int restart_array (mddev_t *mddev) +{ + int err = 0; + + /* + * Complain if it has no devices + */ + if (!mddev->nb_dev) + OUT(-ENXIO); + + if (mddev->pers) { + if (!mddev->ro) + OUT(-EBUSY); + + mddev->ro = 0; + set_device_ro(mddev_to_kdev(mddev), 0); + + printk (KERN_INFO + "md%d switched to read-write mode.\n", mdidx(mddev)); + /* + * Kick recovery or resync if necessary + */ + md_recover_arrays(); + if (mddev->pers->restart_resync) + mddev->pers->restart_resync(mddev); + } else + err = -EINVAL; + +out: + return err; +} + +#define STILL_MOUNTED KERN_WARNING \ +"md: md%d still mounted.\n" + +static int do_md_stop (mddev_t * mddev, int ro) +{ + int err = 0, resync_interrupted = 0; + kdev_t dev = mddev_to_kdev(mddev); + + if (!ro && !fs_may_mount (dev)) { + printk (STILL_MOUNTED, mdidx(mddev)); + OUT(-EBUSY); + } + + /* + * complain if it's already stopped + */ + if (!mddev->nb_dev) + OUT(-ENXIO); + + if (mddev->pers) { + /* + * It is safe to call stop here, it only frees private + * data. Also, it tells us if a device is unstoppable + * (eg. resyncing is in progress) + */ + if (mddev->pers->stop_resync) + if (mddev->pers->stop_resync(mddev)) + resync_interrupted = 1; + + if (mddev->recovery_running) + md_interrupt_thread(md_recovery_thread); + + /* + * This synchronizes with signal delivery to the + * resync or reconstruction thread. It also nicely + * hangs the process if some reconstruction has not + * finished. + */ + down(&mddev->recovery_sem); + up(&mddev->recovery_sem); + + /* + * sync and invalidate buffers because we cannot kill the + * main thread with valid IO transfers still around. + * the kernel lock protects us from new requests being + * added after invalidate_buffers(). + */ + fsync_dev (mddev_to_kdev(mddev)); + fsync_dev (dev); + invalidate_buffers (dev); + + if (ro) { + if (mddev->ro) + OUT(-ENXIO); + mddev->ro = 1; + } else { + if (mddev->ro) + set_device_ro(dev, 0); + if (mddev->pers->stop(mddev)) { + if (mddev->ro) + set_device_ro(dev, 1); + OUT(-EBUSY); + } + if (mddev->ro) + mddev->ro = 0; + } + if (mddev->sb) { + /* + * mark it clean only if there was no resync + * interrupted. + */ + if (!mddev->recovery_running && !resync_interrupted) { + printk("marking sb clean...\n"); + mddev->sb->state |= 1 << MD_SB_CLEAN; + } + md_update_sb(mddev); + } + if (ro) + set_device_ro(dev, 1); + } + + /* + * Free resources if final stop + */ + if (!ro) { + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + free_mddev(mddev); + + printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); + } else + printk (KERN_INFO + "md%d switched to read-only mode.\n", mdidx(mddev)); +out: + return err; +} + +#undef OUT + +/* + * We have to safely support old arrays too. + */ +int detect_old_array (mdp_super_t *sb) +{ + if (sb->major_version > 0) + return 0; + if (sb->minor_version >= 90) + return 0; + + return -EINVAL; +} + + +static void autorun_array (mddev_t *mddev) +{ + mdk_rdev_t *rdev; + struct md_list_head *tmp; + int err; + + if (mddev->disks.prev == &mddev->disks) { + MD_BUG(); + return; + } + + printk("running: "); + + ITERATE_RDEV(mddev,rdev,tmp) { + printk("<%s>", partition_name(rdev->dev)); + } + printk("\nnow!\n"); + + err = do_md_run (mddev); + if (err) { + printk("do_md_run() returned %d\n", err); + /* + * prevent the writeback of an unrunnable array + */ + mddev->sb_dirty = 0; + do_md_stop (mddev, 0); + } +} + +/* + * lets try to run arrays based on all disks that have arrived + * until now. (those are in the ->pending list) + * + * the method: pick the first pending disk, collect all disks with + * the same UUID, remove all from the pending list and put them into + * the 'same_array' list. Then order this list based on superblock + * update time (freshest comes first), kick out 'old' disks and + * compare superblocks. If everything's fine then run it. + */ +static void autorun_devices (void) +{ + struct md_list_head candidates; + struct md_list_head *tmp; + mdk_rdev_t *rdev0, *rdev; + mddev_t *mddev; + kdev_t md_kdev; + + + printk("autorun ...\n"); + while (pending_raid_disks.next != &pending_raid_disks) { + rdev0 = md_list_entry(pending_raid_disks.next, + mdk_rdev_t, pending); + + printk("considering %s ...\n", partition_name(rdev0->dev)); + MD_INIT_LIST_HEAD(&candidates); + ITERATE_RDEV_PENDING(rdev,tmp) { + if (uuid_equal(rdev0, rdev)) { + if (!sb_equal(rdev0->sb, rdev->sb)) { + printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + continue; + } + printk(" adding %s ...\n", partition_name(rdev->dev)); + md_list_del(&rdev->pending); + md_list_add(&rdev->pending, &candidates); + } + } + /* + * now we have a set of devices, with all of them having + * mostly sane superblocks. It's time to allocate the + * mddev. + */ + md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); + mddev = kdev_to_mddev(md_kdev); + if (mddev) { + printk("md%d already running, cannot run %s\n", + mdidx(mddev), partition_name(rdev0->dev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) + export_rdev(rdev); + continue; + } + mddev = alloc_mddev(md_kdev); + printk("created md%d\n", mdidx(mddev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { + bind_rdev_to_array(rdev, mddev); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + autorun_array(mddev); + } + printk("... autorun DONE.\n"); +} + +/* + * import RAID devices based on one partition + * if possible, the array gets run as well. + */ + +#define BAD_VERSION KERN_ERR \ +"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n" + +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_DEVICE KERN_ERR \ +"md: disabled device %s\n" + +#define AUTOADD_FAILED KERN_ERR \ +"md: auto-adding devices to md%d FAILED (error %d).\n" + +#define AUTOADD_FAILED_USED KERN_ERR \ +"md: cannot auto-add device %s to md%d, already used.\n" + +#define AUTORUN_FAILED KERN_ERR \ +"md: auto-running md%d FAILED (error %d).\n" + +#define MDDEV_BUSY KERN_ERR \ +"md: cannot auto-add to md%d, already running.\n" + +#define AUTOADDING KERN_INFO \ +"md: auto-adding devices to md%d, based on %s's superblock.\n" + +#define AUTORUNNING KERN_INFO \ +"md: auto-running md%d.\n" + +static int autostart_array (kdev_t startdev) +{ + int err = -EINVAL, i; + mdp_super_t *sb = NULL; + mdk_rdev_t *start_rdev = NULL, *rdev; + + if (md_import_device(startdev, 1)) { + printk("could not import %s!\n", partition_name(startdev)); + goto abort; + } + + start_rdev = find_rdev_all(startdev); + if (!start_rdev) { + MD_BUG(); + goto abort; + } + if (start_rdev->faulty) { + printk("can not autostart based on faulty %s!\n", + partition_name(startdev)); + goto abort; + } + md_list_add(&start_rdev->pending, &pending_raid_disks); + + sb = start_rdev->sb; + + err = detect_old_array(sb); + if (err) { + printk("array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); + goto abort; + } + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + if (dev == startdev) + continue; + if (md_import_device(dev, 1)) { + printk("could not import %s, trying to run array nevertheless.\n", partition_name(dev)); + continue; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + + /* + * possibly return codes + */ + autorun_devices(); + return 0; + +abort: + if (start_rdev) + export_rdev(start_rdev); + return err; +} + +#undef BAD_VERSION +#undef OUT_OF_MEM +#undef NO_DEVICE +#undef AUTOADD_FAILED_USED +#undef AUTOADD_FAILED +#undef AUTORUN_FAILED +#undef AUTOADDING +#undef AUTORUNNING + +struct { + int set; + int noautodetect; + +} raid_setup_args md__initdata = { 0, 0 }; + +/* + * Searches all registered partitions for autorun RAID arrays + * at boot time. + */ +md__initfunc(void autodetect_raid(void)) +{ +#ifdef CONFIG_AUTODETECT_RAID + struct gendisk *disk; + mdk_rdev_t *rdev; + int i; + + if (raid_setup_args.noautodetect) { + printk(KERN_INFO "skipping autodetection of RAID arrays\n"); + return; + } + printk(KERN_INFO "autodetecting RAID arrays\n"); + + for (disk = gendisk_head ; disk ; disk = disk->next) { + for (i = 0; i < disk->max_p*disk->max_nr; i++) { + kdev_t dev = MKDEV(disk->major,i); + + if (disk->part[i].type == LINUX_OLD_RAID_PARTITION) { + printk(KERN_ALERT +"md: %s's partition type has to be changed from type 0x86 to type 0xfd\n" +" to maintain interoperability with other OSs! Autodetection support for\n" +" type 0x86 will be deleted after some migration timeout. Sorry.\n", + partition_name(dev)); + disk->part[i].type = LINUX_RAID_PARTITION; + } + if (disk->part[i].type != LINUX_RAID_PARTITION) + continue; + + if (md_import_device(dev,1)) { + printk(KERN_ALERT "could not import %s!\n", + partition_name(dev)); + continue; + } + /* + * Sanity checks: + */ + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + continue; + } + if (rdev->faulty) { + MD_BUG(); + continue; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + } + + autorun_devices(); +#endif +} + +static int get_version (void * arg) +{ + mdu_version_t ver; + + ver.major = MD_MAJOR_VERSION; + ver.minor = MD_MINOR_VERSION; + ver.patchlevel = MD_PATCHLEVEL_VERSION; + + if (md_copy_to_user(arg, &ver, sizeof(ver))) + return -EFAULT; + + return 0; +} + +#define SET_FROM_SB(x) info.x = mddev->sb->x +static int get_array_info (mddev_t * mddev, void * arg) +{ + mdu_array_info_t info; + + if (!mddev->sb) + return -EINVAL; + + SET_FROM_SB(major_version); + SET_FROM_SB(minor_version); + SET_FROM_SB(patch_version); + SET_FROM_SB(ctime); + SET_FROM_SB(level); + SET_FROM_SB(size); + SET_FROM_SB(nr_disks); + SET_FROM_SB(raid_disks); + SET_FROM_SB(md_minor); + SET_FROM_SB(not_persistent); + + SET_FROM_SB(utime); + SET_FROM_SB(state); + SET_FROM_SB(active_disks); + SET_FROM_SB(working_disks); + SET_FROM_SB(failed_disks); + SET_FROM_SB(spare_disks); + + SET_FROM_SB(layout); + SET_FROM_SB(chunk_size); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x +static int get_disk_info (mddev_t * mddev, void * arg) +{ + mdu_disk_info_t info; + unsigned int nr; + + if (!mddev->sb) + return -EINVAL; + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + nr = info.number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + SET_FROM_SB(major); + SET_FROM_SB(minor); + SET_FROM_SB(raid_disk); + SET_FROM_SB(state); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_SB(x) mddev->sb->disks[nr].x = info.x + +static int add_new_disk (mddev_t * mddev, void * arg) +{ + int err, size, persistent; + mdu_disk_info_t info; + mdk_rdev_t *rdev; + unsigned int nr; + kdev_t dev; + + if (!mddev->sb) + return -EINVAL; + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + nr = info.number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + dev = MKDEV(info.major,info.minor); + + if (find_rdev_all(dev)) { + printk("device %s already used in a RAID array!\n", + partition_name(dev)); + return -EBUSY; + } + + SET_SB(number); + SET_SB(major); + SET_SB(minor); + SET_SB(raid_disk); + SET_SB(state); + + if ((info.state & (1<old_dev = dev; + rdev->desc_nr = info.number; + + bind_rdev_to_array(rdev, mddev); + + persistent = !mddev->sb->not_persistent; + if (!persistent) + printk("nonpersistent superblock ...\n"); + if (!mddev->sb->chunk_size) + printk("no chunksize?\n"); + + size = calc_dev_size(dev, mddev, persistent); + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + if (!mddev->sb->size || (mddev->sb->size > size)) + mddev->sb->size = size; + } + + /* + * sync all other superblocks with the main superblock + */ + sync_sbs(mddev); + + return 0; +} +#undef SET_SB - realdev->size=blk_size[MAJOR(dev)][MINOR(dev)]; +static int hot_remove_disk (mddev_t * mddev, kdev_t dev) +{ + int err; + mdk_rdev_t *rdev; + mdp_disk_t *disk; - if (hot_add) { - /* - * Check the superblock for consistency. - * The personality itself has to check whether it's getting - * added with the proper flags. The personality has to be - * checked too. ;) - */ - if (analyze_one_sb (realdev)) - return -EINVAL; + if (!mddev->pers) + return -ENODEV; + + printk("trying to remove %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) + return -ENXIO; + + if (rdev->desc_nr == -1) { + MD_BUG(); + return -EINVAL; + } + disk = &mddev->sb->disks[rdev->desc_nr]; + if (disk_active(disk)) + goto busy; + if (disk_removed(disk)) { + MD_BUG(); + return -EINVAL; + } + + err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); + if (err == -EBUSY) + goto busy; + if (err) { + MD_BUG(); + return -EINVAL; + } + + remove_descriptor(disk, mddev->sb); + kick_rdev_from_array(rdev); + mddev->sb_dirty = 1; + md_update_sb(mddev); + + return 0; +busy: + printk("cannot remove active disk %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + return -EBUSY; +} + +static int hot_add_disk (mddev_t * mddev, kdev_t dev) +{ + int i, err, persistent; + unsigned int size; + mdk_rdev_t *rdev; + mdp_disk_t *disk; + + if (!mddev->pers) + return -ENODEV; + + printk("trying to hot-add %s to md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + persistent = !mddev->sb->not_persistent; + size = calc_dev_size(dev, mddev, persistent); + + if (size < mddev->sb->size) { + printk("md%d: disk size %d blocks < array size %d\n", + mdidx(mddev), size, mddev->sb->size); + return -ENOSPC; + } + + rdev = find_rdev(mddev, dev); + if (rdev) + return -EBUSY; + + err = md_import_device (dev, 0); + if (err) { + printk("md: error, md_import_device() returned %d\n", err); + return -EINVAL; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + return -EINVAL; + } + if (rdev->faulty) { + printk("md: can not hot-add faulty %s disk to md%d!\n", + partition_name(dev), mdidx(mddev)); + err = -EINVAL; + goto abort_export; + } + bind_rdev_to_array(rdev, mddev); + + /* + * The rest should better be atomic, we can have disk failures + * noticed in interrupt contexts ... + */ + cli(); + rdev->old_dev = dev; + rdev->size = size; + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + disk = mddev->sb->disks + mddev->sb->raid_disks; + for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { + disk = mddev->sb->disks + i; + + if (!disk->major && !disk->minor) + break; + if (disk_removed(disk)) + break; + } + if (i == MD_SB_DISKS) { + sti(); + printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); + err = -EBUSY; + goto abort_unbind_export; + } + + if (disk_removed(disk)) { /* - * hot_add has to bump up nb_dev itself + * reuse slot */ - if (md_dev[minor].pers->hot_add_disk (&md_dev[minor], dev)) { - /* - * FIXME: here we should free up the inode and stuff - */ - printk ("FIXME\n"); - return -EINVAL; + if (disk->number != i) { + sti(); + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; } - } else - md_dev[minor].nb_dev++; + } else { + disk->number = i; + } - printk ("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor); - return (0); + disk->raid_disk = disk->number; + disk->major = MAJOR(dev); + disk->minor = MINOR(dev); + + if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { + sti(); + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; + } + + mark_disk_spare(disk); + mddev->sb->nr_disks++; + mddev->sb->spare_disks++; + mddev->sb->working_disks++; + + mddev->sb_dirty = 1; + + sti(); + md_update_sb(mddev); + + /* + * Kick recovery, maybe this spare has to be added to the + * array immediately. + */ + md_recover_arrays(); + + return 0; + +abort_unbind_export: + unbind_rdev_from_array(rdev); + +abort_export: + export_rdev(rdev); + return err; +} + +#define SET_SB(x) mddev->sb->x = info.x +static int set_array_info (mddev_t * mddev, void * arg) +{ + mdu_array_info_t info; + + if (mddev->sb) { + printk("array md%d already has a superblock!\n", + mdidx(mddev)); + return -EBUSY; + } + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + if (alloc_array_sb(mddev)) + return -ENOMEM; + + mddev->sb->major_version = MD_MAJOR_VERSION; + mddev->sb->minor_version = MD_MINOR_VERSION; + mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; + mddev->sb->ctime = CURRENT_TIME; + + SET_SB(level); + SET_SB(size); + SET_SB(nr_disks); + SET_SB(raid_disks); + SET_SB(md_minor); + SET_SB(not_persistent); + + SET_SB(state); + SET_SB(active_disks); + SET_SB(working_disks); + SET_SB(failed_disks); + SET_SB(spare_disks); + + SET_SB(layout); + SET_SB(chunk_size); + + mddev->sb->md_magic = MD_SB_MAGIC; + + /* + * Generate a 128 bit UUID + */ + get_random_bytes(&mddev->sb->set_uuid0, 4); + get_random_bytes(&mddev->sb->set_uuid1, 4); + get_random_bytes(&mddev->sb->set_uuid2, 4); + get_random_bytes(&mddev->sb->set_uuid3, 4); + + return 0; +} +#undef SET_SB + +static int set_disk_info (mddev_t * mddev, void * arg) +{ + printk("not yet"); + return -EINVAL; +} + +static int clear_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int write_raid_info (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int protect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int unprotect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; } static int md_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int minor, err; - struct hd_geometry *loc = (struct hd_geometry *) arg; + unsigned int minor; + int err = 0; + struct hd_geometry *loc = (struct hd_geometry *) arg; + mddev_t *mddev = NULL; + kdev_t dev; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; + if (!md_capable_admin()) + return -EACCES; - if (((minor=MINOR(inode->i_rdev)) & 0x80) && - (minor & 0x7f) < MAX_PERSONALITY && - pers[minor & 0x7f] && - pers[minor & 0x7f]->ioctl) - return (pers[minor & 0x7f]->ioctl (inode, file, cmd, arg)); - - if (minor >= MAX_MD_DEV) - return -EINVAL; + dev = inode->i_rdev; + minor = MINOR(dev); + if (minor >= MAX_MD_DEVS) + return -EINVAL; - switch (cmd) - { - case REGISTER_DEV: - return do_md_add (minor, to_kdev_t ((dev_t) arg)); + /* + * Commands dealing with the RAID driver but not any + * particular array: + */ + switch (cmd) + { + case RAID_VERSION: + err = get_version((void *)arg); + goto done; + + case PRINT_RAID_DEBUG: + err = 0; + md_print_devices(); + goto done_unlock; + + case BLKGETSIZE: /* Return device size */ + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user(md_hd_struct[minor].nr_sects, + (long *) arg); + goto done; - case START_MD: - return do_md_run (minor, (int) arg); + case BLKFLSBUF: + fsync_dev(dev); + invalidate_buffers(dev); + goto done; - case STOP_MD: - return do_md_stop (minor, inode); - - case BLKGETSIZE: /* Return device size */ - if (!arg) return -EINVAL; - err = put_user (md_hd_struct[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - if (err) - return err; - break; - - case BLKFLSBUF: - fsync_dev (inode->i_rdev); - invalidate_buffers (inode->i_rdev); - break; - - case BLKRASET: - if (arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - - case BLKRAGET: - if (!arg) return -EINVAL; - err = put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - if (err) - return err; - break; - - /* We have a problem here : there is no easy way to give a CHS - virtual geometry. We currently pretend that we have a 2 heads - 4 sectors (with a BIG number of cylinders...). This drives dosfs - just mad... ;-) */ - - case HDIO_GETGEO: - if (!loc) return -EINVAL; - err = put_user (2, (char *) &loc->heads); - if (err) - return err; - err = put_user (4, (char *) &loc->sectors); - if (err) - return err; - err = put_user (md_hd_struct[minor].nr_sects/8, (short *) &loc->cylinders); - if (err) - return err; - err = put_user (md_hd_struct[MINOR(inode->i_rdev)].start_sect, - (long *) &loc->start); - if (err) - return err; - break; - - RO_IOCTLS(inode->i_rdev,arg); + case BLKRASET: + if (arg > 0xff) { + err = -EINVAL; + goto abort; + } + read_ahead[MAJOR(dev)] = arg; + goto done; - default: - return -EINVAL; - } + case BLKRAGET: + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user (read_ahead[ + MAJOR(dev)], (long *) arg); + goto done; + default: + } + + /* + * Commands creating/starting a new array: + */ + + mddev = kdev_to_mddev(dev); + + switch (cmd) + { + case SET_ARRAY_INFO: + case START_ARRAY: + if (mddev) { + printk("array md%d already exists!\n", + mdidx(mddev)); + err = -EEXIST; + goto abort; + } + default: + } + + switch (cmd) + { + case SET_ARRAY_INFO: + mddev = alloc_mddev(dev); + if (!mddev) { + err = -ENOMEM; + goto abort; + } + /* + * alloc_mddev() should possibly self-lock. + */ + err = lock_mddev(mddev); + if (err) { + printk("ioctl, reason %d, cmd %d\n",err, cmd); + goto abort; + } + err = set_array_info(mddev, (void *)arg); + goto done_unlock; + + case START_ARRAY: + /* + * possibly make it lock the array ... + */ + err = autostart_array((kdev_t)arg); + if (err) { + printk("autostart %s failed!\n", + partition_name((kdev_t)arg)); + } + goto done; + + default: + } + + /* + * Commands querying/configuring an existing array: + */ + + if (!mddev) { + err = -ENODEV; + goto abort; + } + err = lock_mddev(mddev); + if (err) { + printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); + goto abort; + } + + /* + * Commands even a read-only array can execute: + */ + switch (cmd) + { + case GET_ARRAY_INFO: + err = get_array_info(mddev, (void *)arg); + goto done_unlock; + + case GET_DISK_INFO: + err = get_disk_info(mddev, (void *)arg); + goto done_unlock; + + case RESTART_ARRAY_RW: + err = restart_array(mddev); + goto done_unlock; + + case STOP_ARRAY: + err = do_md_stop (mddev, 0); + goto done_unlock; + + case STOP_ARRAY_RO: + err = do_md_stop (mddev, 1); + goto done_unlock; + + /* + * We have a problem here : there is no easy way to give a CHS + * virtual geometry. We currently pretend that we have a 2 heads + * 4 sectors (with a BIG number of cylinders...). This drives + * dosfs just mad... ;-) + */ + case HDIO_GETGEO: + if (!loc) { + err = -EINVAL; + goto abort_unlock; + } + err = md_put_user (2, (char *) &loc->heads); + if (err) + goto abort_unlock; + err = md_put_user (4, (char *) &loc->sectors); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, + (short *) &loc->cylinders); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[minor].start_sect, + (long *) &loc->start); + goto done_unlock; + } + + /* + * The remaining ioctls are changing the state of the + * superblock, so we do not allow read-only arrays + * here: + */ + if (mddev->ro) { + err = -EROFS; + goto abort_unlock; + } - return (0); + switch (cmd) + { + case CLEAR_ARRAY: + err = clear_array(mddev); + goto done_unlock; + + case ADD_NEW_DISK: + err = add_new_disk(mddev, (void *)arg); + goto done_unlock; + + case HOT_REMOVE_DISK: + err = hot_remove_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case HOT_ADD_DISK: + err = hot_add_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case SET_DISK_INFO: + err = set_disk_info(mddev, (void *)arg); + goto done_unlock; + + case WRITE_RAID_INFO: + err = write_raid_info(mddev); + goto done_unlock; + + case UNPROTECT_ARRAY: + err = unprotect_array(mddev); + goto done_unlock; + + case PROTECT_ARRAY: + err = protect_array(mddev); + goto done_unlock; + + case RUN_ARRAY: + { + mdu_param_t param; + + err = md_copy_from_user(¶m, (mdu_param_t *)arg, + sizeof(param)); + if (err) + goto abort_unlock; + + err = do_md_run (mddev); + /* + * we have to clean up the mess if + * the array cannot be run for some + * reason ... + */ + if (err) { + mddev->sb_dirty = 0; + do_md_stop (mddev, 0); + } + goto done_unlock; + } + + default: + printk(KERN_WARNING "%s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); + err = -EINVAL; + goto abort_unlock; + } + +done_unlock: +abort_unlock: + if (mddev) + unlock_mddev(mddev); + else + printk("huh11?\n"); + + return err; +done: + if (err) + printk("huh12?\n"); +abort: + return err; } + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) + static int md_open (struct inode *inode, struct file *file) { - int minor=MINOR(inode->i_rdev); + /* + * Always succeed + */ + return (0); +} - md_dev[minor].busy++; - return (0); /* Always succeed */ +static void md_release (struct inode *inode, struct file *file) +{ + sync_dev(inode->i_rdev); } -static int md_release (struct inode *inode, struct file *file) +static int md_read (struct inode *inode, struct file *file, + char *buf, int count) +{ + mddev_t *mddev = kdev_to_mddev(MD_FILE_TO_INODE(file)->i_rdev); + + if (!mddev || !mddev->pers) + return -ENXIO; + + return block_read (inode, file, buf, count); +} + +static int md_write (struct inode *inode, struct file *file, + const char *buf, int count) +{ + mddev_t *mddev = kdev_to_mddev(MD_FILE_TO_INODE(file)->i_rdev); + + if (!mddev || !mddev->pers) + return -ENXIO; + + return block_write (inode, file, buf, count); +} + +static struct file_operations md_fops= { - int minor=MINOR(inode->i_rdev); + NULL, + md_read, + md_write, + NULL, + NULL, + md_ioctl, + NULL, + md_open, + md_release, + block_fsync +}; + +#else - sync_dev (inode->i_rdev); - md_dev[minor].busy--; - return 0; +static int md_open (struct inode *inode, struct file *file) +{ + /* + * Always succeed + */ + return (0); } +static int md_release (struct inode *inode, struct file *file) +{ + sync_dev(inode->i_rdev); + return 0; +} static ssize_t md_read (struct file *file, char *buf, size_t count, loff_t *ppos) { - int minor=MINOR(file->f_dentry->d_inode->i_rdev); + mddev_t *mddev = kdev_to_mddev(MD_FILE_TO_INODE(file)->i_rdev); - if (!md_dev[minor].pers) /* Check if device is being run */ - return -ENXIO; + if (!mddev || !mddev->pers) + return -ENXIO; - return block_read(file, buf, count, ppos); + return block_read(file, buf, count, ppos); } static ssize_t md_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { - int minor=MINOR(file->f_dentry->d_inode->i_rdev); + mddev_t *mddev = kdev_to_mddev(MD_FILE_TO_INODE(file)->i_rdev); - if (!md_dev[minor].pers) /* Check if device is being run */ - return -ENXIO; + if (!mddev || !mddev->pers) + return -ENXIO; - return block_write(file, buf, count, ppos); + return block_write(file, buf, count, ppos); } static struct file_operations md_fops= { - NULL, - md_read, - md_write, - NULL, - NULL, - md_ioctl, - NULL, - md_open, - NULL, - md_release, - block_fsync + NULL, + md_read, + md_write, + NULL, + NULL, + md_ioctl, + NULL, + md_open, + NULL, + md_release, + block_fsync }; -int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size) +#endif + +int md_map (kdev_t dev, kdev_t *rdev, + unsigned long *rsector, unsigned long size) { - if ((unsigned int) minor >= MAX_MD_DEV) - { - printk ("Bad md device %d\n", minor); - return (-1); - } - - if (!md_dev[minor].pers) - { - printk ("Oops ! md%d not running, giving up !\n", minor); - return (-1); - } + int err; + mddev_t *mddev = kdev_to_mddev(dev); - return (md_dev[minor].pers->map(md_dev+minor, rdev, rsector, size)); + if (!mddev || !mddev->pers) { + err = -ENXIO; + goto out; + } + + err = mddev->pers->map(mddev, dev, rdev, rsector, size); +out: + return err; } -int md_make_request (int minor, int rw, struct buffer_head * bh) +int md_make_request (struct buffer_head * bh, int rw) { - if (md_dev [minor].pers->make_request) { - if (buffer_locked(bh)) - return 0; + int err; + mddev_t *mddev = kdev_to_mddev(bh->b_dev); + + if (!mddev || !mddev->pers) { + err = -ENXIO; + goto out; + } + + if (mddev->pers->make_request) { + if (buffer_locked(bh)) { + err = 0; + goto out; + } set_bit(BH_Lock, &bh->b_state); if (rw == WRITE || rw == WRITEA) { if (!buffer_dirty(bh)) { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; + bh->b_end_io(bh, buffer_uptodate(bh)); + err = 0; + goto out; } } if (rw == READ || rw == READA) { if (buffer_uptodate(bh)) { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; + bh->b_end_io(bh, buffer_uptodate(bh)); + err = 0; + goto out; } } - return (md_dev[minor].pers->make_request(md_dev+minor, rw, bh)); + err = mddev->pers->make_request(mddev, rw, bh); } else { make_request (MAJOR(bh->b_rdev), rw, bh); - return 0; + err = 0; } +out: + return err; } static void do_md_request (void) { - printk ("Got md request, not good..."); - return; + printk(KERN_ALERT "Got md request, not good..."); + return; +} + +int md_thread(void * arg) +{ + mdk_thread_t *thread = arg; + + md_lock_kernel(); + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* + * Detach thread + */ + sys_setsid(); + sprintf(current->comm, thread->name); + md_init_signals(); + md_flush_signals(); + thread->tsk = current; + + /* + * md_thread is a 'system-thread', it's priority should be very + * high. We avoid resource deadlocks individually in each + * raid personality. (RAID5 does preallocation) We also use RR and + * the very same RT priority as kswapd, thus we will never get + * into a priority inversion deadlock. + * + * we definitely have to have equal or higher priority than + * bdflush, otherwise bdflush will deadlock if there are too + * many dirty RAID5 blocks. + */ + current->policy = SCHED_OTHER; + current->priority = 40; + + up(thread->sem); + + for (;;) { + cli(); + if (!test_bit(THREAD_WAKEUP, &thread->flags)) { + if (!thread->run) + break; + interruptible_sleep_on(&thread->wqueue); + } + sti(); + clear_bit(THREAD_WAKEUP, &thread->flags); + if (thread->run) { + thread->run(thread->data); + run_task_queue(&tq_disk); + } + if (md_signal_pending(current)) { + printk("%8s(%d) flushing signals.\n", current->comm, + current->pid); + md_flush_signals(); + } + } + sti(); + up(thread->sem); + return 0; } -void md_wakeup_thread(struct md_thread *thread) +void md_wakeup_thread(mdk_thread_t *thread) { set_bit(THREAD_WAKEUP, &thread->flags); wake_up(&thread->wqueue); } -struct md_thread *md_register_thread (void (*run) (void *), void *data) +mdk_thread_t *md_register_thread (void (*run) (void *), + void *data, const char *name) { - struct md_thread *thread = (struct md_thread *) - kmalloc(sizeof(struct md_thread), GFP_KERNEL); + mdk_thread_t *thread; int ret; struct semaphore sem = MUTEX_LOCKED; - if (!thread) return NULL; + thread = (mdk_thread_t *) kmalloc + (sizeof(mdk_thread_t), GFP_KERNEL); + if (!thread) + return NULL; - memset(thread, 0, sizeof(struct md_thread)); + memset(thread, 0, sizeof(mdk_thread_t)); init_waitqueue(&thread->wqueue); thread->sem = &sem; thread->run = run; thread->data = data; + thread->name = name; ret = kernel_thread(md_thread, thread, 0); if (ret < 0) { kfree(thread); @@ -836,270 +2997,405 @@ return thread; } -void md_unregister_thread (struct md_thread *thread) +void md_interrupt_thread (mdk_thread_t *thread) +{ + if (!thread->tsk) { + MD_BUG(); + return; + } + printk("interrupting MD-thread pid %d\n", thread->tsk->pid); + send_sig(SIGKILL, thread->tsk, 1); +} + +void md_unregister_thread (mdk_thread_t *thread) { struct semaphore sem = MUTEX_LOCKED; thread->sem = &sem; thread->run = NULL; - if (thread->tsk) - printk("Killing md_thread %d %p %s\n", - thread->tsk->pid, thread->tsk, thread->tsk->comm); - else - printk("Aiee. md_thread has 0 tsk\n"); - send_sig(SIGKILL, thread->tsk, 1); - printk("downing on %p\n", &sem); + thread->name = NULL; + if (!thread->tsk) { + MD_BUG(); + return; + } + md_interrupt_thread(thread); down(&sem); } -#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) - -int md_thread(void * arg) +void md_recover_arrays (void) { - struct md_thread *thread = arg; - - lock_kernel(); - exit_mm(current); - exit_files(current); - exit_fs(current); - - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "md_thread"); - siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); - thread->tsk = current; - up(thread->sem); - - for (;;) { - cli(); - if (!test_bit(THREAD_WAKEUP, &thread->flags)) { - do { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&thread->wqueue); - cli(); - if (test_bit(THREAD_WAKEUP, &thread->flags)) - break; - if (!thread->run) { - sti(); - up(thread->sem); - return 0; - } - } while (signal_pending(current)); - } - sti(); - clear_bit(THREAD_WAKEUP, &thread->flags); - if (thread->run) { - thread->run(thread->data); - run_task_queue(&tq_disk); - } + if (!md_recovery_thread) { + MD_BUG(); + return; } + md_wakeup_thread(md_recovery_thread); } -EXPORT_SYMBOL(md_size); -EXPORT_SYMBOL(md_maxreadahead); -EXPORT_SYMBOL(register_md_personality); -EXPORT_SYMBOL(unregister_md_personality); -EXPORT_SYMBOL(partition_name); -EXPORT_SYMBOL(md_dev); -EXPORT_SYMBOL(md_error); -EXPORT_SYMBOL(md_register_thread); -EXPORT_SYMBOL(md_unregister_thread); -EXPORT_SYMBOL(md_update_sb); -EXPORT_SYMBOL(md_map); -EXPORT_SYMBOL(md_wakeup_thread); -EXPORT_SYMBOL(md_do_sync); -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_md = { - PROC_MD, 6, "mdstat", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, -}; +int md_error (kdev_t dev, kdev_t rdev) +{ + mddev_t *mddev = kdev_to_mddev(dev); + mdk_rdev_t * rrdev; + int rc; + + if (!mddev) { + MD_BUG(); + return 0; + } + rrdev = find_rdev(mddev, rdev); + mark_rdev_faulty(rrdev); + /* + * if recovery was running, stop it now. + */ + if (mddev->pers->stop_resync) + mddev->pers->stop_resync(mddev); + if (mddev->pers->error_handler) { + rc = mddev->pers->error_handler(mddev, rdev); + md_recover_arrays(); + return rc; + } +#if 0 + /* + * Drop all buffers in the failed array. + * _not_. This is called from IRQ handlers ... + */ + invalidate_buffers(rdev); #endif + return 0; +} -static void md_geninit (struct gendisk *gdisk) +static int status_unused (char * page) { - int i; - - for(i=0;isame_set.next && !rdev->same_set.prev) { + /* + * The device is not yet used by any array. + */ + i++; + sz += sprintf(page + sz, "%s ", + partition_name(rdev->dev)); + } + } + if (!i) + sz += sprintf(page + sz, ""); + + sz += sprintf(page + sz, "\n"); + return sz; } -int md_error (kdev_t mddev, kdev_t rdev) + +static int status_resync (char * page, mddev_t * mddev) { - unsigned int minor = MINOR (mddev); - int rc; + int sz = 0; + unsigned int blocksize, max_blocks, resync, res, dt, tt, et; + + resync = mddev->curr_resync; + blocksize = blksize_size[MD_MAJOR][mdidx(mddev)]; + max_blocks = blk_size[MD_MAJOR][mdidx(mddev)] / (blocksize >> 10); + + /* + * Should not happen. + */ + if (!max_blocks) { + MD_BUG(); + return 0; + } + res = resync*100/max_blocks; + if (!mddev->recovery_running) + /* + * true resync + */ + sz += sprintf(page + sz, " resync=%u%%", res); + else + /* + * recovery ... + */ + sz += sprintf(page + sz, " recovery=%u%%", res); + + /* + * We do not want to overflow, so the order of operands and + * the * 100 / 100 trick are important. We do a +1 to be + * safe against division by zero. We only estimate anyway. + * + * dt: time until now + * tt: total time + * et: estimated finish time + */ + dt = ((jiffies - mddev->resync_start) / HZ); + tt = (dt * (max_blocks / (resync/100+1)))/100; + if (tt > dt) + et = tt - dt; + else + /* + * ignore rounding effects near finish time + */ + et = 0; + + sz += sprintf(page + sz, " finish=%u.%umin", et / 60, (et % 60)/6); - if (MAJOR(mddev) != MD_MAJOR || minor > MAX_MD_DEV) - panic ("md_error gets unknown device\n"); - if (!md_dev [minor].pers) - panic ("md_error gets an error for an unknown device\n"); - if (md_dev [minor].pers->error_handler) { - rc = md_dev [minor].pers->error_handler (md_dev+minor, rdev); -#if SUPPORT_RECONSTRUCTION - md_wakeup_thread(md_sync_thread); -#endif /* SUPPORT_RECONSTRUCTION */ - return rc; - } - return 0; + return sz; } int get_md_status (char *page) { - int sz=0, i, j, size; - - sz+=sprintf( page+sz, "Personalities : "); - for (i=0; iname); - - page[sz-1]='\n'; - - sz+=sprintf (page+sz, "read_ahead "); - if (read_ahead[MD_MAJOR]==INT_MAX) - sz+=sprintf (page+sz, "not set\n"); - else - sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); + int sz = 0, j, size; + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev; + mddev_t *mddev; + + sz += sprintf(page + sz, "Personalities : "); + for (j = 0; j < MAX_PERSONALITY; j++) + if (pers[j]) + sz += sprintf(page+sz, "[%s] ", pers[j]->name); + + sz += sprintf(page+sz, "\n"); + + + sz += sprintf(page+sz, "read_ahead "); + if (read_ahead[MD_MAJOR] == INT_MAX) + sz += sprintf(page+sz, "not set\n"); + else + sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); - for (i=0; iname); + ITERATE_MDDEV(mddev,tmp) { + sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), + mddev->pers ? "" : "in"); + if (mddev->pers) { + if (mddev->ro) + sz += sprintf(page + sz, " (read-only)"); + sz += sprintf(page + sz, " %s", mddev->pers->name); + } - size=0; - for (j=0; jdev), rdev->desc_nr); + if (rdev->faulty) { + sz += sprintf(page + sz, "(F)"); + continue; + } + size += rdev->size; + } - if (md_dev[i].nb_dev) { - if (md_dev[i].pers) - sz+=sprintf (page+sz, " %d blocks", md_size[i]); - else - sz+=sprintf (page+sz, " %d blocks", size); - } + if (mddev->nb_dev) { + if (mddev->pers) + sz += sprintf(page + sz, " %d blocks", + md_size[mdidx(mddev)]); + else + sz += sprintf(page + sz, " %d blocks", size); + } - if (!md_dev[i].pers) - { - sz+=sprintf (page+sz, "\n"); - continue; - } + if (!mddev->pers) { + sz += sprintf(page+sz, "\n"); + continue; + } - if (md_dev[i].pers->max_invalid_dev) - sz+=sprintf (page+sz, " maxfault=%ld", MAX_FAULT(md_dev+i)); + sz += mddev->pers->status (page+sz, mddev); - sz+=md_dev[i].pers->status (page+sz, i, md_dev+i); - sz+=sprintf (page+sz, "\n"); - } + if (mddev->curr_resync) + sz += status_resync (page+sz, mddev); + else { + if (md_atomic_read(&mddev->resync_sem.count) != 1) + sz += sprintf(page + sz, " resync=DELAYED"); + } + sz += sprintf(page + sz, "\n"); + } + sz += status_unused (page + sz); - return (sz); + return (sz); } -int register_md_personality (int p_num, struct md_personality *p) +int register_md_personality (int pnum, mdk_personality_t *p) { - int i=(p_num >> PERSONALITY_SHIFT); - - if (i >= MAX_PERSONALITY) - return -EINVAL; + if (pnum >= MAX_PERSONALITY) + return -EINVAL; - if (pers[i]) - return -EBUSY; + if (pers[pnum]) + return -EBUSY; - pers[i]=p; - printk ("%s personality registered\n", p->name); - return 0; + pers[pnum] = p; + printk(KERN_INFO "%s personality registered\n", p->name); + return 0; } -int unregister_md_personality (int p_num) +int unregister_md_personality (int pnum) { - int i=(p_num >> PERSONALITY_SHIFT); - - if (i >= MAX_PERSONALITY) - return -EINVAL; + if (pnum >= MAX_PERSONALITY) + return -EINVAL; - printk ("%s personality unregistered\n", pers[i]->name); - pers[i]=NULL; - return 0; + printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); + pers[pnum] = NULL; + return 0; } -static md_descriptor_t *get_spare(struct md_dev *mddev) +static mdp_disk_t *get_spare(mddev_t *mddev) { - int i; - md_superblock_t *sb = mddev->sb; - md_descriptor_t *descriptor; - struct real_dev *realdev; - - for (i = 0; i < mddev->nb_dev; i++) { - realdev = &mddev->devices[i]; - if (!realdev->sb) + mdp_super_t *sb = mddev->sb; + mdp_disk_t *disk; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + if (!rdev->sb) { + MD_BUG(); continue; - descriptor = &sb->disks[realdev->sb->descriptor.number]; - if (descriptor->state & (1 << MD_FAULTY_DEVICE)) + } + disk = &sb->disks[rdev->desc_nr]; + if (disk_faulty(disk)) { + MD_BUG(); continue; - if (descriptor->state & (1 << MD_ACTIVE_DEVICE)) + } + if (disk_active(disk)) continue; - return descriptor; + return disk; } return NULL; } +static int is_mddev_idle (mddev_t *mddev) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; + int idle; + unsigned long curr_events; + + idle = 1; + ITERATE_RDEV(mddev,rdev,tmp) { + curr_events = io_events[MAJOR(rdev->dev)]; + + if (curr_events != rdev->last_events) { +// printk("!I(%d)", curr_events-rdev->last_events); + rdev->last_events = curr_events; + idle = 0; + } + } + return idle; +} + /* * parallel resyncing thread. - * - * FIXME: - make it abort with a dirty array on mdstop, now it just blocks - * - fix read error handing */ -int md_do_sync(struct md_dev *mddev) +/* + * Determine correct block size for this device. + */ +unsigned int device_bsize (kdev_t dev) +{ + unsigned int i, correct_size; + + correct_size = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)]) { + i = blksize_size[MAJOR(dev)][MINOR(dev)]; + if (i) + correct_size = i; + } + + return correct_size; +} + +static struct wait_queue *resync_wait = (struct wait_queue *)NULL; + +#define RA_ORDER (1) +#define RA_PAGE_SIZE (PAGE_SIZE*(1<resync_sem); + if (err) + goto out_nolock; + +recheck: + serialize = 0; + ITERATE_MDDEV(mddev2,tmp) { + if (mddev2 == mddev) + continue; + if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { + printk(KERN_INFO "md: serializing resync, md%d has overlapping physical units with md%d!\n", mdidx(mddev), mdidx(mddev2)); + serialize = 1; + break; + } + } + if (serialize) { + interruptible_sleep_on(&resync_wait); + if (md_signal_pending(current)) { + md_flush_signals(); + err = -EINTR; + goto out; + } + goto recheck; + } + + mddev->curr_resync = 1; - blocksize = blksize_size[major][minor]; + blocksize = device_bsize(read_disk); max_blocks = blk_size[major][minor] / (blocksize >> 10); - printk("... resync log\n"); - printk(" .... mddev->nb_dev: %d\n", mddev->nb_dev); - printk(" .... raid array: %s\n", kdevname(read_disk)); - printk(" .... max_blocks: %d blocksize: %d\n", max_blocks, blocksize); - printk("md: syncing RAID array %s\n", kdevname(read_disk)); + printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); + printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec.\n", + sysctl_speed_limit); + printk(KERN_INFO "md: using maximum available idle IO bandwith for reconstruction.\n"); + + /* + * Resync has low priority. + */ + current->priority = 1; + + is_mddev_idle(mddev); /* this also initializes IO event counters */ + starttime = jiffies; + mddev->resync_start = starttime; - mddev->busy++; + /* + * Tune reconstruction: + */ + window = md_maxreadahead[mdidx(mddev)]/1024; + nr_blocks = window / (blocksize >> 10); + if (!nr_blocks || (nr_blocks > MAX_NR_BLOCKS)) + nr_blocks = MAX_NR_BLOCKS; + printk(KERN_INFO "md: using %dk window.\n",window); - starttime=jiffies; - for (j = 0; j < max_blocks; j++) { + for (j = 0; j < max_blocks; j += nr_blocks) { + if (j) + mddev->curr_resync = j; /* * B careful. When some1 mounts a non-'blocksize' filesystem * then we get the blocksize changed right under us. Go deal * with it transparently, recalculate 'blocksize', 'j' and * 'max_blocks': */ - curr_bsize = blksize_size[major][minor]; + curr_bsize = device_bsize(read_disk); if (curr_bsize != blocksize) { - diff_blocksize: + printk(KERN_INFO "md%d: blocksize changed\n", + mdidx(mddev)); +retry_read: if (curr_bsize > blocksize) /* * this is safe, rounds downwards. @@ -1109,114 +3405,384 @@ j *= blocksize/curr_bsize; blocksize = curr_bsize; + nr_blocks = window / (blocksize >> 10); + if (!nr_blocks || (nr_blocks > MAX_NR_BLOCKS)) + nr_blocks = MAX_NR_BLOCKS; max_blocks = blk_size[major][minor] / (blocksize >> 10); - } - if ((bh = breada (read_disk, j, blocksize, j * blocksize, - max_blocks * blocksize)) != NULL) { - mark_buffer_dirty(bh, 1); - brelse(bh); - } else { + printk("nr_blocks changed to %d (blocksize %d, j %d, max_blocks %d)\n", + nr_blocks, blocksize, j, max_blocks); /* - * FIXME: Ugly, but set_blocksize() isnt safe ... + * We will retry the current block-group */ - curr_bsize = blksize_size[major][minor]; - if (curr_bsize != blocksize) - goto diff_blocksize; + } - /* - * It's a real read problem. FIXME, handle this - * a better way. - */ - printk ( KERN_ALERT - "read error, stopping reconstruction.\n"); - mddev->busy--; - return 1; + /* + * Cleanup routines expect this + */ + for (k = 0; k < nr_blocks; k++) + bh[k] = NULL; + + chunk = nr_blocks; + if (chunk > max_blocks-j) + chunk = max_blocks-j; + + /* + * request buffer heads ... + */ + for (i = 0; i < chunk; i++) { + bh[i] = getblk (read_disk, j+i, blocksize); + if (!bh[i]) + goto read_error; + if (!buffer_dirty(bh[i])) + mark_buffer_lowprio(bh[i]); } /* - * Let's sleep some if we are faster than our speed limit: + * read buffer heads ... */ - while (blocksize*j/(jiffies-starttime+1)*HZ/1024 > SPEED_LIMIT) - { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + ll_rw_block (READ, chunk, bh); + run_task_queue(&tq_disk); + + /* + * verify that all of them are OK ... + */ + for (i = 0; i < chunk; i++) { + ii = chunk-i-1; + wait_on_buffer(bh[ii]); + if (!buffer_uptodate(bh[ii])) + goto read_error; + } + +retry_write: + for (i = 0; i < chunk; i++) + mark_buffer_dirty_lowprio(bh[i]); + + ll_rw_block(WRITE, chunk, bh); + run_task_queue(&tq_disk); + + for (i = 0; i < chunk; i++) { + ii = chunk-i-1; + wait_on_buffer(bh[ii]); + + if (spare && disk_faulty(spare)) { + for (k = 0; k < chunk; k++) + brelse(bh[k]); + printk(" \n "); + err = -EIO; + goto out; + } + + if (!buffer_uptodate(bh[ii])) { + curr_bsize = device_bsize(read_disk); + if (curr_bsize != blocksize) { + printk(KERN_INFO + "md%d: blocksize changed during write\n", + mdidx(mddev)); + for (k = 0; k < chunk; k++) + if (bh[k]) { + if (buffer_lowprio(bh[k])) + mark_buffer_clean(bh[k]); + brelse(bh[k]); + } + goto retry_read; + } + printk(" BAD WRITE %8d>\n", j); + /* + * Ouch, write error, retry or bail out. + */ + if (max_write_errors) { + max_write_errors--; + printk ( KERN_WARNING "md%d: write error while reconstructing, at block %u(%d).\n", mdidx(mddev), j, blocksize); + goto retry_write; + } + printk ( KERN_ALERT + "too many write errors, stopping reconstruction.\n"); + for (k = 0; k < chunk; k++) + if (bh[k]) { + if (buffer_lowprio(bh[k])) + mark_buffer_clean(bh[k]); + brelse(bh[k]); + } + err = -EIO; + goto out; + } } /* - * FIXME: put this status bar thing into /proc + * This is the normal 'everything went OK' case + * do a 'free-behind' logic, we sure dont need + * this buffer if it was the only user. */ - if (!(j%(max_blocks/100))) { - if (!(percent%10)) - printk (" %03d%% done.\n",percent); - else - printk ("."); - percent++; + for (i = 0; i < chunk; i++) + cache_drop_behind(bh[i]); + + + if (md_signal_pending(current)) { + /* + * got a signal, exit. + */ + mddev->curr_resync = 0; + printk("md_do_sync() got signal ... exiting\n"); + md_flush_signals(); + err = -EINTR; + goto out; } + + /* + * this loop exits only if either when we are slower than + * the 'hard' speed limit, or the system was IO-idle for + * a jiffy. + * the system might be non-idle CPU-wise, but we only care + * about not overloading the IO subsystem. (things like an + * e2fsck being done on the RAID array should execute fast) + */ +repeat: + if (md_need_resched(current)) + schedule(); + + if ((blocksize/1024)*j/((jiffies-starttime)/HZ + 1) + 1 + > sysctl_speed_limit) { + current->priority = 1; + + if (!is_mddev_idle(mddev)) { + current->state = TASK_INTERRUPTIBLE; + md_schedule_timeout(HZ/2); + if (!md_signal_pending(current)) + goto repeat; + } + } else + current->priority = 40; } fsync_dev(read_disk); - printk("md: %s: sync done.\n", kdevname(read_disk)); - mddev->busy--; - return 0; + printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); + err = 0; + /* + * this also signals 'finished resyncing' to md_stop + */ +out: + up(&mddev->resync_sem); +out_nolock: + free_pages((unsigned long)bh, RA_ORDER); + mddev->curr_resync = 0; + wake_up(&resync_wait); + return err; + +read_error: + /* + * set_blocksize() might change the blocksize. This + * should not happen often, but it happens when eg. + * someone mounts a filesystem that has non-1k + * blocksize. set_blocksize() doesnt touch our + * buffer, but to avoid aliasing problems we change + * our internal blocksize too and retry the read. + */ + curr_bsize = device_bsize(read_disk); + if (curr_bsize != blocksize) { + printk(KERN_INFO "md%d: blocksize changed during read\n", + mdidx(mddev)); + for (k = 0; k < chunk; k++) + if (bh[k]) { + if (buffer_lowprio(bh[k])) + mark_buffer_clean(bh[k]); + brelse(bh[k]); + } + goto retry_read; + } + + /* + * It's a real read problem. We retry and bail out + * only if it's excessive. + */ + if (max_read_errors) { + max_read_errors--; + printk ( KERN_WARNING "md%d: read error while reconstructing, at block %u(%d).\n", mdidx(mddev), j, blocksize); + for (k = 0; k < chunk; k++) + if (bh[k]) { + if (buffer_lowprio(bh[k])) + mark_buffer_clean(bh[k]); + brelse(bh[k]); + } + goto retry_read; + } + printk ( KERN_ALERT "too many read errors, stopping reconstruction.\n"); + for (k = 0; k < chunk; k++) + if (bh[k]) { + if (buffer_lowprio(bh[k])) + mark_buffer_clean(bh[k]); + brelse(bh[k]); + } + err = -EIO; + goto out; } +#undef MAX_NR_BLOCKS + /* - * This is a kernel thread which: syncs a spare disk with the active array + * This is a kernel thread which syncs a spare disk with the active array * * the amount of foolproofing might seem to be a tad excessive, but an * early (not so error-safe) version of raid1syncd synced the first 0.5 gigs * of my root partition with the first 0.5 gigs of my /home partition ... so * i'm a bit nervous ;) */ -void mdsyncd (void *data) +void md_do_recovery (void *data) { - int i; - struct md_dev *mddev; - md_superblock_t *sb; - md_descriptor_t *spare; + int err; + mddev_t *mddev; + mdp_super_t *sb; + mdp_disk_t *spare; unsigned long flags; + struct md_list_head *tmp; - for (i = 0, mddev = md_dev; i < MAX_MD_DEV; i++, mddev++) { + printk(KERN_INFO "md: recovery thread got woken up ...\n"); +restart: + ITERATE_MDDEV(mddev,tmp) { if ((sb = mddev->sb) == NULL) continue; + if (mddev->recovery_running) + continue; if (sb->active_disks == sb->raid_disks) continue; - if (!sb->spare_disks) + if (!sb->spare_disks) { + printk(KERN_ERR "md%d: no spare disk to reconstruct array! -- continuing in degraded mode\n", mdidx(mddev)); continue; + } + /* + * now here we get the spare and resync it. + */ if ((spare = get_spare(mddev)) == NULL) continue; - if (!mddev->pers->mark_spare) + printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + if (!mddev->pers->diskop) continue; - if (mddev->pers->mark_spare(mddev, spare, SPARE_WRITE)) - continue; - if (md_do_sync(mddev) || (spare->state & (1 << MD_FAULTY_DEVICE))) { - mddev->pers->mark_spare(mddev, spare, SPARE_INACTIVE); + if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) continue; + down(&mddev->recovery_sem); + mddev->recovery_running = 1; + err = md_do_sync(mddev, spare); + if (err == -EIO) { + printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + if (!disk_faulty(spare)) { + mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); + mark_disk_faulty(spare); + mark_disk_nonsync(spare); + mark_disk_inactive(spare); + sb->spare_disks--; + sb->working_disks--; + sb->failed_disks++; + } + } else + if (disk_faulty(spare)) + mddev->pers->diskop(mddev, &spare, + DISKOP_SPARE_INACTIVE); + if (err == -EINTR) { + /* + * Recovery got interrupted ... + * signal back that we have finished using the array. + */ + mddev->pers->diskop(mddev, &spare, + DISKOP_SPARE_INACTIVE); + up(&mddev->recovery_sem); + /* + * we keep 'recovery_running == 1', so we will not + * start a reconstruction next time around ... + * the stop code will set it to 0 explicitly. + */ + goto restart; + } else { + mddev->recovery_running = 0; + up(&mddev->recovery_sem); } save_flags(flags); cli(); - mddev->pers->mark_spare(mddev, spare, SPARE_ACTIVE); - spare->state |= (1 << MD_SYNC_DEVICE); - spare->state |= (1 << MD_ACTIVE_DEVICE); - sb->spare_disks--; - sb->active_disks++; - mddev->sb_dirty = 1; - md_update_sb(mddev - md_dev); + if (!disk_faulty(spare)) { + /* + * the SPARE_ACTIVE diskop possibly changes the + * pointer too + */ + mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_ACTIVE); + mark_disk_sync(spare); + mark_disk_active(spare); + sb->active_disks++; + sb->spare_disks--; + } restore_flags(flags); + mddev->sb_dirty = 1; + md_update_sb(mddev); + goto restart; } + printk(KERN_INFO "md: recovery thread finished ...\n"); } +int md_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) +{ + struct md_list_head *tmp; + mddev_t *mddev; + + if ((code == MD_SYS_DOWN) || (code == MD_SYS_HALT) + || (code == MD_SYS_POWER_OFF)) { + + printk(KERN_INFO "stopping all md devices.\n"); + + ITERATE_MDDEV(mddev,tmp) + do_md_stop (mddev, 1); + /* + * certain more exotic SCSI devices are known to be + * volatile wrt too early system reboots. While the + * right place to handle this issue is the given + * driver, we do want to have a safe RAID driver ... + */ + md_mdelay(1000*1); + } + return NOTIFY_DONE; +} + +struct notifier_block md_notifier = { + md_notify_reboot, + NULL, + 0 +}; + +md__initfunc(void raid_setup(char *str, int *ints)) +{ + char tmpline[100]; + int len, pos, nr, i; + + len = strlen(str) + 1; + nr = 0; + pos = 0; + + for (i = 0; i < len; i++) { + char c = str[i]; + + if (c == ',' || !c) { + tmpline[pos] = 0; + if (!strcmp(tmpline,"noautodetect")) + raid_setup_args.noautodetect = 1; + nr++; + pos = 0; + continue; + } + tmpline[pos] = c; + pos++; + } + raid_setup_args.set = 1; + return; +} + #ifdef CONFIG_MD_BOOT struct { int set; int ints[100]; char str[100]; -} md_setup_args __initdata = { +} md_setup_args md__initdata = { 0,{0},{0} }; /* called from init/main.c */ -__initfunc(void md_setup(char *str,int *ints)) +md__initfunc(void md_setup(char *str,int *ints)) { int i; for(i=0;i<=ints[0];i++) { @@ -1228,21 +3794,24 @@ return; } -__initfunc(void do_md_setup(char *str,int *ints)) +md__initfunc(void do_md_setup(char *str,int *ints)) { - int minor, pers, factor, fault; +#if 0 + int minor, pers, chunk_size, fault; kdev_t dev; int i=1; + printk("i plan to phase this out --mingo\n"); + if(ints[0] < 4) { - printk ("md: Too few Arguments (%d).\n", ints[0]); + printk (KERN_WARNING "md: Too few Arguments (%d).\n", ints[0]); return; } minor=ints[i++]; - if (minor >= MAX_MD_DEV) { - printk ("md: Minor device number too high.\n"); + if ((unsigned int)minor >= MAX_MD_DEVS) { + printk (KERN_WARNING "md: Minor device number too high.\n"); return; } @@ -1252,18 +3821,20 @@ case -1: #ifdef CONFIG_MD_LINEAR pers = LINEAR; - printk ("md: Setting up md%d as linear device.\n",minor); + printk (KERN_INFO "md: Setting up md%d as linear device.\n", + minor); #else - printk ("md: Linear mode not configured." + printk (KERN_WARNING "md: Linear mode not configured." "Recompile the kernel with linear mode enabled!\n"); #endif break; case 0: pers = STRIPED; #ifdef CONFIG_MD_STRIPED - printk ("md: Setting up md%d as a striped device.\n",minor); + printk (KERN_INFO "md: Setting up md%d as a striped device.\n", + minor); #else - printk ("md: Striped mode not configured." + printk (KERN_WARNING "md: Striped mode not configured." "Recompile the kernel with striped mode enabled!\n"); #endif break; @@ -1278,79 +3849,145 @@ break; */ default: - printk ("md: Unknown or not supported raid level %d.\n", ints[--i]); + printk (KERN_WARNING "md: Unknown or not supported raid level %d.\n", ints[--i]); return; } - if(pers) { + if (pers) { - factor=ints[i++]; /* Chunksize */ - fault =ints[i++]; /* Faultlevel */ + chunk_size = ints[i++]; /* Chunksize */ + fault = ints[i++]; /* Faultlevel */ - pers=pers | factor | (fault << FAULT_SHIFT); + pers = pers | chunk_size | (fault << FAULT_SHIFT); - while( str && (dev = name_to_kdev_t(str))) { - do_md_add (minor, dev); - if((str = strchr (str, ',')) != NULL) - str++; - } + while( str && (dev = name_to_kdev_t(str))) { + do_md_add (minor, dev); + if((str = strchr (str, ',')) != NULL) + str++; + } - do_md_run (minor, pers); - printk ("md: Loading md%d.\n",minor); + do_md_run (minor, pers); + printk (KERN_INFO "md: Loading md%d.\n",minor); } - +#endif } #endif +void hsm_init (void); +void translucent_init (void); void linear_init (void); void raid0_init (void); void raid1_init (void); void raid5_init (void); -__initfunc(int md_init (void)) +md__initfunc(int md_init (void)) { - printk ("md driver %d.%d.%d MAX_MD_DEV=%d, MAX_REAL=%d\n", - MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, - MAX_MD_DEV, MAX_REAL); - - if (register_blkdev (MD_MAJOR, "md", &md_fops)) - { - printk ("Unable to get major %d for md\n", MD_MAJOR); - return (-1); - } - - blk_dev[MD_MAJOR].request_fn=DEVICE_REQUEST; - blk_dev[MD_MAJOR].current_request=NULL; - read_ahead[MD_MAJOR]=INT_MAX; - memset(md_dev, 0, MAX_MD_DEV * sizeof (struct md_dev)); - md_gendisk.next=gendisk_head; - - gendisk_head=&md_gendisk; - -#if SUPPORT_RECONSTRUCTION - if ((md_sync_thread = md_register_thread(mdsyncd, NULL)) == NULL) - printk("md: bug: md_sync_thread == NULL\n"); -#endif /* SUPPORT_RECONSTRUCTION */ + static char * name = "mdrecoveryd"; + + printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MAX_REAL=%d\n", + MD_MAJOR_VERSION, MD_MINOR_VERSION, + MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MAX_REAL); + + if (register_blkdev (MD_MAJOR, "md", &md_fops)) + { + printk (KERN_ALERT "Unable to get major %d for md\n", MD_MAJOR); + return (-1); + } + + blk_dev[MD_MAJOR].request_fn = DEVICE_REQUEST; + blk_dev[MD_MAJOR].current_request = NULL; + read_ahead[MD_MAJOR] = INT_MAX; + md_gendisk.next = gendisk_head; + + gendisk_head = &md_gendisk; + + md_recovery_thread = md_register_thread(md_do_recovery, NULL, name); + if (!md_recovery_thread) + printk(KERN_ALERT "bug: couldn't allocate md_recovery_thread\n"); + md_register_reboot_notifier(&md_notifier); + md_register_sysctl(); + +#ifdef CONFIG_MD_HSM + hsm_init (); +#endif +#ifdef CONFIG_MD_TRANSLUCENT + translucent_init (); +#endif #ifdef CONFIG_MD_LINEAR - linear_init (); + linear_init (); #endif #ifdef CONFIG_MD_STRIPED - raid0_init (); + raid0_init (); #endif #ifdef CONFIG_MD_MIRRORING - raid1_init (); + raid1_init (); #endif #ifdef CONFIG_MD_RAID5 - raid5_init (); + raid5_init (); +#endif +#if defined(CONFIG_MD_RAID5) || defined(CONFIG_MD_RAID5_MODULE) + /* + * pick a XOR routine, runtime. + */ + calibrate_xor_block(); #endif - return (0); + + return (0); } #ifdef CONFIG_MD_BOOT -__initfunc(void md_setup_drive(void)) +md__initfunc(void md_setup_drive(void)) { if(md_setup_args.set) do_md_setup(md_setup_args.str, md_setup_args.ints); } #endif + +MD_EXPORT_SYMBOL(md_size); +MD_EXPORT_SYMBOL(register_md_personality); +MD_EXPORT_SYMBOL(unregister_md_personality); +MD_EXPORT_SYMBOL(partition_name); +MD_EXPORT_SYMBOL(md_error); +MD_EXPORT_SYMBOL(md_recover_arrays); +MD_EXPORT_SYMBOL(md_register_thread); +MD_EXPORT_SYMBOL(md_unregister_thread); +MD_EXPORT_SYMBOL(md_update_sb); +MD_EXPORT_SYMBOL(md_map); +MD_EXPORT_SYMBOL(md_wakeup_thread); +MD_EXPORT_SYMBOL(md_do_sync); +MD_EXPORT_SYMBOL(md_print_devices); +MD_EXPORT_SYMBOL(find_rdev_nr); +MD_EXPORT_SYMBOL(md_check_ordering); +MD_EXPORT_SYMBOL(md_interrupt_thread); +MD_EXPORT_SYMBOL(mddev_map); + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry proc_md = { + PROC_MD, 6, "mdstat", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, +}; +#endif + +static void md_geninit (struct gendisk *gdisk) +{ + int i; + + for(i = 0; i < MAX_MD_DEVS; i++) { + md_blocksizes[i] = 1024; + md_maxreadahead[i] = MD_READAHEAD; + md_gendisk.part[i].start_sect = -1; /* avoid partition check */ + md_gendisk.part[i].nr_sects = 0; + } + + printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); + + blksize_size[MD_MAJOR] = md_blocksizes; + md_set_global_readahead(md_maxreadahead); + +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &proc_md); +#endif +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/nbd.c linux.ac/drivers/block/nbd.c --- linux.vanilla/drivers/block/nbd.c Wed Mar 24 10:55:15 1999 +++ linux.ac/drivers/block/nbd.c Mon Jun 21 13:13:11 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/raid0.c linux.ac/drivers/block/raid0.c --- linux.vanilla/drivers/block/raid0.c Sun Nov 8 15:07:37 1998 +++ linux.ac/drivers/block/raid0.c Mon Jul 19 03:26:58 1999 @@ -1,4 +1,3 @@ - /* raid0.c : Multiple Devices driver for Linux Copyright (C) 1994-96 Marc ZYNGIER @@ -18,146 +17,201 @@ */ #include -#include -#include -#include +#include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY -static int create_strip_zones (int minor, struct md_dev *mddev) +static int create_strip_zones (mddev_t *mddev) { - int i, j, c=0; - int current_offset=0; - struct real_dev *smallest_by_zone; - struct raid0_data *data=(struct raid0_data *) mddev->private; - - data->nr_strip_zones=1; - - for (i=1; inb_dev; i++) - { - for (j=0; jdevices[i].size==mddev->devices[j].size) - { - c=1; - break; - } - - if (!c) - data->nr_strip_zones++; - - c=0; - } - - if ((data->strip_zone=vmalloc(sizeof(struct strip_zone)*data->nr_strip_zones)) == NULL) - return 1; - - data->smallest=NULL; - - for (i=0; inr_strip_zones; i++) - { - data->strip_zone[i].dev_offset=current_offset; - smallest_by_zone=NULL; - c=0; - - for (j=0; jnb_dev; j++) - if (mddev->devices[j].size>current_offset) - { - data->strip_zone[i].dev[c++]=mddev->devices+j; - if (!smallest_by_zone || - smallest_by_zone->size > mddev->devices[j].size) - smallest_by_zone=mddev->devices+j; - } - - data->strip_zone[i].nb_dev=c; - data->strip_zone[i].size=(smallest_by_zone->size-current_offset)*c; - - if (!data->smallest || - data->smallest->size > data->strip_zone[i].size) - data->smallest=data->strip_zone+i; - - data->strip_zone[i].zone_offset=i ? (data->strip_zone[i-1].zone_offset+ - data->strip_zone[i-1].size) : 0; - current_offset=smallest_by_zone->size; - } - return 0; + int i, c, j, j1, j2; + int current_offset, curr_zone_offset; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; + + /* + * The number of 'same size groups' + */ + conf->nr_strip_zones = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev1,j1) { + printk("raid0: looking at %s\n", partition_name(rdev1->dev)); + c = 0; + ITERATE_RDEV_ORDERED(mddev,rdev2,j2) { + printk("raid0: comparing %s(%d) with %s(%d)\n", partition_name(rdev1->dev), rdev1->size, partition_name(rdev2->dev), rdev2->size); + if (rdev2 == rdev1) { + printk("raid0: END\n"); + break; + } + if (rdev2->size == rdev1->size) + { + /* + * Not unique, dont count it as a new + * group + */ + printk("raid0: EQUAL\n"); + c = 1; + break; + } + printk("raid0: NOT EQUAL\n"); + } + if (!c) { + printk("raid0: ==> UNIQUE\n"); + conf->nr_strip_zones++; + printk("raid0: %d zones\n", conf->nr_strip_zones); + } + } + printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); + + conf->strip_zone = vmalloc(sizeof(struct strip_zone)* + conf->nr_strip_zones); + if (!conf->strip_zone) + return 1; + + + conf->smallest = NULL; + current_offset = 0; + curr_zone_offset = 0; + + for (i = 0; i < conf->nr_strip_zones; i++) + { + struct strip_zone *zone = conf->strip_zone + i; + + printk("zone %d\n", i); + zone->dev_offset = current_offset; + smallest = NULL; + c = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + + printk(" checking %s ...", partition_name(rdev->dev)); + if (rdev->size > current_offset) + { + printk(" contained as device %d\n", c); + zone->dev[c] = rdev; + c++; + if (!smallest || (rdev->size size)) { + smallest = rdev; + printk(" (%d) is smallest!.\n", rdev->size); + } + } else + printk(" nope.\n"); + } + + zone->nb_dev = c; + zone->size = (smallest->size - current_offset) * c; + printk(" zone->nb_dev: %d, size: %d\n",zone->nb_dev,zone->size); + + if (!conf->smallest || (zone->size < conf->smallest->size)) + conf->smallest = zone; + + zone->zone_offset = curr_zone_offset; + curr_zone_offset += zone->size; + + current_offset = smallest->size; + printk("current zone offset: %d\n", current_offset); + } + printk("done.\n"); + return 0; } -static int raid0_run (int minor, struct md_dev *mddev) +static int raid0_run (mddev_t *mddev) { - int cur=0, i=0, size, zone0_size, nb_zone; - struct raid0_data *data; - - MOD_INC_USE_COUNT; + int cur=0, i=0, size, zone0_size, nb_zone; + raid0_conf_t *conf; - if ((mddev->private=vmalloc (sizeof (struct raid0_data))) == NULL) return 1; - data=(struct raid0_data *) mddev->private; - - if (create_strip_zones (minor, mddev)) - { - vfree(data); - return 1; - } - - nb_zone=data->nr_zones= - md_size[minor]/data->smallest->size + - (md_size[minor]%data->smallest->size ? 1 : 0); - - printk ("raid0 : Allocating %ld bytes for hash.\n",(long)sizeof(struct raid0_hash)*nb_zone); - if ((data->hash_table=vmalloc (sizeof (struct raid0_hash)*nb_zone)) == NULL) - { - vfree(data->strip_zone); - vfree(data); - return 1; - } - size=data->strip_zone[cur].size; - - i=0; - while (curnr_strip_zones) - { - data->hash_table[i].zone0=data->strip_zone+cur; - - if (size>=data->smallest->size)/* If we completely fill the slot */ - { - data->hash_table[i++].zone1=NULL; - size-=data->smallest->size; - - if (!size) - { - if (++cur==data->nr_strip_zones) continue; - size=data->strip_zone[cur].size; - } - - continue; - } - - if (++cur==data->nr_strip_zones) /* Last dev, set unit1 as NULL */ - { - data->hash_table[i].zone1=NULL; - continue; - } - - zone0_size=size; /* Here, we use a 2nd dev to fill the slot */ - size=data->strip_zone[cur].size; - data->hash_table[i++].zone1=data->strip_zone+cur; - size-=(data->smallest->size - zone0_size); - } + MOD_INC_USE_COUNT; - return (0); + conf = vmalloc(sizeof (raid0_conf_t)); + if (!conf) + goto out; + mddev->private = (void *)conf; + + if (md_check_ordering(mddev)) { + printk("raid0: disks are not ordered, aborting!\n"); + goto out_free_conf; + } + + if (create_strip_zones (mddev)) + goto out_free_conf; + + printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); + printk("raid0 : conf->smallest->size is %d blocks.\n", conf->smallest->size); + nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + + (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); + printk("raid0 : nb_zone is %d.\n", nb_zone); + conf->nr_zones = nb_zone; + + printk("raid0 : Allocating %d bytes for hash.\n", + sizeof(struct raid0_hash)*nb_zone); + + conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); + if (!conf->hash_table) + goto out_free_zone_conf; + size = conf->strip_zone[cur].size; + + i = 0; + while (cur < conf->nr_strip_zones) { + conf->hash_table[i].zone0 = conf->strip_zone + cur; + + /* + * If we completely fill the slot + */ + if (size >= conf->smallest->size) { + conf->hash_table[i++].zone1 = NULL; + size -= conf->smallest->size; + + if (!size) { + if (++cur == conf->nr_strip_zones) + continue; + size = conf->strip_zone[cur].size; + } + continue; + } + if (++cur == conf->nr_strip_zones) { + /* + * Last dev, set unit1 as NULL + */ + conf->hash_table[i].zone1=NULL; + continue; + } + + /* + * Here we use a 2nd dev to fill the slot + */ + zone0_size = size; + size = conf->strip_zone[cur].size; + conf->hash_table[i++].zone1 = conf->strip_zone + cur; + size -= (conf->smallest->size - zone0_size); + } + return 0; + +out_free_zone_conf: + vfree(conf->strip_zone); + conf->strip_zone = NULL; + +out_free_conf: + vfree(conf); + mddev->private = NULL; +out: + MOD_DEC_USE_COUNT; + return 1; } - -static int raid0_stop (int minor, struct md_dev *mddev) +static int raid0_stop (mddev_t *mddev) { - struct raid0_data *data=(struct raid0_data *) mddev->private; + raid0_conf_t *conf = mddev_to_conf(mddev); - vfree (data->hash_table); - vfree (data->strip_zone); - vfree (data); + vfree (conf->hash_table); + conf->hash_table = NULL; + vfree (conf->strip_zone); + conf->strip_zone = NULL; + vfree (conf); + mddev->private = NULL; - MOD_DEC_USE_COUNT; - return 0; + MOD_DEC_USE_COUNT; + return 0; } /* @@ -167,129 +221,135 @@ * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_map (struct md_dev *mddev, kdev_t *rdev, +static int raid0_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, unsigned long *rsector, unsigned long size) { - struct raid0_data *data=(struct raid0_data *) mddev->private; - static struct raid0_hash *hash; - struct strip_zone *zone; - struct real_dev *tmp_dev; - int blk_in_chunk, factor, chunk, chunk_size; - long block, rblock; - - factor=FACTOR(mddev); - chunk_size=(1UL << FACTOR_SHIFT(factor)); - block=*rsector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - /* Sanity check */ - if ((chunk_size*2)<(*rsector % (chunk_size*2))+size) - { - printk ("raid0_convert : can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, *rsector, size); - return (-1); - } - - if (block >= (hash->zone0->size + - hash->zone0->zone_offset)) - { - if (!hash->zone1) - { - printk ("raid0_convert : hash->zone1==NULL for block %ld\n", block); - return (-1); - } - - zone=hash->zone1; - } - else - zone=hash->zone0; + raid0_conf_t *conf = mddev_to_conf(mddev); + struct raid0_hash *hash; + struct strip_zone *zone; + mdk_rdev_t *tmp_dev; + int blk_in_chunk, chunksize_bits, chunk, chunk_size; + long block, rblock; + + chunk_size = mddev->param.chunk_size >> 10; + chunksize_bits = ffz(~chunk_size); + block = *rsector >> 1; + hash = conf->hash_table + block / conf->smallest->size; + + /* Sanity check */ + if ((chunk_size * 2) < (*rsector % (chunk_size * 2)) + size) + goto bad_map; + + if (!hash) + goto bad_hash; + + if (!hash->zone0) + goto bad_zone0; + + if (block >= (hash->zone0->size + hash->zone0->zone_offset)) { + if (!hash->zone1) + goto bad_zone1; + zone = hash->zone1; + } else + zone = hash->zone0; - blk_in_chunk=block & (chunk_size -1); - chunk=(block - zone->zone_offset) / (zone->nb_dev<dev[(block >> FACTOR_SHIFT(factor)) % zone->nb_dev]; - rblock=(chunk << FACTOR_SHIFT(factor)) + blk_in_chunk + zone->dev_offset; + blk_in_chunk = block & (chunk_size -1); + chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits); + tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev]; + rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset; - *rdev=tmp_dev->dev; - *rsector=rblock<<1; + *rdev = tmp_dev->dev; + *rsector = rblock << 1; - return (0); + return 0; + +bad_map: + printk ("raid0_map bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, *rsector, size); + return -1; +bad_hash: + printk("raid0_map bug: hash==NULL for block %ld\n", block); + return -1; +bad_zone0: + printk ("raid0_map bug: hash->zone0==NULL for block %ld\n", block); + return -1; +bad_zone1: + printk ("raid0_map bug: hash->zone1==NULL for block %ld\n", block); + return -1; } -static int raid0_status (char *page, int minor, struct md_dev *mddev) +static int raid0_status (char *page, mddev_t *mddev) { - int sz=0; + int sz = 0; #undef MD_DEBUG #ifdef MD_DEBUG - int j, k; - struct raid0_data *data=(struct raid0_data *) mddev->private; + int j, k; + raid0_conf_t *conf = mddev_to_conf(mddev); - sz+=sprintf (page+sz, " "); - for (j=0; jnr_zones; j++) - { - sz+=sprintf (page+sz, "[z%d", - data->hash_table[j].zone0-data->strip_zone); - if (data->hash_table[j].zone1) - sz+=sprintf (page+sz, "/z%d] ", - data->hash_table[j].zone1-data->strip_zone); - else - sz+=sprintf (page+sz, "] "); - } + sz += sprintf(page + sz, " "); + for (j = 0; j < conf->nr_zones; j++) { + sz += sprintf(page + sz, "[z%d", + conf->hash_table[j].zone0 - conf->strip_zone); + if (conf->hash_table[j].zone1) + sz += sprintf(page+sz, "/z%d] ", + conf->hash_table[j].zone1 - conf->strip_zone); + else + sz += sprintf(page+sz, "] "); + } - sz+=sprintf (page+sz, "\n"); + sz += sprintf(page + sz, "\n"); - for (j=0; jnr_strip_zones; j++) - { - sz+=sprintf (page+sz, " z%d=[", j); - for (k=0; kstrip_zone[j].nb_dev; k++) - sz+=sprintf (page+sz, "%s/", - partition_name(data->strip_zone[j].dev[k]->dev)); - sz--; - sz+=sprintf (page+sz, "] zo=%d do=%d s=%d\n", - data->strip_zone[j].zone_offset, - data->strip_zone[j].dev_offset, - data->strip_zone[j].size); - } + for (j = 0; j < conf->nr_strip_zones; j++) { + sz += sprintf(page + sz, " z%d=[", j); + for (k = 0; k < conf->strip_zone[j].nb_dev; k++) + sz += sprintf (page+sz, "%s/", partition_name( + conf->strip_zone[j].dev[k]->dev)); + sz--; + sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n", + conf->strip_zone[j].zone_offset, + conf->strip_zone[j].dev_offset, + conf->strip_zone[j].size); + } #endif - sz+=sprintf (page+sz, " %dk chunks", 1<param.chunk_size/1024); + return sz; } - -static struct md_personality raid0_personality= +static mdk_personality_t raid0_personality= { - "raid0", - raid0_map, - NULL, /* no special make_request */ - NULL, /* no special end_request */ - raid0_run, - raid0_stop, - raid0_status, - NULL, /* no ioctls */ - 0, - NULL, /* no error_handler */ - NULL, /* hot_add_disk */ - NULL, /* hot_remove_disk */ - NULL /* mark_spare */ + "raid0", + raid0_map, + NULL, /* no special make_request */ + NULL, /* no special end_request */ + raid0_run, + raid0_stop, + raid0_status, + NULL, /* no ioctls */ + 0, + NULL, /* no error_handler */ + NULL, /* no diskop */ + NULL, /* no stop resync */ + NULL /* no restart resync */ }; - #ifndef MODULE void raid0_init (void) { - register_md_personality (RAID0, &raid0_personality); + register_md_personality (RAID0, &raid0_personality); } #else int init_module (void) { - return (register_md_personality (RAID0, &raid0_personality)); + return (register_md_personality (RAID0, &raid0_personality)); } void cleanup_module (void) { - unregister_md_personality (RAID0); + unregister_md_personality (RAID0); } #endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/raid1.c linux.ac/drivers/block/raid1.c --- linux.vanilla/drivers/block/raid1.c Tue Dec 22 23:19:36 1998 +++ linux.ac/drivers/block/raid1.c Mon Jul 19 03:26:58 1999 @@ -1,6 +1,6 @@ -/************************************************************************ +/* * raid1.c : Multiple Devices driver for Linux - * Copyright (C) 1996 Ingo Molnar, Miguel de Icaza, Gadi Oxman + * Copyright (C) 1996, 1997, 1998 Ingo Molnar, Miguel de Icaza, Gadi Oxman * * RAID-1 management functions. * @@ -15,50 +15,52 @@ */ #include -#include #include -#include -#include -#include +#include #include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY -/* - * The following can be used to debug the driver - */ -/*#define RAID1_DEBUG*/ -#ifdef RAID1_DEBUG -#define PRINTK(x) do { printk x; } while (0); -#else -#define PRINTK(x) do { ; } while (0); -#endif +#define MAX_LINEAR_SECTORS 128 #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) -static struct md_personality raid1_personality; -static struct md_thread *raid1_thread = NULL; +static mdk_personality_t raid1_personality; struct buffer_head *raid1_retry_list = NULL; -static int __raid1_map (struct md_dev *mddev, kdev_t *rdev, +static void * raid1_kmalloc (int size) +{ + void * ptr; + /* + * now we are rather fault tolerant than nice, but + * there are a couple of places in the RAID code where we + * simply can not afford to fail an allocation because + * there is no failure return path (eg. make_request()) + */ + while (!(ptr = kmalloc (sizeof (raid1_conf_t), GFP_KERNEL))) + printk ("raid1: out of memory, retrying...\n"); + + memset(ptr, 0, size); + return ptr; +} + +static int __raid1_map (mddev_t *mddev, kdev_t *rdev, unsigned long *rsector, unsigned long size) { - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; - int i, n = raid_conf->raid_disks; + raid1_conf_t *conf = mddev_to_conf(mddev); + int i, disks = MD_SB_DISKS; /* * Later we do read balancing on the read side * now we use the first available disk. */ - PRINTK(("raid1_map().\n")); - - for (i=0; imirrors[i].operational) { - *rdev = raid_conf->mirrors[i].dev; + for (i = 0; i < disks; i++) { + if (conf->mirrors[i].operational) { + *rdev = conf->mirrors[i].dev; return (0); } } @@ -67,29 +69,29 @@ return (-1); } -static int raid1_map (struct md_dev *mddev, kdev_t *rdev, +static int raid1_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, unsigned long *rsector, unsigned long size) { return 0; } -void raid1_reschedule_retry (struct buffer_head *bh) +static void raid1_reschedule_retry (struct buffer_head *bh) { struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_dev_id); - - PRINTK(("raid1_reschedule_retry().\n")); + mddev_t *mddev = r1_bh->mddev; + raid1_conf_t *conf = mddev_to_conf(mddev); r1_bh->next_retry = raid1_retry_list; raid1_retry_list = bh; - md_wakeup_thread(raid1_thread); + md_wakeup_thread(conf->thread); } /* - * raid1_end_buffer_io() is called when we have finished servicing a mirrored + * raid1_end_bh_io() is called when we have finished servicing a mirrored * operation and are ready to return a success/failure code to the buffer * cache layer. */ -static inline void raid1_end_buffer_io(struct raid1_bh *r1_bh, int uptodate) +static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate) { struct buffer_head *bh = r1_bh->master_bh; @@ -97,8 +99,6 @@ kfree(r1_bh); } -int raid1_one_error=0; - void raid1_end_request (struct buffer_head *bh, int uptodate) { struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_dev_id); @@ -106,12 +106,7 @@ save_flags(flags); cli(); - PRINTK(("raid1_end_request().\n")); - if (raid1_one_error) { - raid1_one_error=0; - uptodate=0; - } /* * this branch is our 'one mirror IO has finished' event handler: */ @@ -136,15 +131,11 @@ */ if ( (r1_bh->cmd == READ) || (r1_bh->cmd == READA) ) { - - PRINTK(("raid1_end_request(), read branch.\n")); - /* * we have only one buffer_head on the read side */ if (uptodate) { - PRINTK(("raid1_end_request(), read branch, uptodate.\n")); - raid1_end_buffer_io(r1_bh, uptodate); + raid1_end_bh_io(r1_bh, uptodate); restore_flags(flags); return; } @@ -152,67 +143,56 @@ * oops, read error: */ printk(KERN_ERR "raid1: %s: rescheduling block %lu\n", - kdevname(bh->b_dev), bh->b_blocknr); - raid1_reschedule_retry (bh); + partition_name(bh->b_dev), bh->b_blocknr); + raid1_reschedule_retry(bh); restore_flags(flags); return; } /* - * WRITE or WRITEA. - */ - PRINTK(("raid1_end_request(), write branch.\n")); - - /* + * WRITE: + * * Let's see if all mirrored write operations have finished - * already [we have irqs off, so we can decrease]: + * already. */ - if (!--r1_bh->remaining) { - struct md_dev *mddev = r1_bh->mddev; - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; - int i, n = raid_conf->raid_disks; + if (atomic_dec_and_test(&r1_bh->remaining)) { + int i, disks = MD_SB_DISKS; - PRINTK(("raid1_end_request(), remaining == 0.\n")); + for ( i = 0; i < disks; i++) + if (r1_bh->mirror_bh[i]) + kfree(r1_bh->mirror_bh[i]); - for ( i=0; imirror_bh[i]) kfree(r1_bh->mirror_bh[i]); - - raid1_end_buffer_io(r1_bh, test_bit(BH_Uptodate, &r1_bh->state)); + raid1_end_bh_io(r1_bh, test_bit(BH_Uptodate, &r1_bh->state)); } - else PRINTK(("raid1_end_request(), remaining == %u.\n", r1_bh->remaining)); restore_flags(flags); } -/* This routine checks if the undelying device is an md device and in that - * case it maps the blocks before putting the request on the queue +/* + * This routine checks if the undelying device is an md device + * and in that case it maps the blocks before putting the + * request on the queue */ -static inline void -map_and_make_request (int rw, struct buffer_head *bh) +static void map_and_make_request (int rw, struct buffer_head *bh) { if (MAJOR (bh->b_rdev) == MD_MAJOR) - md_map (MINOR (bh->b_rdev), &bh->b_rdev, &bh->b_rsector, bh->b_size >> 9); + md_map (bh->b_rdev, &bh->b_rdev, + &bh->b_rsector, bh->b_size >> 9); clear_bit(BH_Lock, &bh->b_state); make_request (MAJOR (bh->b_rdev), rw, bh); } -static int -raid1_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh) +static int raid1_make_request (mddev_t *mddev, int rw, + struct buffer_head * bh) { - - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; + raid1_conf_t *conf = mddev_to_conf(mddev); struct buffer_head *mirror_bh[MD_SB_DISKS], *bh_req; struct raid1_bh * r1_bh; - int n = raid_conf->raid_disks, i, sum_bhs = 0, switch_disks = 0, sectors; + int disks = MD_SB_DISKS; + int i, sum_bhs = 0, switch_disks = 0, sectors, lowprio = 0; struct mirror_info *mirror; - PRINTK(("raid1_make_request().\n")); - - while (!( /* FIXME: now we are rather fault tolerant than nice */ - r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_KERNEL) - ) ) - printk ("raid1_make_request(#1): out of memory\n"); - memset (r1_bh, 0, sizeof (struct raid1_bh)); + r1_bh = raid1_kmalloc (sizeof (struct raid1_bh)); /* * make_request() can abort the operation when READA or WRITEA are being @@ -223,43 +203,65 @@ if (rw == READA) rw = READ; if (rw == WRITEA) rw = WRITE; - if (rw == WRITE || rw == WRITEA) - mark_buffer_clean(bh); /* Too early ? */ + if (rw == WRITE) { + /* + * Too early ? + */ + mark_buffer_clean(bh); + /* + * not too early. we _first_ clean the bh, then we start + * the IO, then when the IO has finished, we unlock the + * bh and mark it uptodate. This way we do not miss the + * case when the bh got dirty again during the IO. + */ + } + + /* + * special flag for 'lowprio' reconstruction requests ... + */ + if (buffer_lowprio(bh)) + lowprio = 1; /* - * i think the read and write branch should be separated completely, since we want - * to do read balancing on the read side for example. Comments? :) --mingo + * i think the read and write branch should be separated completely, + * since we want to do read balancing on the read side for example. + * Comments? :) --mingo */ r1_bh->master_bh=bh; r1_bh->mddev=mddev; r1_bh->cmd = rw; - if (rw==READ || rw==READA) { - int last_used = raid_conf->last_used; - PRINTK(("raid1_make_request(), read branch.\n")); - mirror = raid_conf->mirrors + last_used; + if (rw==READ) { + int last_used = conf->last_used; + + /* + * read balancing logic: + */ + mirror = conf->mirrors + last_used; bh->b_rdev = mirror->dev; sectors = bh->b_size >> 9; - if (bh->b_blocknr * sectors == raid_conf->next_sect) { - raid_conf->sect_count += sectors; - if (raid_conf->sect_count >= mirror->sect_limit) + + if (bh->b_blocknr * sectors == conf->next_sect) { + conf->sect_count += sectors; + if (conf->sect_count >= mirror->sect_limit) switch_disks = 1; } else switch_disks = 1; - raid_conf->next_sect = (bh->b_blocknr + 1) * sectors; - if (switch_disks) { - PRINTK(("read-balancing: switching %d -> %d (%d sectors)\n", last_used, mirror->next, raid_conf->sect_count)); - raid_conf->sect_count = 0; - last_used = raid_conf->last_used = mirror->next; + conf->next_sect = (bh->b_blocknr + 1) * sectors; + /* + * Do not switch disks if full resync is in progress ... + */ + if (switch_disks && !conf->resync_mirrors) { + conf->sect_count = 0; + last_used = conf->last_used = mirror->next; /* - * Do not switch to write-only disks ... resyncing - * is in progress + * Do not switch to write-only disks ... + * reconstruction is in progress */ - while (raid_conf->mirrors[last_used].write_only) - raid_conf->last_used = raid_conf->mirrors[last_used].next; + while (conf->mirrors[last_used].write_only) + conf->last_used = conf->mirrors[last_used].next; } - PRINTK (("raid1 read queue: %d %d\n", MAJOR (bh->b_rdev), MINOR (bh->b_rdev))); bh_req = &r1_bh->bh_req; memcpy(bh_req, bh, sizeof(*bh)); bh_req->b_end_io = raid1_end_request; @@ -269,13 +271,12 @@ } /* - * WRITE or WRITEA. + * WRITE: */ - PRINTK(("raid1_make_request(n=%d), write branch.\n",n)); - for (i = 0; i < n; i++) { + for (i = 0; i < disks; i++) { - if (!raid_conf->mirrors [i].operational) { + if (!conf->mirrors[i].operational) { /* * the r1_bh->mirror_bh[i] pointer remains NULL */ @@ -283,85 +284,91 @@ continue; } + /* + * special case for reconstruction ... + */ + if (lowprio && (i == conf->last_used)) { + mirror_bh[i] = NULL; + continue; + } + + /* + * We should use a private pool (size depending on NR_REQUEST), + * to avoid writes filling up the memory with bhs + * + * Such pools are much faster than kmalloc anyways (so we waste + * almost nothing by not using the master bh when writing and + * win alot of cleanness) but for now we are cool enough. --mingo + * + * It's safe to sleep here, buffer heads cannot be used in a shared + * manner in the write branch. Look how we lock the buffer at the + * beginning of this function to grok the difference ;) + */ + mirror_bh[i] = raid1_kmalloc(sizeof(struct buffer_head)); + /* + * prepare mirrored bh (fields ordered for max mem throughput): + */ + mirror_bh[i]->b_blocknr = bh->b_blocknr; + mirror_bh[i]->b_dev = bh->b_dev; + mirror_bh[i]->b_rdev = conf->mirrors[i].dev; + mirror_bh[i]->b_rsector = bh->b_rsector; + mirror_bh[i]->b_state = (1<b_state |= (1<b_count = 1; + mirror_bh[i]->b_size = bh->b_size; + mirror_bh[i]->b_data = bh->b_data; + mirror_bh[i]->b_list = BUF_LOCKED; + mirror_bh[i]->b_end_io = raid1_end_request; + mirror_bh[i]->b_dev_id = r1_bh; + + r1_bh->mirror_bh[i] = mirror_bh[i]; + sum_bhs++; + } + + md_atomic_set(&r1_bh->remaining, sum_bhs); + /* - * We should use a private pool (size depending on NR_REQUEST), - * to avoid writes filling up the memory with bhs - * - * Such pools are much faster than kmalloc anyways (so we waste almost - * nothing by not using the master bh when writing and win alot of cleanness) - * - * but for now we are cool enough. --mingo - * - * It's safe to sleep here, buffer heads cannot be used in a shared - * manner in the write branch. Look how we lock the buffer at the beginning - * of this function to grok the difference ;) - */ - while (!( /* FIXME: now we are rather fault tolerant than nice */ - mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_KERNEL) - ) ) - printk ("raid1_make_request(#2): out of memory\n"); - memset (mirror_bh[i], 0, sizeof (struct buffer_head)); - - /* - * prepare mirrored bh (fields ordered for max mem throughput): - */ - mirror_bh [i]->b_blocknr = bh->b_blocknr; - mirror_bh [i]->b_dev = bh->b_dev; - mirror_bh [i]->b_rdev = raid_conf->mirrors [i].dev; - mirror_bh [i]->b_rsector = bh->b_rsector; - mirror_bh [i]->b_state = (1<b_count = 1; - mirror_bh [i]->b_size = bh->b_size; - mirror_bh [i]->b_data = bh->b_data; - mirror_bh [i]->b_list = BUF_LOCKED; - mirror_bh [i]->b_end_io = raid1_end_request; - mirror_bh [i]->b_dev_id = r1_bh; - - r1_bh->mirror_bh[i] = mirror_bh[i]; - sum_bhs++; - } - - r1_bh->remaining = sum_bhs; - - PRINTK(("raid1_make_request(), write branch, sum_bhs=%d.\n",sum_bhs)); - - /* - * We have to be a bit careful about the semaphore above, thats why we - * start the requests separately. Since kmalloc() could fail, sleep and - * make_request() can sleep too, this is the safer solution. Imagine, - * end_request decreasing the semaphore before we could have set it up ... - * We could play tricks with the semaphore (presetting it and correcting - * at the end if sum_bhs is not 'n' but we have to do end_request by hand - * if all requests finish until we had a chance to set up the semaphore - * correctly ... lots of races). - */ - for (i = 0; i < n; i++) - if (mirror_bh [i] != NULL) - map_and_make_request (rw, mirror_bh [i]); + * We have to be a bit careful about the semaphore above, thats + * why we start the requests separately. Since kmalloc() could + * fail, sleep and make_request() can sleep too, this is the + * safer solution. Imagine, end_request decreasing the semaphore + * before we could have set it up ... We could play tricks with + * the semaphore (presetting it and correcting at the end if + * sum_bhs is not 'n' but we have to do end_request by hand if + * all requests finish until we had a chance to set up the + * semaphore correctly ... lots of races). + */ + for (i = 0; i < disks; i++) + if (mirror_bh[i]) + map_and_make_request(rw, mirror_bh[i]); return (0); } -static int raid1_status (char *page, int minor, struct md_dev *mddev) +static int raid1_status (char *page, mddev_t *mddev) { - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; + raid1_conf_t *conf = mddev_to_conf(mddev); int sz = 0, i; - sz += sprintf (page+sz, " [%d/%d] [", raid_conf->raid_disks, raid_conf->working_disks); - for (i = 0; i < raid_conf->raid_disks; i++) - sz += sprintf (page+sz, "%s", raid_conf->mirrors [i].operational ? "U" : "_"); + sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, + conf->working_disks); + for (i = 0; i < conf->raid_disks; i++) + sz += sprintf (page+sz, "%s", + conf->mirrors[i].operational ? "U" : "_"); sz += sprintf (page+sz, "]"); return sz; } -static void raid1_fix_links (struct raid1_data *raid_conf, int failed_index) +static void unlink_disk (raid1_conf_t *conf, int target) { - int disks = raid_conf->raid_disks; - int j; + int disks = MD_SB_DISKS; + int i; - for (j = 0; j < disks; j++) - if (raid_conf->mirrors [j].next == failed_index) - raid_conf->mirrors [j].next = raid_conf->mirrors [failed_index].next; + for (i = 0; i < disks; i++) + if (conf->mirrors[i].next == target) + conf->mirrors[i].next = conf->mirrors[target].next; } #define LAST_DISK KERN_ALERT \ @@ -380,48 +387,53 @@ #define ALREADY_SYNCING KERN_INFO \ "raid1: syncing already in progress.\n" -static int raid1_error (struct md_dev *mddev, kdev_t dev) +static void mark_disk_bad (mddev_t *mddev, int failed) { - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; - struct mirror_info *mirror; - md_superblock_t *sb = mddev->sb; - int disks = raid_conf->raid_disks; - int i; + raid1_conf_t *conf = mddev_to_conf(mddev); + struct mirror_info *mirror = conf->mirrors+failed; + mdp_super_t *sb = mddev->sb; + + mirror->operational = 0; + unlink_disk(conf, failed); + mark_disk_faulty(sb->disks+mirror->number); + mark_disk_nonsync(sb->disks+mirror->number); + mark_disk_inactive(sb->disks+mirror->number); + sb->active_disks--; + sb->working_disks--; + sb->failed_disks++; + mddev->sb_dirty = 1; + md_wakeup_thread(conf->thread); + conf->working_disks--; + printk (DISK_FAILED, partition_name (mirror->dev), + conf->working_disks); +} - PRINTK(("raid1_error called\n")); +static int raid1_error (mddev_t *mddev, kdev_t dev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + struct mirror_info * mirrors = conf->mirrors; + int disks = MD_SB_DISKS; + int i; - if (raid_conf->working_disks == 1) { + if (conf->working_disks == 1) { /* * Uh oh, we can do nothing if this is our last disk, but * first check if this is a queued request for a device * which has just failed. */ - for (i = 0, mirror = raid_conf->mirrors; i < disks; - i++, mirror++) - if (mirror->dev == dev && !mirror->operational) + for (i = 0; i < disks; i++) { + if (mirrors[i].dev==dev && !mirrors[i].operational) return 0; + } printk (LAST_DISK); } else { - /* Mark disk as unusable */ - for (i = 0, mirror = raid_conf->mirrors; i < disks; - i++, mirror++) { - if (mirror->dev == dev && mirror->operational){ - mirror->operational = 0; - raid1_fix_links (raid_conf, i); - sb->disks[mirror->number].state |= - (1 << MD_FAULTY_DEVICE); - sb->disks[mirror->number].state &= - ~(1 << MD_SYNC_DEVICE); - sb->disks[mirror->number].state &= - ~(1 << MD_ACTIVE_DEVICE); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; - mddev->sb_dirty = 1; - md_wakeup_thread(raid1_thread); - raid_conf->working_disks--; - printk (DISK_FAILED, kdevname (dev), - raid_conf->working_disks); + /* + * Mark disk as unusable + */ + for (i = 0; i < disks; i++) { + if (mirrors[i].dev==dev && mirrors[i].operational) { + mark_disk_bad (mddev, i); + break; } } } @@ -434,219 +446,396 @@ #undef START_SYNCING /* - * This is the personality-specific hot-addition routine + * Insert the spare disk into the drive-ring */ +static void link_disk(raid1_conf_t *conf, struct mirror_info *mirror) +{ + int j, next; + int disks = MD_SB_DISKS; + struct mirror_info *p = conf->mirrors; -#define NO_SUPERBLOCK KERN_ERR \ -"raid1: cannot hot-add disk to the array with no RAID superblock\n" + for (j = 0; j < disks; j++, p++) + if (p->operational && !p->write_only) { + next = p->next; + p->next = mirror->raid_disk; + mirror->next = next; + return; + } -#define WRONG_LEVEL KERN_ERR \ -"raid1: hot-add: level of disk is not RAID-1\n" + printk("raid1: bug: no read-operational devices\n"); +} -#define HOT_ADD_SUCCEEDED KERN_INFO \ -"raid1: device %s hot-added\n" +static void print_raid1_conf (raid1_conf_t *conf) +{ + int i; + struct mirror_info *tmp; + + printk("RAID1 conf printout:\n"); + if (!conf) { + printk("(conf==NULL)\n"); + return; + } + printk(" --- wd:%d rd:%d nd:%d\n", conf->working_disks, + conf->raid_disks, conf->nr_disks); + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + i, tmp->spare,tmp->operational, + tmp->number,tmp->raid_disk,tmp->used_slot, + partition_name(tmp->dev)); + } +} -static int raid1_hot_add_disk (struct md_dev *mddev, kdev_t dev) +static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state) { + int err = 0; + int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; + raid1_conf_t *conf = mddev->private; + struct mirror_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; unsigned long flags; - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; - struct mirror_info *mirror; - md_superblock_t *sb = mddev->sb; - struct real_dev * realdev; - int n; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *failed_desc, *spare_desc, *added_desc; + + save_flags(flags); + cli(); + print_raid1_conf(conf); /* - * The device has its superblock already read and it was found - * to be consistent for generic RAID usage. Now we check whether - * it's usable for RAID-1 hot addition. + * find the disk ... */ + switch (state) { - n = mddev->nb_dev++; - realdev = &mddev->devices[n]; - if (!realdev->sb) { - printk (NO_SUPERBLOCK); - return -EINVAL; - } - if (realdev->sb->level != 1) { - printk (WRONG_LEVEL); - return -EINVAL; + case DISKOP_SPARE_ACTIVE: + + /* + * Find the failed disk within the RAID1 configuration ... + * (this can only be in the first conf->working_disks part) + */ + for (i = 0; i < conf->raid_disks; i++) { + tmp = conf->mirrors + i; + if ((!tmp->operational && !tmp->spare) || + !tmp->used_slot) { + failed_disk = i; + break; + } + } + /* + * When we activate a spare disk we _must_ have a disk in + * the lower (active) part of the array to replace. + */ + if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + /* fall through */ + + case DISKOP_SPARE_WRITE: + case DISKOP_SPARE_INACTIVE: + + /* + * Find the spare disk ... (can only be in the 'high' + * area of the array) + */ + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (tmp->spare && tmp->number == (*d)->number) { + spare_disk = i; + break; + } + } + if (spare_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_REMOVE_DISK: + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (tmp->used_slot && (tmp->number == (*d)->number)) { + if (tmp->operational) { + err = -EBUSY; + goto abort; + } + removed_disk = i; + break; + } + } + if (removed_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_ADD_DISK: + + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (!tmp->used_slot) { + added_disk = i; + break; + } + } + if (added_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; } - /* FIXME: are there other things left we could sanity-check? */ + switch (state) { /* - * We have to disable interrupts, as our RAID-1 state is used - * from irq handlers as well. + * Switch the spare disk to write-only mode: */ - save_flags(flags); - cli(); + case DISKOP_SPARE_WRITE: + sdisk = conf->mirrors + spare_disk; + sdisk->operational = 1; + sdisk->write_only = 1; + break; + /* + * Deactivate a spare disk: + */ + case DISKOP_SPARE_INACTIVE: + sdisk = conf->mirrors + spare_disk; + sdisk->operational = 0; + sdisk->write_only = 0; + break; + /* + * Activate (mark read-write) the (now sync) spare disk, + * which means we switch it's 'raid position' (->raid_disk) + * with the failed disk. (only the first 'conf->nr_disks' + * slots are used for 'real' disks and we must preserve this + * property) + */ + case DISKOP_SPARE_ACTIVE: - raid_conf->raid_disks++; - mirror = raid_conf->mirrors+n; + sdisk = conf->mirrors + spare_disk; + fdisk = conf->mirrors + failed_disk; - mirror->number=n; - mirror->raid_disk=n; - mirror->dev=dev; - mirror->next=0; /* FIXME */ - mirror->sect_limit=128; - - mirror->operational=0; - mirror->spare=1; - mirror->write_only=0; - - sb->disks[n].state |= (1 << MD_FAULTY_DEVICE); - sb->disks[n].state &= ~(1 << MD_SYNC_DEVICE); - sb->disks[n].state &= ~(1 << MD_ACTIVE_DEVICE); - sb->nr_disks++; - sb->spare_disks++; + spare_desc = &sb->disks[sdisk->number]; + failed_desc = &sb->disks[fdisk->number]; - restore_flags(flags); + if (spare_desc != *d) { + MD_BUG(); + err = 1; + goto abort; + } - md_update_sb(MINOR(dev)); + if (spare_desc->raid_disk != sdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (sdisk->raid_disk != spare_disk) { + MD_BUG(); + err = 1; + goto abort; + } - printk (HOT_ADD_SUCCEEDED, kdevname(realdev->dev)); + if (failed_desc->raid_disk != fdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } - return 0; -} + if (fdisk->raid_disk != failed_disk) { + MD_BUG(); + err = 1; + goto abort; + } -#undef NO_SUPERBLOCK -#undef WRONG_LEVEL -#undef HOT_ADD_SUCCEEDED + /* + * do the switch finally + */ + xchg_values(*spare_desc, *failed_desc); + xchg_values(*fdisk, *sdisk); -/* - * Insert the spare disk into the drive-ring - */ -static void add_ring(struct raid1_data *raid_conf, struct mirror_info *mirror) -{ - int j, next; - struct mirror_info *p = raid_conf->mirrors; + /* + * (careful, 'failed' and 'spare' are switched from now on) + * + * we want to preserve linear numbering and we want to + * give the proper raid_disk number to the now activated + * disk. (this means we switch back these values) + */ + + xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); + xchg_values(sdisk->raid_disk, fdisk->raid_disk); + xchg_values(spare_desc->number, failed_desc->number); + xchg_values(sdisk->number, fdisk->number); - for (j = 0; j < raid_conf->raid_disks; j++, p++) - if (p->operational && !p->write_only) { - next = p->next; - p->next = mirror->raid_disk; - mirror->next = next; - return; - } - printk("raid1: bug: no read-operational devices\n"); -} + *d = failed_desc; -static int raid1_mark_spare(struct md_dev *mddev, md_descriptor_t *spare, - int state) -{ - int i = 0, failed_disk = -1; - struct raid1_data *raid_conf = mddev->private; - struct mirror_info *mirror = raid_conf->mirrors; - md_descriptor_t *descriptor; - unsigned long flags; + if (sdisk->dev == MKDEV(0,0)) + sdisk->used_slot = 0; + /* + * this really activates the spare. + */ + fdisk->spare = 0; + fdisk->write_only = 0; + link_disk(conf, fdisk); - for (i = 0; i < MD_SB_DISKS; i++, mirror++) { - if (mirror->spare && mirror->number == spare->number) - goto found; - } - return 1; -found: - for (i = 0, mirror = raid_conf->mirrors; i < raid_conf->raid_disks; - i++, mirror++) - if (!mirror->operational) - failed_disk = i; + /* + * if we activate a spare, we definitely replace a + * non-operational disk slot in the 'low' area of + * the disk array. + */ - save_flags(flags); - cli(); - switch (state) { - case SPARE_WRITE: - mirror->operational = 1; - mirror->write_only = 1; - raid_conf->raid_disks = MAX(raid_conf->raid_disks, - mirror->raid_disk + 1); - break; - case SPARE_INACTIVE: - mirror->operational = 0; - mirror->write_only = 0; - break; - case SPARE_ACTIVE: - mirror->spare = 0; - mirror->write_only = 0; - raid_conf->working_disks++; - add_ring(raid_conf, mirror); - - if (failed_disk != -1) { - descriptor = &mddev->sb->disks[raid_conf->mirrors[failed_disk].number]; - i = spare->raid_disk; - spare->raid_disk = descriptor->raid_disk; - descriptor->raid_disk = i; - } - break; - default: - printk("raid1_mark_spare: bug: state == %d\n", state); - restore_flags(flags); - return 1; + conf->working_disks++; + + break; + + case DISKOP_HOT_REMOVE_DISK: + rdisk = conf->mirrors + removed_disk; + + if (rdisk->spare && (removed_disk < conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + rdisk->dev = MKDEV(0,0); + rdisk->used_slot = 0; + conf->nr_disks--; + break; + + case DISKOP_HOT_ADD_DISK: + adisk = conf->mirrors + added_disk; + added_desc = *d; + + if (added_disk != added_desc->number) { + MD_BUG(); + err = 1; + goto abort; + } + + adisk->number = added_desc->number; + adisk->raid_disk = added_desc->raid_disk; + adisk->dev = MKDEV(added_desc->major,added_desc->minor); + + adisk->operational = 0; + adisk->write_only = 0; + adisk->spare = 1; + adisk->used_slot = 1; + conf->nr_disks++; + + break; + + default: + MD_BUG(); + err = 1; + goto abort; } +abort: restore_flags(flags); - return 0; + print_raid1_conf(conf); + return err; } + +#define IO_ERROR KERN_ALERT \ +"raid1: %s: unrecoverable I/O read error for block %lu\n" + +#define REDIRECT_SECTOR KERN_ERR \ +"raid1: %s: redirecting sector %lu to another mirror\n" + /* * This is a kernel thread which: * * 1. Retries failed read operations on working mirrors. * 2. Updates the raid superblock when problems encounter. */ -void raid1d (void *data) +static void raid1d (void *data) { struct buffer_head *bh; kdev_t dev; unsigned long flags; - struct raid1_bh * r1_bh; - struct md_dev *mddev; + struct raid1_bh *r1_bh; + mddev_t *mddev; - PRINTK(("raid1d() active\n")); - save_flags(flags); - cli(); while (raid1_retry_list) { + save_flags(flags); + cli(); bh = raid1_retry_list; r1_bh = (struct raid1_bh *)(bh->b_dev_id); raid1_retry_list = r1_bh->next_retry; restore_flags(flags); - mddev = md_dev + MINOR(bh->b_dev); + mddev = kdev_to_mddev(bh->b_dev); if (mddev->sb_dirty) { - printk("dirty sb detected, updating.\n"); + printk(KERN_INFO "dirty sb detected, updating.\n"); mddev->sb_dirty = 0; - md_update_sb(MINOR(bh->b_dev)); + md_update_sb(mddev); } dev = bh->b_rdev; - __raid1_map (md_dev + MINOR(bh->b_dev), &bh->b_rdev, &bh->b_rsector, bh->b_size >> 9); + __raid1_map (mddev, &bh->b_rdev, &bh->b_rsector, + bh->b_size >> 9); if (bh->b_rdev == dev) { - printk (KERN_ALERT - "raid1: %s: unrecoverable I/O read error for block %lu\n", - kdevname(bh->b_dev), bh->b_blocknr); - raid1_end_buffer_io(r1_bh, 0); + printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); + raid1_end_bh_io(r1_bh, 0); } else { - printk (KERN_ERR "raid1: %s: redirecting sector %lu to another mirror\n", - kdevname(bh->b_dev), bh->b_blocknr); + printk (REDIRECT_SECTOR, + partition_name(bh->b_dev), bh->b_blocknr); map_and_make_request (r1_bh->cmd, bh); } - cli(); } - restore_flags(flags); } +#undef IO_ERROR +#undef REDIRECT_SECTOR + +/* + * Private kernel thread to reconstruct mirrors after an unclean + * shutdown. + */ +static void raid1syncd (void *data) +{ + raid1_conf_t *conf = data; + mddev_t *mddev = conf->mddev; + + if (!conf->resync_mirrors) + return; + if (conf->resync_mirrors == 2) + return; + down(&mddev->recovery_sem); + if (md_do_sync(mddev, NULL)) { + up(&mddev->recovery_sem); + return; + } + /* + * Only if everything went Ok. + */ + conf->resync_mirrors = 0; + up(&mddev->recovery_sem); +} + /* * This will catch the scenario in which one of the mirrors was * mounted as a normal device rather than as a part of a raid set. + * + * check_consistency is very personality-dependent, eg. RAID5 cannot + * do this check, it uses another method. */ -static int __check_consistency (struct md_dev *mddev, int row) +static int __check_consistency (mddev_t *mddev, int row) { - struct raid1_data *raid_conf = mddev->private; + raid1_conf_t *conf = mddev_to_conf(mddev); + int disks = MD_SB_DISKS; kdev_t dev; struct buffer_head *bh = NULL; int i, rc = 0; char *buffer = NULL; - for (i = 0; i < raid_conf->raid_disks; i++) { - if (!raid_conf->mirrors[i].operational) + for (i = 0; i < disks; i++) { + printk("(checking disk %d)\n",i); + if (!conf->mirrors[i].operational) continue; - dev = raid_conf->mirrors[i].dev; + printk("(really checking disk %d)\n",i); + dev = conf->mirrors[i].dev; set_blocksize(dev, 4096); if ((bh = bread(dev, row / 4, 4096)) == NULL) break; @@ -675,163 +864,342 @@ return rc; } -static int check_consistency (struct md_dev *mddev) +static int check_consistency (mddev_t *mddev) { - int size = mddev->sb->size; - int row; + if (__check_consistency(mddev, 0)) +/* + * we do not do this currently, as it's perfectly possible to + * have an inconsistent array when it's freshly created. Only + * newly written data has to be consistent. + */ + return 0; - for (row = 0; row < size; row += size / 8) - if (__check_consistency(mddev, row)) - return 1; return 0; } -static int raid1_run (int minor, struct md_dev *mddev) +#define INVALID_LEVEL KERN_WARNING \ +"raid1: md%d: raid level not set to mirroring (%d)\n" + +#define NO_SB KERN_ERR \ +"raid1: disabled mirror %s (couldn't access raid superblock)\n" + +#define ERRORS KERN_ERR \ +"raid1: disabled mirror %s (errors detected)\n" + +#define NOT_IN_SYNC KERN_ERR \ +"raid1: disabled mirror %s (not in sync)\n" + +#define INCONSISTENT KERN_ERR \ +"raid1: disabled mirror %s (inconsistent descriptor)\n" + +#define ALREADY_RUNNING KERN_ERR \ +"raid1: disabled mirror %s (mirror %d already operational)\n" + +#define OPERATIONAL KERN_INFO \ +"raid1: device %s operational as mirror %d\n" + +#define MEM_ERROR KERN_ERR \ +"raid1: couldn't allocate memory for md%d\n" + +#define SPARE KERN_INFO \ +"raid1: spare disk %s\n" + +#define NONE_OPERATIONAL KERN_ERR \ +"raid1: no operational mirrors for md%d\n" + +#define RUNNING_CKRAID KERN_ERR \ +"raid1: detected mirror differences -- running resync\n" + +#define ARRAY_IS_ACTIVE KERN_INFO \ +"raid1: raid set md%d active with %d out of %d mirrors\n" + +#define THREAD_ERROR KERN_ERR \ +"raid1: couldn't allocate thread for md%d\n" + +#define START_RESYNC KERN_WARNING \ +"raid1: raid set md%d not clean; reconstructing mirrors\n" + +static int raid1_run (mddev_t *mddev) { - struct raid1_data *raid_conf; - int i, j, raid_disk; - md_superblock_t *sb = mddev->sb; - md_descriptor_t *descriptor; - struct real_dev *realdev; + raid1_conf_t *conf; + int i, j, disk_idx; + struct mirror_info *disk; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *descriptor; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + int start_recovery = 0; MOD_INC_USE_COUNT; if (sb->level != 1) { - printk("raid1: %s: raid level not set to mirroring (%d)\n", - kdevname(MKDEV(MD_MAJOR, minor)), sb->level); - MOD_DEC_USE_COUNT; - return -EIO; - } - /**** - * copy the now verified devices into our private RAID1 bookkeeping - * area. [whatever we allocate in raid1_run(), should be freed in - * raid1_stop()] - */ - - while (!( /* FIXME: now we are rather fault tolerant than nice */ - mddev->private = kmalloc (sizeof (struct raid1_data), GFP_KERNEL) - ) ) - printk ("raid1_run(): out of memory\n"); - raid_conf = mddev->private; - memset(raid_conf, 0, sizeof(*raid_conf)); - - PRINTK(("raid1_run(%d) called.\n", minor)); - - for (i = 0; i < mddev->nb_dev; i++) { - realdev = &mddev->devices[i]; - if (!realdev->sb) { - printk(KERN_ERR "raid1: disabled mirror %s (couldn't access raid superblock)\n", kdevname(realdev->dev)); + printk(INVALID_LEVEL, mdidx(mddev), sb->level); + goto out; + } + /* + * copy the already verified devices into our private RAID1 + * bookkeeping area. [whatever we allocate in raid1_run(), + * should be freed in raid1_stop()] + */ + + conf = raid1_kmalloc(sizeof(raid1_conf_t)); + mddev->private = conf; + if (!conf) { + printk(MEM_ERROR, mdidx(mddev)); + goto out; + } + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + printk(ERRORS, partition_name(rdev->dev)); + } else { + if (!rdev->sb) { + MD_BUG(); + continue; + } + } + if (rdev->desc_nr == -1) { + MD_BUG(); continue; } - - /* - * This is important -- we are using the descriptor on - * the disk only to get a pointer to the descriptor on - * the main superblock, which might be more recent. - */ - descriptor = &sb->disks[realdev->sb->descriptor.number]; - if (descriptor->state & (1 << MD_FAULTY_DEVICE)) { - printk(KERN_ERR "raid1: disabled mirror %s (errors detected)\n", kdevname(realdev->dev)); + descriptor = &sb->disks[rdev->desc_nr]; + disk_idx = descriptor->raid_disk; + disk = conf->mirrors + disk_idx; + + if (disk_faulty(descriptor)) { + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_LINEAR_SECTORS; + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; continue; } - if (descriptor->state & (1 << MD_ACTIVE_DEVICE)) { - if (!(descriptor->state & (1 << MD_SYNC_DEVICE))) { - printk(KERN_ERR "raid1: disabled mirror %s (not in sync)\n", kdevname(realdev->dev)); + if (disk_active(descriptor)) { + if (!disk_sync(descriptor)) { + printk(NOT_IN_SYNC, + partition_name(rdev->dev)); continue; } - raid_disk = descriptor->raid_disk; - if (descriptor->number > sb->nr_disks || raid_disk > sb->raid_disks) { - printk(KERN_ERR "raid1: disabled mirror %s (inconsistent descriptor)\n", kdevname(realdev->dev)); + if ((descriptor->number > MD_SB_DISKS) || + (disk_idx > sb->raid_disks)) { + + printk(INCONSISTENT, + partition_name(rdev->dev)); continue; } - if (raid_conf->mirrors[raid_disk].operational) { - printk(KERN_ERR "raid1: disabled mirror %s (mirror %d already operational)\n", kdevname(realdev->dev), raid_disk); + if (disk->operational) { + printk(ALREADY_RUNNING, + partition_name(rdev->dev), + disk_idx); continue; } - printk(KERN_INFO "raid1: device %s operational as mirror %d\n", kdevname(realdev->dev), raid_disk); - raid_conf->mirrors[raid_disk].number = descriptor->number; - raid_conf->mirrors[raid_disk].raid_disk = raid_disk; - raid_conf->mirrors[raid_disk].dev = mddev->devices [i].dev; - raid_conf->mirrors[raid_disk].operational = 1; - raid_conf->mirrors[raid_disk].sect_limit = 128; - raid_conf->working_disks++; + printk(OPERATIONAL, partition_name(rdev->dev), + disk_idx); + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_LINEAR_SECTORS; + disk->operational = 1; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + conf->working_disks++; } else { /* * Must be a spare disk .. */ - printk(KERN_INFO "raid1: spare disk %s\n", kdevname(realdev->dev)); - raid_disk = descriptor->raid_disk; - raid_conf->mirrors[raid_disk].number = descriptor->number; - raid_conf->mirrors[raid_disk].raid_disk = raid_disk; - raid_conf->mirrors[raid_disk].dev = mddev->devices [i].dev; - raid_conf->mirrors[raid_disk].sect_limit = 128; - - raid_conf->mirrors[raid_disk].operational = 0; - raid_conf->mirrors[raid_disk].write_only = 0; - raid_conf->mirrors[raid_disk].spare = 1; - } - } - if (!raid_conf->working_disks) { - printk(KERN_ERR "raid1: no operational mirrors for %s\n", kdevname(MKDEV(MD_MAJOR, minor))); - kfree(raid_conf); - mddev->private = NULL; - MOD_DEC_USE_COUNT; - return -EIO; - } - - raid_conf->raid_disks = sb->raid_disks; - raid_conf->mddev = mddev; - - for (j = 0; !raid_conf->mirrors[j].operational; j++); - raid_conf->last_used = j; - for (i = raid_conf->raid_disks - 1; i >= 0; i--) { - if (raid_conf->mirrors[i].operational) { - PRINTK(("raid_conf->mirrors[%d].next == %d\n", i, j)); - raid_conf->mirrors[i].next = j; + printk(SPARE, partition_name(rdev->dev)); + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_LINEAR_SECTORS; + disk->operational = 0; + disk->write_only = 0; + disk->spare = 1; + disk->used_slot = 1; + } + } + if (!conf->working_disks) { + printk(NONE_OPERATIONAL, mdidx(mddev)); + goto out_free_conf; + } + + conf->raid_disks = sb->raid_disks; + conf->nr_disks = sb->nr_disks; + conf->mddev = mddev; + + for (i = 0; i < MD_SB_DISKS; i++) { + + descriptor = sb->disks+i; + disk_idx = descriptor->raid_disk; + disk = conf->mirrors + disk_idx; + + if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && + !disk->used_slot) { + + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = MKDEV(0,0); + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + } + } + + /* + * find the first working one and use it as a starting point + * to read balancing. + */ + for (j = 0; !conf->mirrors[j].operational; j++) + /* nothing */; + conf->last_used = j; + + /* + * initialize the 'working disks' list. + */ + for (i = conf->raid_disks - 1; i >= 0; i--) { + if (conf->mirrors[i].operational) { + conf->mirrors[i].next = j; j = i; } } - if (check_consistency(mddev)) { - printk(KERN_ERR "raid1: detected mirror differences -- run ckraid\n"); - sb->state |= 1 << MD_SB_ERRORS; - kfree(raid_conf); - mddev->private = NULL; - MOD_DEC_USE_COUNT; - return -EIO; + if (conf->working_disks != sb->raid_disks) { + printk(KERN_ALERT "raid1: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); + start_recovery = 1; } + if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { + /* + * we do sanity checks even if the device says + * it's clean ... + */ + if (check_consistency(mddev)) { + printk(RUNNING_CKRAID); + sb->state &= ~(1 << MD_SB_CLEAN); + } + } + + { + const char * name = "raid1d"; + + conf->thread = md_register_thread(raid1d, conf, name); + if (!conf->thread) { + printk(THREAD_ERROR, mdidx(mddev)); + goto out_free_conf; + } + } + + if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { + const char * name = "raid1syncd"; + + conf->resync_thread = md_register_thread(raid1syncd, conf,name); + if (!conf->resync_thread) { + printk(THREAD_ERROR, mdidx(mddev)); + goto out_free_conf; + } + + printk(START_RESYNC, mdidx(mddev)); + conf->resync_mirrors = 1; + md_wakeup_thread(conf->resync_thread); + } + /* * Regenerate the "device is in sync with the raid set" bit for * each device. */ - for (i = 0; i < sb->nr_disks ; i++) { - sb->disks[i].state &= ~(1 << MD_SYNC_DEVICE); + for (i = 0; i < MD_SB_DISKS; i++) { + mark_disk_nonsync(sb->disks+i); for (j = 0; j < sb->raid_disks; j++) { - if (!raid_conf->mirrors[j].operational) + if (!conf->mirrors[j].operational) continue; - if (sb->disks[i].number == raid_conf->mirrors[j].number) - sb->disks[i].state |= 1 << MD_SYNC_DEVICE; + if (sb->disks[i].number == conf->mirrors[j].number) + mark_disk_sync(sb->disks+i); } } - sb->active_disks = raid_conf->working_disks; + sb->active_disks = conf->working_disks; - printk("raid1: raid set %s active with %d out of %d mirrors\n", kdevname(MKDEV(MD_MAJOR, minor)), sb->active_disks, sb->raid_disks); - /* Ok, everything is just fine now */ - return (0); + if (start_recovery) + md_recover_arrays(); + + + printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); + /* + * Ok, everything is just fine now + */ + return 0; + +out_free_conf: + kfree(conf); + mddev->private = NULL; +out: + MOD_DEC_USE_COUNT; + return -EIO; +} + +#undef INVALID_LEVEL +#undef NO_SB +#undef ERRORS +#undef NOT_IN_SYNC +#undef INCONSISTENT +#undef ALREADY_RUNNING +#undef OPERATIONAL +#undef SPARE +#undef NONE_OPERATIONAL +#undef RUNNING_CKRAID +#undef ARRAY_IS_ACTIVE + +static int raid1_stop_resync (mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + + if (conf->resync_thread) { + if (conf->resync_mirrors) { + conf->resync_mirrors = 2; + md_interrupt_thread(conf->resync_thread); + printk(KERN_INFO "raid1: mirror resync was not fully finished, restarting next time.\n"); + return 1; + } + return 0; + } + return 0; +} + +static int raid1_restart_resync (mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + + if (conf->resync_mirrors) { + if (!conf->resync_thread) { + MD_BUG(); + return 0; + } + conf->resync_mirrors = 1; + md_wakeup_thread(conf->resync_thread); + return 1; + } + return 0; } -static int raid1_stop (int minor, struct md_dev *mddev) +static int raid1_stop (mddev_t *mddev) { - struct raid1_data *raid_conf = (struct raid1_data *) mddev->private; + raid1_conf_t *conf = mddev_to_conf(mddev); - kfree (raid_conf); + md_unregister_thread(conf->thread); + if (conf->resync_thread) + md_unregister_thread(conf->resync_thread); + kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; return 0; } -static struct md_personality raid1_personality= +static mdk_personality_t raid1_personality= { "raid1", raid1_map, @@ -843,15 +1211,13 @@ NULL, /* no ioctls */ 0, raid1_error, - raid1_hot_add_disk, - /* raid1_hot_remove_drive */ NULL, - raid1_mark_spare + raid1_diskop, + raid1_stop_resync, + raid1_restart_resync }; int raid1_init (void) { - if ((raid1_thread = md_register_thread(raid1d, NULL)) == NULL) - return -EBUSY; return register_md_personality (RAID1, &raid1_personality); } @@ -863,7 +1229,6 @@ void cleanup_module (void) { - md_unregister_thread (raid1_thread); unregister_md_personality (RAID1); } #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/raid5.c linux.ac/drivers/block/raid5.c --- linux.vanilla/drivers/block/raid5.c Sun Nov 8 15:07:37 1998 +++ linux.ac/drivers/block/raid5.c Mon Jul 19 03:26:58 1999 @@ -1,4 +1,4 @@ -/***************************************************************************** +/* * raid5.c : Multiple Devices driver for Linux * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman * @@ -14,16 +14,15 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include -#include -#include +#include #include #include -#include -static struct md_personality raid5_personality; +static mdk_personality_t raid5_personality; /* * Stripe cache @@ -33,7 +32,7 @@ #define HASH_PAGES_ORDER 0 #define NR_HASH (HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *)) #define HASH_MASK (NR_HASH - 1) -#define stripe_hash(raid_conf, sect, size) ((raid_conf)->stripe_hashtbl[((sect) / (size >> 9)) & HASH_MASK]) +#define stripe_hash(conf, sect, size) ((conf)->stripe_hashtbl[((sect) / (size >> 9)) & HASH_MASK]) /* * The following can be used to debug the driver @@ -46,6 +45,8 @@ #define PRINTK(x) do { ; } while (0) #endif +static void print_raid5_conf (raid5_conf_t *conf); + static inline int stripe_locked(struct stripe_head *sh) { return test_bit(STRIPE_LOCKED, &sh->state); @@ -61,32 +62,32 @@ */ static inline void lock_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; - if (!test_and_set_bit(STRIPE_LOCKED, &sh->state)) { + raid5_conf_t *conf = sh->raid_conf; + if (!md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) { PRINTK(("locking stripe %lu\n", sh->sector)); - raid_conf->nr_locked_stripes++; + conf->nr_locked_stripes++; } } static inline void unlock_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; - if (test_and_clear_bit(STRIPE_LOCKED, &sh->state)) { + raid5_conf_t *conf = sh->raid_conf; + if (md_test_and_clear_bit(STRIPE_LOCKED, &sh->state)) { PRINTK(("unlocking stripe %lu\n", sh->sector)); - raid_conf->nr_locked_stripes--; + conf->nr_locked_stripes--; wake_up(&sh->wait); } } static inline void finish_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; + raid5_conf_t *conf = sh->raid_conf; unlock_stripe(sh); sh->cmd = STRIPE_NONE; sh->phase = PHASE_COMPLETE; - raid_conf->nr_pending_stripes--; - raid_conf->nr_cached_stripes++; - wake_up(&raid_conf->wait_for_stripe); + conf->nr_pending_stripes--; + conf->nr_cached_stripes++; + wake_up(&conf->wait_for_stripe); } void __wait_on_stripe(struct stripe_head *sh) @@ -114,7 +115,7 @@ __wait_on_stripe(sh); } -static inline void remove_hash(struct raid5_data *raid_conf, struct stripe_head *sh) +static inline void remove_hash(raid5_conf_t *conf, struct stripe_head *sh) { PRINTK(("remove_hash(), stripe %lu\n", sh->sector)); @@ -123,21 +124,22 @@ sh->hash_next->hash_pprev = sh->hash_pprev; *sh->hash_pprev = sh->hash_next; sh->hash_pprev = NULL; - raid_conf->nr_hashed_stripes--; + conf->nr_hashed_stripes--; } } -static inline void insert_hash(struct raid5_data *raid_conf, struct stripe_head *sh) +static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) { - struct stripe_head **shp = &stripe_hash(raid_conf, sh->sector, sh->size); + struct stripe_head **shp = &stripe_hash(conf, sh->sector, sh->size); - PRINTK(("insert_hash(), stripe %lu, nr_hashed_stripes %d\n", sh->sector, raid_conf->nr_hashed_stripes)); + PRINTK(("insert_hash(), stripe %lu, nr_hashed_stripes %d\n", + sh->sector, conf->nr_hashed_stripes)); if ((sh->hash_next = *shp) != NULL) (*shp)->hash_pprev = &sh->hash_next; *shp = sh; sh->hash_pprev = shp; - raid_conf->nr_hashed_stripes++; + conf->nr_hashed_stripes++; } static struct buffer_head *get_free_buffer(struct stripe_head *sh, int b_size) @@ -145,13 +147,15 @@ struct buffer_head *bh; unsigned long flags; - save_flags(flags); - cli(); - if ((bh = sh->buffer_pool) == NULL) - return NULL; + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh = sh->buffer_pool; + if (!bh) + goto out_unlock; sh->buffer_pool = bh->b_next; bh->b_size = b_size; - restore_flags(flags); +out_unlock: + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); + return bh; } @@ -160,12 +164,14 @@ struct buffer_head *bh; unsigned long flags; - save_flags(flags); - cli(); - if ((bh = sh->bh_pool) == NULL) - return NULL; + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh = sh->bh_pool; + if (!bh) + goto out_unlock; sh->bh_pool = bh->b_next; - restore_flags(flags); +out_unlock: + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); + return bh; } @@ -173,54 +179,52 @@ { unsigned long flags; - save_flags(flags); - cli(); + md_spin_lock_irqsave(&sh->stripe_lock, flags); bh->b_next = sh->buffer_pool; sh->buffer_pool = bh; - restore_flags(flags); + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); } static void put_free_bh(struct stripe_head *sh, struct buffer_head *bh) { unsigned long flags; - save_flags(flags); - cli(); + md_spin_lock_irqsave(&sh->stripe_lock, flags); bh->b_next = sh->bh_pool; sh->bh_pool = bh; - restore_flags(flags); + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); } -static struct stripe_head *get_free_stripe(struct raid5_data *raid_conf) +static struct stripe_head *get_free_stripe(raid5_conf_t *conf) { struct stripe_head *sh; unsigned long flags; save_flags(flags); cli(); - if ((sh = raid_conf->free_sh_list) == NULL) { + if ((sh = conf->free_sh_list) == NULL) { restore_flags(flags); return NULL; } - raid_conf->free_sh_list = sh->free_next; - raid_conf->nr_free_sh--; - if (!raid_conf->nr_free_sh && raid_conf->free_sh_list) + conf->free_sh_list = sh->free_next; + conf->nr_free_sh--; + if (!conf->nr_free_sh && conf->free_sh_list) printk ("raid5: bug: free_sh_list != NULL, nr_free_sh == 0\n"); restore_flags(flags); - if (sh->hash_pprev || sh->nr_pending || sh->count) + if (sh->hash_pprev || md_atomic_read(&sh->nr_pending) || sh->count) printk("get_free_stripe(): bug\n"); return sh; } -static void put_free_stripe(struct raid5_data *raid_conf, struct stripe_head *sh) +static void put_free_stripe(raid5_conf_t *conf, struct stripe_head *sh) { unsigned long flags; save_flags(flags); cli(); - sh->free_next = raid_conf->free_sh_list; - raid_conf->free_sh_list = sh; - raid_conf->nr_free_sh++; + sh->free_next = conf->free_sh_list; + conf->free_sh_list = sh; + conf->nr_free_sh++; restore_flags(flags); } @@ -324,8 +328,8 @@ static void kfree_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; - int disks = raid_conf->raid_disks, j; + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks, j; PRINTK(("kfree_stripe called, stripe %lu\n", sh->sector)); if (sh->phase != PHASE_COMPLETE || stripe_locked(sh) || sh->count) { @@ -338,19 +342,19 @@ if (sh->bh_new[j] || sh->bh_copy[j]) printk("raid5: bug: sector %lu, new %p, copy %p\n", sh->sector, sh->bh_new[j], sh->bh_copy[j]); } - remove_hash(raid_conf, sh); - put_free_stripe(raid_conf, sh); + remove_hash(conf, sh); + put_free_stripe(conf, sh); } -static int shrink_stripe_cache(struct raid5_data *raid_conf, int nr) +static int shrink_stripe_cache(raid5_conf_t *conf, int nr) { struct stripe_head *sh; int i, count = 0; - PRINTK(("shrink_stripe_cache called, %d/%d, clock %d\n", nr, raid_conf->nr_hashed_stripes, raid_conf->clock)); + PRINTK(("shrink_stripe_cache called, %d/%d, clock %d\n", nr, conf->nr_hashed_stripes, conf->clock)); for (i = 0; i < NR_HASH; i++) { repeat: - sh = raid_conf->stripe_hashtbl[(i + raid_conf->clock) & HASH_MASK]; + sh = conf->stripe_hashtbl[(i + conf->clock) & HASH_MASK]; for (; sh; sh = sh->hash_next) { if (sh->phase != PHASE_COMPLETE) continue; @@ -360,30 +364,30 @@ continue; kfree_stripe(sh); if (++count == nr) { - PRINTK(("shrink completed, nr_hashed_stripes %d\n", raid_conf->nr_hashed_stripes)); - raid_conf->clock = (i + raid_conf->clock) & HASH_MASK; + PRINTK(("shrink completed, nr_hashed_stripes %d\n", conf->nr_hashed_stripes)); + conf->clock = (i + conf->clock) & HASH_MASK; return nr; } goto repeat; } } - PRINTK(("shrink completed, nr_hashed_stripes %d\n", raid_conf->nr_hashed_stripes)); + PRINTK(("shrink completed, nr_hashed_stripes %d\n", conf->nr_hashed_stripes)); return count; } -static struct stripe_head *find_stripe(struct raid5_data *raid_conf, unsigned long sector, int size) +static struct stripe_head *find_stripe(raid5_conf_t *conf, unsigned long sector, int size) { struct stripe_head *sh; - if (raid_conf->buffer_size != size) { - PRINTK(("switching size, %d --> %d\n", raid_conf->buffer_size, size)); - shrink_stripe_cache(raid_conf, raid_conf->max_nr_stripes); - raid_conf->buffer_size = size; + if (conf->buffer_size != size) { + PRINTK(("switching size, %d --> %d\n", conf->buffer_size, size)); + shrink_stripe_cache(conf, conf->max_nr_stripes); + conf->buffer_size = size; } PRINTK(("find_stripe, sector %lu\n", sector)); - for (sh = stripe_hash(raid_conf, sector, size); sh; sh = sh->hash_next) - if (sh->sector == sector && sh->raid_conf == raid_conf) { + for (sh = stripe_hash(conf, sector, size); sh; sh = sh->hash_next) + if (sh->sector == sector && sh->raid_conf == conf) { if (sh->size == size) { PRINTK(("found stripe %lu\n", sector)); return sh; @@ -397,7 +401,7 @@ return NULL; } -static int grow_stripes(struct raid5_data *raid_conf, int num, int priority) +static int grow_stripes(raid5_conf_t *conf, int num, int priority) { struct stripe_head *sh; @@ -405,62 +409,64 @@ if ((sh = kmalloc(sizeof(struct stripe_head), priority)) == NULL) return 1; memset(sh, 0, sizeof(*sh)); - if (grow_buffers(sh, 2 * raid_conf->raid_disks, PAGE_SIZE, priority)) { - shrink_buffers(sh, 2 * raid_conf->raid_disks); + sh->stripe_lock = MD_SPIN_LOCK_UNLOCKED; + + if (grow_buffers(sh, 2 * conf->raid_disks, PAGE_SIZE, priority)) { + shrink_buffers(sh, 2 * conf->raid_disks); kfree(sh); return 1; } - if (grow_bh(sh, raid_conf->raid_disks, priority)) { - shrink_buffers(sh, 2 * raid_conf->raid_disks); - shrink_bh(sh, raid_conf->raid_disks); + if (grow_bh(sh, conf->raid_disks, priority)) { + shrink_buffers(sh, 2 * conf->raid_disks); + shrink_bh(sh, conf->raid_disks); kfree(sh); return 1; } - put_free_stripe(raid_conf, sh); - raid_conf->nr_stripes++; + put_free_stripe(conf, sh); + conf->nr_stripes++; } return 0; } -static void shrink_stripes(struct raid5_data *raid_conf, int num) +static void shrink_stripes(raid5_conf_t *conf, int num) { struct stripe_head *sh; while (num--) { - sh = get_free_stripe(raid_conf); + sh = get_free_stripe(conf); if (!sh) break; - shrink_buffers(sh, raid_conf->raid_disks * 2); - shrink_bh(sh, raid_conf->raid_disks); + shrink_buffers(sh, conf->raid_disks * 2); + shrink_bh(sh, conf->raid_disks); kfree(sh); - raid_conf->nr_stripes--; + conf->nr_stripes--; } } -static struct stripe_head *kmalloc_stripe(struct raid5_data *raid_conf, unsigned long sector, int size) +static struct stripe_head *kmalloc_stripe(raid5_conf_t *conf, unsigned long sector, int size) { struct stripe_head *sh = NULL, *tmp; struct buffer_head *buffer_pool, *bh_pool; PRINTK(("kmalloc_stripe called\n")); - while ((sh = get_free_stripe(raid_conf)) == NULL) { - shrink_stripe_cache(raid_conf, raid_conf->max_nr_stripes / 8); - if ((sh = get_free_stripe(raid_conf)) != NULL) + while ((sh = get_free_stripe(conf)) == NULL) { + shrink_stripe_cache(conf, conf->max_nr_stripes / 8); + if ((sh = get_free_stripe(conf)) != NULL) break; - if (!raid_conf->nr_pending_stripes) + if (!conf->nr_pending_stripes) printk("raid5: bug: nr_free_sh == 0, nr_pending_stripes == 0\n"); - md_wakeup_thread(raid_conf->thread); + md_wakeup_thread(conf->thread); PRINTK(("waiting for some stripes to complete\n")); - sleep_on(&raid_conf->wait_for_stripe); + sleep_on(&conf->wait_for_stripe); } /* * The above might have slept, so perhaps another process * already created the stripe for us.. */ - if ((tmp = find_stripe(raid_conf, sector, size)) != NULL) { - put_free_stripe(raid_conf, sh); + if ((tmp = find_stripe(conf, sector, size)) != NULL) { + put_free_stripe(conf, sh); wait_on_stripe(tmp); return tmp; } @@ -472,25 +478,25 @@ sh->bh_pool = bh_pool; sh->phase = PHASE_COMPLETE; sh->cmd = STRIPE_NONE; - sh->raid_conf = raid_conf; + sh->raid_conf = conf; sh->sector = sector; sh->size = size; - raid_conf->nr_cached_stripes++; - insert_hash(raid_conf, sh); + conf->nr_cached_stripes++; + insert_hash(conf, sh); } else printk("raid5: bug: kmalloc_stripe() == NULL\n"); return sh; } -static struct stripe_head *get_stripe(struct raid5_data *raid_conf, unsigned long sector, int size) +static struct stripe_head *get_stripe(raid5_conf_t *conf, unsigned long sector, int size) { struct stripe_head *sh; PRINTK(("get_stripe, sector %lu\n", sector)); - sh = find_stripe(raid_conf, sector, size); + sh = find_stripe(conf, sector, size); if (sh) wait_on_stripe(sh); else - sh = kmalloc_stripe(raid_conf, sector, size); + sh = kmalloc_stripe(conf, sector, size); return sh; } @@ -523,7 +529,7 @@ bh->b_end_io(bh, uptodate); if (!uptodate) printk(KERN_ALERT "raid5: %s: unrecoverable I/O error for " - "block %lu\n", kdevname(bh->b_dev), bh->b_blocknr); + "block %lu\n", partition_name(bh->b_dev), bh->b_blocknr); } static inline void raid5_mark_buffer_uptodate (struct buffer_head *bh, int uptodate) @@ -537,36 +543,35 @@ static void raid5_end_request (struct buffer_head * bh, int uptodate) { struct stripe_head *sh = bh->b_dev_id; - struct raid5_data *raid_conf = sh->raid_conf; - int disks = raid_conf->raid_disks, i; + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks, i; unsigned long flags; PRINTK(("end_request %lu, nr_pending %d\n", sh->sector, sh->nr_pending)); - save_flags(flags); - cli(); + md_spin_lock_irqsave(&sh->stripe_lock, flags); raid5_mark_buffer_uptodate(bh, uptodate); - --sh->nr_pending; - if (!sh->nr_pending) { - md_wakeup_thread(raid_conf->thread); - atomic_inc(&raid_conf->nr_handle); + if (atomic_dec_and_test(&sh->nr_pending)) { + md_wakeup_thread(conf->thread); + atomic_inc(&conf->nr_handle); } - if (!uptodate) + if (!uptodate) { md_error(bh->b_dev, bh->b_rdev); - if (raid_conf->failed_disks) { + } + if (conf->failed_disks) { for (i = 0; i < disks; i++) { - if (raid_conf->disks[i].operational) + if (conf->disks[i].operational) continue; if (bh != sh->bh_old[i] && bh != sh->bh_req[i] && bh != sh->bh_copy[i]) continue; - if (bh->b_rdev != raid_conf->disks[i].dev) + if (bh->b_rdev != conf->disks[i].dev) continue; set_bit(STRIPE_ERROR, &sh->state); } } - restore_flags(flags); + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); } -static int raid5_map (struct md_dev *mddev, kdev_t *rdev, +static int raid5_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, unsigned long *rsector, unsigned long size) { /* No complex mapping used: the core of the work is done in the @@ -577,11 +582,10 @@ static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, int i) { - struct raid5_data *raid_conf = sh->raid_conf; - struct md_dev *mddev = raid_conf->mddev; - int minor = (int) (mddev - md_dev); + raid5_conf_t *conf = sh->raid_conf; + mddev_t *mddev = conf->mddev; char *b_data; - kdev_t dev = MKDEV(MD_MAJOR, minor); + kdev_t dev = mddev_to_kdev(mddev); int block = sh->sector / (sh->size >> 9); b_data = ((volatile struct buffer_head *) bh)->b_data; @@ -589,7 +593,7 @@ init_buffer(bh, dev, block, raid5_end_request, sh); ((volatile struct buffer_head *) bh)->b_data = b_data; - bh->b_rdev = raid_conf->disks[i].dev; + bh->b_rdev = conf->disks[i].dev; bh->b_rsector = sh->sector; bh->b_state = (1 << BH_Req); @@ -597,33 +601,62 @@ bh->b_list = BUF_LOCKED; } -static int raid5_error (struct md_dev *mddev, kdev_t dev) +static int raid5_error (mddev_t *mddev, kdev_t dev) { - struct raid5_data *raid_conf = (struct raid5_data *) mddev->private; - md_superblock_t *sb = mddev->sb; + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + mdp_super_t *sb = mddev->sb; struct disk_info *disk; int i; PRINTK(("raid5_error called\n")); - raid_conf->resync_parity = 0; - for (i = 0, disk = raid_conf->disks; i < raid_conf->raid_disks; i++, disk++) + conf->resync_parity = 0; + for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) { if (disk->dev == dev && disk->operational) { disk->operational = 0; - sb->disks[disk->number].state |= (1 << MD_FAULTY_DEVICE); - sb->disks[disk->number].state &= ~(1 << MD_SYNC_DEVICE); - sb->disks[disk->number].state &= ~(1 << MD_ACTIVE_DEVICE); + mark_disk_faulty(sb->disks+disk->number); + mark_disk_nonsync(sb->disks+disk->number); + mark_disk_inactive(sb->disks+disk->number); sb->active_disks--; sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; - raid_conf->working_disks--; - raid_conf->failed_disks++; - md_wakeup_thread(raid_conf->thread); + conf->working_disks--; + conf->failed_disks++; + md_wakeup_thread(conf->thread); printk (KERN_ALERT - "RAID5: Disk failure on %s, disabling device." - "Operation continuing on %d devices\n", - kdevname (dev), raid_conf->working_disks); + "raid5: Disk failure on %s, disabling device." + " Operation continuing on %d devices\n", + partition_name (dev), conf->working_disks); + return -EIO; } + } + /* + * handle errors in spares (during reconstruction) + */ + if (conf->spare) { + disk = conf->spare; + if (disk->dev == dev) { + printk (KERN_ALERT + "raid5: Disk failure on spare %s\n", + partition_name (dev)); + if (!conf->spare->operational) { + MD_BUG(); + return -EIO; + } + disk->operational = 0; + disk->write_only = 0; + conf->spare = NULL; + mark_disk_faulty(sb->disks+disk->number); + mark_disk_nonsync(sb->disks+disk->number); + mark_disk_inactive(sb->disks+disk->number); + sb->spare_disks--; + sb->working_disks--; + sb->failed_disks++; + + return -EIO; + } + } + MD_BUG(); return 0; } @@ -634,12 +667,12 @@ static inline unsigned long raid5_compute_sector (int r_sector, unsigned int raid_disks, unsigned int data_disks, unsigned int * dd_idx, unsigned int * pd_idx, - struct raid5_data *raid_conf) + raid5_conf_t *conf) { unsigned int stripe; int chunk_number, chunk_offset; unsigned long new_sector; - int sectors_per_chunk = raid_conf->chunk_size >> 9; + int sectors_per_chunk = conf->chunk_size >> 9; /* First compute the information on this sector */ @@ -662,9 +695,9 @@ /* * Select the parity disk based on the user selected algorithm. */ - if (raid_conf->level == 4) + if (conf->level == 4) *pd_idx = data_disks; - else switch (raid_conf->algorithm) { + else switch (conf->algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: *pd_idx = data_disks - stripe % raid_disks; if (*dd_idx >= *pd_idx) @@ -684,7 +717,7 @@ *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; break; default: - printk ("raid5: unsupported algorithm %d\n", raid_conf->algorithm); + printk ("raid5: unsupported algorithm %d\n", conf->algorithm); } /* @@ -705,16 +738,16 @@ static unsigned long compute_blocknr(struct stripe_head *sh, int i) { - struct raid5_data *raid_conf = sh->raid_conf; - int raid_disks = raid_conf->raid_disks, data_disks = raid_disks - 1; + raid5_conf_t *conf = sh->raid_conf; + int raid_disks = conf->raid_disks, data_disks = raid_disks - 1; unsigned long new_sector = sh->sector, check; - int sectors_per_chunk = raid_conf->chunk_size >> 9; + int sectors_per_chunk = conf->chunk_size >> 9; unsigned long stripe = new_sector / sectors_per_chunk; int chunk_offset = new_sector % sectors_per_chunk; int chunk_number, dummy1, dummy2, dd_idx = i; unsigned long r_sector, blocknr; - switch (raid_conf->algorithm) { + switch (conf->algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: case ALGORITHM_RIGHT_ASYMMETRIC: if (i > sh->pd_idx) @@ -727,14 +760,14 @@ i -= (sh->pd_idx + 1); break; default: - printk ("raid5: unsupported algorithm %d\n", raid_conf->algorithm); + printk ("raid5: unsupported algorithm %d\n", conf->algorithm); } chunk_number = stripe * data_disks + i; r_sector = chunk_number * sectors_per_chunk + chunk_offset; blocknr = r_sector / (sh->size >> 9); - check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, raid_conf); + check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { printk("compute_blocknr: map not correct\n"); return 0; @@ -742,36 +775,11 @@ return blocknr; } -#ifdef HAVE_ARCH_XORBLOCK -static void xor_block(struct buffer_head *dest, struct buffer_head *source) -{ - __xor_block((char *) dest->b_data, (char *) source->b_data, dest->b_size); -} -#else -static void xor_block(struct buffer_head *dest, struct buffer_head *source) -{ - long lines = dest->b_size / (sizeof (long)) / 8, i; - long *destp = (long *) dest->b_data, *sourcep = (long *) source->b_data; - - for (i = lines; i > 0; i--) { - *(destp + 0) ^= *(sourcep + 0); - *(destp + 1) ^= *(sourcep + 1); - *(destp + 2) ^= *(sourcep + 2); - *(destp + 3) ^= *(sourcep + 3); - *(destp + 4) ^= *(sourcep + 4); - *(destp + 5) ^= *(sourcep + 5); - *(destp + 6) ^= *(sourcep + 6); - *(destp + 7) ^= *(sourcep + 7); - destp += 8; - sourcep += 8; - } -} -#endif - static void compute_block(struct stripe_head *sh, int dd_idx) { - struct raid5_data *raid_conf = sh->raid_conf; - int i, disks = raid_conf->raid_disks; + raid5_conf_t *conf = sh->raid_conf; + int i, count, disks = conf->raid_disks; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; PRINTK(("compute_block, stripe %lu, idx %d\n", sh->sector, dd_idx)); @@ -780,69 +788,100 @@ raid5_build_block(sh, sh->bh_old[dd_idx], dd_idx); memset(sh->bh_old[dd_idx]->b_data, 0, sh->size); + bh_ptr[0] = sh->bh_old[dd_idx]; + count = 1; for (i = 0; i < disks; i++) { if (i == dd_idx) continue; if (sh->bh_old[i]) { - xor_block(sh->bh_old[dd_idx], sh->bh_old[i]); - continue; - } else + bh_ptr[count++] = sh->bh_old[i]; + } else { printk("compute_block() %d, stripe %lu, %d not present\n", dd_idx, sh->sector, i); + } + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if(count != 1) { + xor_block(count, &bh_ptr[0]); } raid5_mark_buffer_uptodate(sh->bh_old[dd_idx], 1); } static void compute_parity(struct stripe_head *sh, int method) { - struct raid5_data *raid_conf = sh->raid_conf; - int i, pd_idx = sh->pd_idx, disks = raid_conf->raid_disks; + raid5_conf_t *conf = sh->raid_conf; + int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, lowprio, count; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; PRINTK(("compute_parity, stripe %lu, method %d\n", sh->sector, method)); + lowprio = 1; for (i = 0; i < disks; i++) { if (i == pd_idx || !sh->bh_new[i]) continue; if (!sh->bh_copy[i]) sh->bh_copy[i] = raid5_kmalloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_copy[i], i); + if (!buffer_lowprio(sh->bh_new[i])) + lowprio = 0; + else + mark_buffer_lowprio(sh->bh_copy[i]); mark_buffer_clean(sh->bh_new[i]); memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size); } if (sh->bh_copy[pd_idx] == NULL) sh->bh_copy[pd_idx] = raid5_kmalloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_copy[pd_idx], sh->pd_idx); + if (lowprio) + mark_buffer_lowprio(sh->bh_copy[pd_idx]); if (method == RECONSTRUCT_WRITE) { memset(sh->bh_copy[pd_idx]->b_data, 0, sh->size); + bh_ptr[0] = sh->bh_copy[pd_idx]; + count = 1; for (i = 0; i < disks; i++) { if (i == sh->pd_idx) continue; if (sh->bh_new[i]) { - xor_block(sh->bh_copy[pd_idx], sh->bh_copy[i]); - continue; + bh_ptr[count++] = sh->bh_copy[i]; + } else if (sh->bh_old[i]) { + bh_ptr[count++] = sh->bh_old[i]; } - if (sh->bh_old[i]) { - xor_block(sh->bh_copy[pd_idx], sh->bh_old[i]); - continue; + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; } } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } } else if (method == READ_MODIFY_WRITE) { memcpy(sh->bh_copy[pd_idx]->b_data, sh->bh_old[pd_idx]->b_data, sh->size); + bh_ptr[0] = sh->bh_copy[pd_idx]; + count = 1; for (i = 0; i < disks; i++) { if (i == sh->pd_idx) continue; if (sh->bh_new[i] && sh->bh_old[i]) { - xor_block(sh->bh_copy[pd_idx], sh->bh_copy[i]); - xor_block(sh->bh_copy[pd_idx], sh->bh_old[i]); - continue; + bh_ptr[count++] = sh->bh_copy[i]; + bh_ptr[count++] = sh->bh_old[i]; + } + if (count >= (MAX_XOR_BLOCKS - 1)) { + xor_block(count, &bh_ptr[0]); + count = 1; } } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } } raid5_mark_buffer_uptodate(sh->bh_copy[pd_idx], 1); } static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int dd_idx, int rw) { - struct raid5_data *raid_conf = sh->raid_conf; + raid5_conf_t *conf = sh->raid_conf; struct buffer_head *bh_req; if (sh->bh_new[dd_idx]) { @@ -860,19 +899,22 @@ if (sh->phase == PHASE_COMPLETE && sh->cmd == STRIPE_NONE) { sh->phase = PHASE_BEGIN; sh->cmd = (rw == READ) ? STRIPE_READ : STRIPE_WRITE; - raid_conf->nr_pending_stripes++; - atomic_inc(&raid_conf->nr_handle); + conf->nr_pending_stripes++; + atomic_inc(&conf->nr_handle); } sh->bh_new[dd_idx] = bh; sh->bh_req[dd_idx] = bh_req; sh->cmd_new[dd_idx] = rw; sh->new[dd_idx] = 1; + + if (buffer_lowprio(bh)) + mark_buffer_lowprio(bh_req); } static void complete_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; - int disks = raid_conf->raid_disks; + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks; int i, new = 0; PRINTK(("complete_stripe %lu\n", sh->sector)); @@ -909,6 +951,22 @@ } } + +static int is_stripe_lowprio(struct stripe_head *sh, int disks) +{ + int i, lowprio = 1; + + for (i = 0; i < disks; i++) { + if (sh->bh_new[i]) + if (!buffer_lowprio(sh->bh_new[i])) + lowprio = 0; + if (sh->bh_old[i]) + if (!buffer_lowprio(sh->bh_old[i])) + lowprio = 0; + } + return lowprio; +} + /* * handle_stripe() is our main logic routine. Note that: * @@ -919,28 +977,27 @@ * 2. We should be careful to set sh->nr_pending whenever we sleep, * to prevent re-entry of handle_stripe() for the same sh. * - * 3. raid_conf->failed_disks and disk->operational can be changed + * 3. conf->failed_disks and disk->operational can be changed * from an interrupt. This complicates things a bit, but it allows * us to stop issuing requests for a failed drive as soon as possible. */ static void handle_stripe(struct stripe_head *sh) { - struct raid5_data *raid_conf = sh->raid_conf; - struct md_dev *mddev = raid_conf->mddev; - int minor = (int) (mddev - md_dev); + raid5_conf_t *conf = sh->raid_conf; + mddev_t *mddev = conf->mddev; struct buffer_head *bh; - int disks = raid_conf->raid_disks; - int i, nr = 0, nr_read = 0, nr_write = 0; + int disks = conf->raid_disks; + int i, nr = 0, nr_read = 0, nr_write = 0, lowprio; int nr_cache = 0, nr_cache_other = 0, nr_cache_overwrite = 0, parity = 0; int nr_failed_other = 0, nr_failed_overwrite = 0, parity_failed = 0; int reading = 0, nr_writing = 0; int method1 = INT_MAX, method2 = INT_MAX; int block; unsigned long flags; - int operational[MD_SB_DISKS], failed_disks = raid_conf->failed_disks; + int operational[MD_SB_DISKS], failed_disks = conf->failed_disks; PRINTK(("handle_stripe(), stripe %lu\n", sh->sector)); - if (sh->nr_pending) { + if (md_atomic_read(&sh->nr_pending)) { printk("handle_stripe(), stripe %lu, io still pending\n", sh->sector); return; } @@ -949,9 +1006,9 @@ return; } - atomic_dec(&raid_conf->nr_handle); + atomic_dec(&conf->nr_handle); - if (test_and_clear_bit(STRIPE_ERROR, &sh->state)) { + if (md_test_and_clear_bit(STRIPE_ERROR, &sh->state)) { printk("raid5: restarting stripe %lu\n", sh->sector); sh->phase = PHASE_BEGIN; } @@ -969,11 +1026,11 @@ save_flags(flags); cli(); for (i = 0; i < disks; i++) { - operational[i] = raid_conf->disks[i].operational; - if (i == sh->pd_idx && raid_conf->resync_parity) + operational[i] = conf->disks[i].operational; + if (i == sh->pd_idx && conf->resync_parity) operational[i] = 0; } - failed_disks = raid_conf->failed_disks; + failed_disks = conf->failed_disks; restore_flags(flags); if (failed_disks > 1) { @@ -1017,7 +1074,7 @@ } if (nr_write && nr_read) - printk("raid5: bug, nr_write == %d, nr_read == %d, sh->cmd == %d\n", nr_write, nr_read, sh->cmd); + printk("raid5: bug, nr_write ==`%d, nr_read == %d, sh->cmd == %d\n", nr_write, nr_read, sh->cmd); if (nr_write) { /* @@ -1030,7 +1087,7 @@ if (sh->bh_new[i]) continue; block = (int) compute_blocknr(sh, i); - bh = find_buffer(MKDEV(MD_MAJOR, minor), block, sh->size); + bh = find_buffer(mddev_to_kdev(mddev), block, sh->size); if (bh && bh->b_count == 0 && buffer_dirty(bh) && !buffer_locked(bh)) { PRINTK(("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block)); add_stripe_bh(sh, bh, i, WRITE); @@ -1064,21 +1121,22 @@ if (!method1 || !method2) { lock_stripe(sh); - sh->nr_pending++; + lowprio = is_stripe_lowprio(sh, disks); + atomic_inc(&sh->nr_pending); sh->phase = PHASE_WRITE; compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); for (i = 0; i < disks; i++) { - if (!operational[i] && !raid_conf->spare && !raid_conf->resync_parity) + if (!operational[i] && !conf->spare && !conf->resync_parity) continue; if (i == sh->pd_idx || sh->bh_new[i]) nr_writing++; } - sh->nr_pending = nr_writing; - PRINTK(("handle_stripe() %lu, writing back %d\n", sh->sector, sh->nr_pending)); + md_atomic_set(&sh->nr_pending, nr_writing); + PRINTK(("handle_stripe() %lu, writing back %d\n", sh->sector, md_atomic_read(&sh->nr_pending))); for (i = 0; i < disks; i++) { - if (!operational[i] && !raid_conf->spare && !raid_conf->resync_parity) + if (!operational[i] && !conf->spare && !conf->resync_parity) continue; bh = sh->bh_copy[i]; if (i != sh->pd_idx && ((bh == NULL) ^ (sh->bh_new[i] == NULL))) @@ -1089,18 +1147,30 @@ bh->b_state |= (1<b_state); - if (!operational[i] && !raid_conf->resync_parity) { - bh->b_rdev = raid_conf->spare->dev; - make_request(MAJOR(raid_conf->spare->dev), WRITE, bh); - } else - make_request(MAJOR(raid_conf->disks[i].dev), WRITE, bh); + if (!operational[i] && !conf->resync_parity) { + bh->b_rdev = conf->spare->dev; + make_request(MAJOR(conf->spare->dev), WRITE, bh); + } else { +#if 0 + make_request(MAJOR(conf->disks[i].dev), WRITE, bh); +#else + if (!lowprio || (i==sh->pd_idx)) + make_request(MAJOR(conf->disks[i].dev), WRITE, bh); + else { + mark_buffer_clean(bh); + raid5_end_request(bh,1); + sh->new[i] = 0; + } +#endif + } } } return; } lock_stripe(sh); - sh->nr_pending++; + lowprio = is_stripe_lowprio(sh, disks); + atomic_inc(&sh->nr_pending); if (method1 < method2) { sh->write_method = RECONSTRUCT_WRITE; for (i = 0; i < disks; i++) { @@ -1110,6 +1180,8 @@ continue; sh->bh_old[i] = raid5_kmalloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_old[i], i); + if (lowprio) + mark_buffer_lowprio(sh->bh_old[i]); reading++; } } else { @@ -1121,19 +1193,21 @@ continue; sh->bh_old[i] = raid5_kmalloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_old[i], i); + if (lowprio) + mark_buffer_lowprio(sh->bh_old[i]); reading++; } } sh->phase = PHASE_READ_OLD; - sh->nr_pending = reading; - PRINTK(("handle_stripe() %lu, reading %d old buffers\n", sh->sector, sh->nr_pending)); + md_atomic_set(&sh->nr_pending, reading); + PRINTK(("handle_stripe() %lu, reading %d old buffers\n", sh->sector, md_atomic_read(&sh->nr_pending))); for (i = 0; i < disks; i++) { if (!sh->bh_old[i]) continue; if (buffer_uptodate(sh->bh_old[i])) continue; clear_bit(BH_Lock, &sh->bh_old[i]->b_state); - make_request(MAJOR(raid_conf->disks[i].dev), READ, sh->bh_old[i]); + make_request(MAJOR(conf->disks[i].dev), READ, sh->bh_old[i]); } } else { /* @@ -1141,7 +1215,8 @@ */ method1 = nr_read - nr_cache_overwrite; lock_stripe(sh); - sh->nr_pending++; + lowprio = is_stripe_lowprio(sh,disks); + atomic_inc(&sh->nr_pending); PRINTK(("handle_stripe(), sector %lu, nr_read %d, nr_cache %d, method1 %d\n", sh->sector, nr_read, nr_cache, method1)); if (!method1 || (method1 == 1 && nr_cache == disks - 1)) { @@ -1149,18 +1224,22 @@ for (i = 0; i < disks; i++) { if (!sh->bh_new[i]) continue; - if (!sh->bh_old[i]) + if (!sh->bh_old[i]) { compute_block(sh, i); + if (lowprio) + mark_buffer_lowprio + (sh->bh_old[i]); + } memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); } - sh->nr_pending--; + atomic_dec(&sh->nr_pending); complete_stripe(sh); return; } if (nr_failed_overwrite) { sh->phase = PHASE_READ_OLD; - sh->nr_pending = (disks - 1) - nr_cache; - PRINTK(("handle_stripe() %lu, phase READ_OLD, pending %d\n", sh->sector, sh->nr_pending)); + md_atomic_set(&sh->nr_pending, (disks - 1) - nr_cache); + PRINTK(("handle_stripe() %lu, phase READ_OLD, pending %d\n", sh->sector, md_atomic_read(&sh->nr_pending))); for (i = 0; i < disks; i++) { if (sh->bh_old[i]) continue; @@ -1168,13 +1247,16 @@ continue; sh->bh_old[i] = raid5_kmalloc_buffer(sh, sh->size); raid5_build_block(sh, sh->bh_old[i], i); + if (lowprio) + mark_buffer_lowprio(sh->bh_old[i]); clear_bit(BH_Lock, &sh->bh_old[i]->b_state); - make_request(MAJOR(raid_conf->disks[i].dev), READ, sh->bh_old[i]); + make_request(MAJOR(conf->disks[i].dev), READ, sh->bh_old[i]); } } else { sh->phase = PHASE_READ; - sh->nr_pending = nr_read - nr_cache_overwrite; - PRINTK(("handle_stripe() %lu, phase READ, pending %d\n", sh->sector, sh->nr_pending)); + md_atomic_set(&sh->nr_pending, + nr_read - nr_cache_overwrite); + PRINTK(("handle_stripe() %lu, phase READ, pending %d\n", sh->sector, md_atomic_read(&sh->nr_pending))); for (i = 0; i < disks; i++) { if (!sh->bh_new[i]) continue; @@ -1182,16 +1264,16 @@ memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); continue; } - make_request(MAJOR(raid_conf->disks[i].dev), READ, sh->bh_req[i]); + make_request(MAJOR(conf->disks[i].dev), READ, sh->bh_req[i]); } } } } -static int raid5_make_request (struct md_dev *mddev, int rw, struct buffer_head * bh) +static int raid5_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) { - struct raid5_data *raid_conf = (struct raid5_data *) mddev->private; - const unsigned int raid_disks = raid_conf->raid_disks; + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + const unsigned int raid_disks = conf->raid_disks; const unsigned int data_disks = raid_disks - 1; unsigned int dd_idx, pd_idx; unsigned long new_sector; @@ -1202,15 +1284,15 @@ if (rw == WRITEA) rw = WRITE; new_sector = raid5_compute_sector(bh->b_rsector, raid_disks, data_disks, - &dd_idx, &pd_idx, raid_conf); + &dd_idx, &pd_idx, conf); PRINTK(("raid5_make_request, sector %lu\n", new_sector)); repeat: - sh = get_stripe(raid_conf, new_sector, bh->b_size); + sh = get_stripe(conf, new_sector, bh->b_size); if ((rw == READ && sh->cmd == STRIPE_WRITE) || (rw == WRITE && sh->cmd == STRIPE_READ)) { PRINTK(("raid5: lock contention, rw == %d, sh->cmd == %d\n", rw, sh->cmd)); lock_stripe(sh); - if (!sh->nr_pending) + if (!md_atomic_read(&sh->nr_pending)) handle_stripe(sh); goto repeat; } @@ -1221,24 +1303,24 @@ printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector); printk("raid5: bh %p, bh_new %p\n", bh, sh->bh_new[dd_idx]); lock_stripe(sh); - md_wakeup_thread(raid_conf->thread); + md_wakeup_thread(conf->thread); wait_on_stripe(sh); goto repeat; } add_stripe_bh(sh, bh, dd_idx, rw); - md_wakeup_thread(raid_conf->thread); + md_wakeup_thread(conf->thread); return 0; } static void unplug_devices(struct stripe_head *sh) { #if 0 - struct raid5_data *raid_conf = sh->raid_conf; + raid5_conf_t *conf = sh->raid_conf; int i; - for (i = 0; i < raid_conf->raid_disks; i++) - unplug_device(blk_dev + MAJOR(raid_conf->disks[i].dev)); + for (i = 0; i < conf->raid_disks; i++) + unplug_device(blk_dev + MAJOR(conf->disks[i].dev)); #endif } @@ -1252,8 +1334,8 @@ static void raid5d (void *data) { struct stripe_head *sh; - struct raid5_data *raid_conf = data; - struct md_dev *mddev = raid_conf->mddev; + raid5_conf_t *conf = data; + mddev_t *mddev = conf->mddev; int i, handled = 0, unplug = 0; unsigned long flags; @@ -1261,47 +1343,47 @@ if (mddev->sb_dirty) { mddev->sb_dirty = 0; - md_update_sb((int) (mddev - md_dev)); + md_update_sb(mddev); } for (i = 0; i < NR_HASH; i++) { repeat: - sh = raid_conf->stripe_hashtbl[i]; + sh = conf->stripe_hashtbl[i]; for (; sh; sh = sh->hash_next) { - if (sh->raid_conf != raid_conf) + if (sh->raid_conf != conf) continue; if (sh->phase == PHASE_COMPLETE) continue; - if (sh->nr_pending) + if (md_atomic_read(&sh->nr_pending)) continue; - if (sh->sector == raid_conf->next_sector) { - raid_conf->sector_count += (sh->size >> 9); - if (raid_conf->sector_count >= 128) + if (sh->sector == conf->next_sector) { + conf->sector_count += (sh->size >> 9); + if (conf->sector_count >= 128) unplug = 1; } else unplug = 1; if (unplug) { - PRINTK(("unplugging devices, sector == %lu, count == %d\n", sh->sector, raid_conf->sector_count)); + PRINTK(("unplugging devices, sector == %lu, count == %d\n", sh->sector, conf->sector_count)); unplug_devices(sh); unplug = 0; - raid_conf->sector_count = 0; + conf->sector_count = 0; } - raid_conf->next_sector = sh->sector + (sh->size >> 9); + conf->next_sector = sh->sector + (sh->size >> 9); handled++; handle_stripe(sh); goto repeat; } } - if (raid_conf) { - PRINTK(("%d stripes handled, nr_handle %d\n", handled, atomic_read(&raid_conf->nr_handle))); + if (conf) { + PRINTK(("%d stripes handled, nr_handle %d\n", handled, md_atomic_read(&conf->nr_handle))); save_flags(flags); cli(); - if (!atomic_read(&raid_conf->nr_handle)) - clear_bit(THREAD_WAKEUP, &raid_conf->thread->flags); + if (!md_atomic_read(&conf->nr_handle)) + clear_bit(THREAD_WAKEUP, &conf->thread->flags); + restore_flags(flags); } PRINTK(("--- raid5d inactive\n")); } -#if SUPPORT_RECONSTRUCTION /* * Private kernel thread for parity reconstruction after an unclean * shutdown. Reconstruction on spare drives in case of a failed drive @@ -1309,44 +1391,64 @@ */ static void raid5syncd (void *data) { - struct raid5_data *raid_conf = data; - struct md_dev *mddev = raid_conf->mddev; + raid5_conf_t *conf = data; + mddev_t *mddev = conf->mddev; - if (!raid_conf->resync_parity) + if (!conf->resync_parity) + return; + if (conf->resync_parity == 2) + return; + down(&mddev->recovery_sem); + if (md_do_sync(mddev,NULL)) { + up(&mddev->recovery_sem); + printk("raid5: resync aborted!\n"); return; - md_do_sync(mddev); - raid_conf->resync_parity = 0; + } + conf->resync_parity = 0; + up(&mddev->recovery_sem); + printk("raid5: resync finished.\n"); } -#endif /* SUPPORT_RECONSTRUCTION */ -static int __check_consistency (struct md_dev *mddev, int row) +static int __check_consistency (mddev_t *mddev, int row) { - struct raid5_data *raid_conf = mddev->private; + raid5_conf_t *conf = mddev->private; kdev_t dev; struct buffer_head *bh[MD_SB_DISKS], tmp; - int i, rc = 0, nr = 0; + int i, rc = 0, nr = 0, count; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - if (raid_conf->working_disks != raid_conf->raid_disks) + if (conf->working_disks != conf->raid_disks) return 0; tmp.b_size = 4096; if ((tmp.b_data = (char *) get_free_page(GFP_KERNEL)) == NULL) return 0; + md_clear_page((unsigned long)tmp.b_data); memset(bh, 0, MD_SB_DISKS * sizeof(struct buffer_head *)); - for (i = 0; i < raid_conf->raid_disks; i++) { - dev = raid_conf->disks[i].dev; + for (i = 0; i < conf->raid_disks; i++) { + dev = conf->disks[i].dev; set_blocksize(dev, 4096); if ((bh[i] = bread(dev, row / 4, 4096)) == NULL) break; nr++; } - if (nr == raid_conf->raid_disks) { - for (i = 1; i < nr; i++) - xor_block(&tmp, bh[i]); + if (nr == conf->raid_disks) { + bh_ptr[0] = &tmp; + count = 1; + for (i = 1; i < nr; i++) { + bh_ptr[count++] = bh[i]; + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } if (memcmp(tmp.b_data, bh[0]->b_data, 4096)) rc = 1; } - for (i = 0; i < raid_conf->raid_disks; i++) { - dev = raid_conf->disks[i].dev; + for (i = 0; i < conf->raid_disks; i++) { + dev = conf->disks[i].dev; if (bh[i]) { bforget(bh[i]); bh[i] = NULL; @@ -1358,285 +1460,607 @@ return rc; } -static int check_consistency (struct md_dev *mddev) +static int check_consistency (mddev_t *mddev) { - int size = mddev->sb->size; - int row; + if (__check_consistency(mddev, 0)) +/* + * We are not checking this currently, as it's legitimate to have + * an inconsistent array, at creation time. + */ + return 0; - for (row = 0; row < size; row += size / 8) - if (__check_consistency(mddev, row)) - return 1; return 0; } -static int raid5_run (int minor, struct md_dev *mddev) +static int raid5_run (mddev_t *mddev) { - struct raid5_data *raid_conf; + raid5_conf_t *conf; int i, j, raid_disk, memory; - md_superblock_t *sb = mddev->sb; - md_descriptor_t *descriptor; - struct real_dev *realdev; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *desc; + mdk_rdev_t *rdev; + struct disk_info *disk; + struct md_list_head *tmp; + int start_recovery = 0; MOD_INC_USE_COUNT; if (sb->level != 5 && sb->level != 4) { - printk("raid5: %s: raid level not set to 4/5 (%d)\n", kdevname(MKDEV(MD_MAJOR, minor)), sb->level); + printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), sb->level); MOD_DEC_USE_COUNT; return -EIO; } - mddev->private = kmalloc (sizeof (struct raid5_data), GFP_KERNEL); - if ((raid_conf = mddev->private) == NULL) + mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL); + if ((conf = mddev->private) == NULL) goto abort; - memset (raid_conf, 0, sizeof (*raid_conf)); - raid_conf->mddev = mddev; + memset (conf, 0, sizeof (*conf)); + conf->mddev = mddev; - if ((raid_conf->stripe_hashtbl = (struct stripe_head **) __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL) + if ((conf->stripe_hashtbl = (struct stripe_head **) md__get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL) goto abort; - memset(raid_conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); + memset(conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); - init_waitqueue(&raid_conf->wait_for_stripe); - PRINTK(("raid5_run(%d) called.\n", minor)); - - for (i = 0; i < mddev->nb_dev; i++) { - realdev = &mddev->devices[i]; - if (!realdev->sb) { - printk(KERN_ERR "raid5: disabled device %s (couldn't access raid superblock)\n", kdevname(realdev->dev)); - continue; - } + init_waitqueue(&conf->wait_for_stripe); + PRINTK(("raid5_run(md%d) called.\n", mdidx(mddev))); + ITERATE_RDEV(mddev,rdev,tmp) { /* * This is important -- we are using the descriptor on * the disk only to get a pointer to the descriptor on * the main superblock, which might be more recent. */ - descriptor = &sb->disks[realdev->sb->descriptor.number]; - if (descriptor->state & (1 << MD_FAULTY_DEVICE)) { - printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", kdevname(realdev->dev)); + desc = sb->disks + rdev->desc_nr; + raid_disk = desc->raid_disk; + disk = conf->disks + raid_disk; + + if (disk_faulty(desc)) { + printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", partition_name(rdev->dev)); + if (!rdev->faulty) { + MD_BUG(); + goto abort; + } + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; continue; } - if (descriptor->state & (1 << MD_ACTIVE_DEVICE)) { - if (!(descriptor->state & (1 << MD_SYNC_DEVICE))) { - printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", kdevname(realdev->dev)); - continue; + if (disk_active(desc)) { + if (!disk_sync(desc)) { + printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", partition_name(rdev->dev)); + MD_BUG(); + goto abort; } - raid_disk = descriptor->raid_disk; - if (descriptor->number > sb->nr_disks || raid_disk > sb->raid_disks) { - printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", kdevname(realdev->dev)); + if (raid_disk > sb->raid_disks) { + printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", partition_name(rdev->dev)); continue; } - if (raid_conf->disks[raid_disk].operational) { - printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", kdevname(realdev->dev), raid_disk); + if (disk->operational) { + printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", partition_name(rdev->dev), raid_disk); continue; } - printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", kdevname(realdev->dev), raid_disk); + printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", partition_name(rdev->dev), raid_disk); - raid_conf->disks[raid_disk].number = descriptor->number; - raid_conf->disks[raid_disk].raid_disk = raid_disk; - raid_conf->disks[raid_disk].dev = mddev->devices[i].dev; - raid_conf->disks[raid_disk].operational = 1; + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; + disk->operational = 1; + disk->used_slot = 1; - raid_conf->working_disks++; + conf->working_disks++; } else { /* * Must be a spare disk .. */ - printk(KERN_INFO "raid5: spare disk %s\n", kdevname(realdev->dev)); - raid_disk = descriptor->raid_disk; - raid_conf->disks[raid_disk].number = descriptor->number; - raid_conf->disks[raid_disk].raid_disk = raid_disk; - raid_conf->disks[raid_disk].dev = mddev->devices [i].dev; - - raid_conf->disks[raid_disk].operational = 0; - raid_conf->disks[raid_disk].write_only = 0; - raid_conf->disks[raid_disk].spare = 1; - } - } - raid_conf->raid_disks = sb->raid_disks; - raid_conf->failed_disks = raid_conf->raid_disks - raid_conf->working_disks; - raid_conf->mddev = mddev; - raid_conf->chunk_size = sb->chunk_size; - raid_conf->level = sb->level; - raid_conf->algorithm = sb->parity_algorithm; - raid_conf->max_nr_stripes = NR_STRIPES; + printk(KERN_INFO "raid5: spare disk %s\n", partition_name(rdev->dev)); + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; - if (raid_conf->working_disks != sb->raid_disks && sb->state != (1 << MD_SB_CLEAN)) { - printk(KERN_ALERT "raid5: raid set %s not clean and not all disks are operational -- run ckraid\n", kdevname(MKDEV(MD_MAJOR, minor))); - goto abort; + disk->operational = 0; + disk->write_only = 0; + disk->spare = 1; + disk->used_slot = 1; + } } - if (!raid_conf->chunk_size || raid_conf->chunk_size % 4) { - printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", raid_conf->chunk_size, kdevname(MKDEV(MD_MAJOR, minor))); + + for (i = 0; i < MD_SB_DISKS; i++) { + desc = sb->disks + i; + raid_disk = desc->raid_disk; + disk = conf->disks + raid_disk; + + if (disk_faulty(desc) && (raid_disk < sb->raid_disks) && + !conf->disks[raid_disk].used_slot) { + + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = MKDEV(0,0); + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + } + } + + conf->raid_disks = sb->raid_disks; + /* + * 0 for a fully functional array, 1 for a degraded array. + */ + conf->failed_disks = conf->raid_disks - conf->working_disks; + conf->mddev = mddev; + conf->chunk_size = sb->chunk_size; + conf->level = sb->level; + conf->algorithm = sb->layout; + conf->max_nr_stripes = NR_STRIPES; + +#if 0 + for (i = 0; i < conf->raid_disks; i++) { + if (!conf->disks[i].used_slot) { + MD_BUG(); + goto abort; + } + } +#endif + if (!conf->chunk_size || conf->chunk_size % 4) { + printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", conf->chunk_size, mdidx(mddev)); goto abort; } - if (raid_conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { - printk(KERN_ERR "raid5: unsupported parity algorithm %d for %s\n", raid_conf->algorithm, kdevname(MKDEV(MD_MAJOR, minor))); + if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { + printk(KERN_ERR "raid5: unsupported parity algorithm %d for md%d\n", conf->algorithm, mdidx(mddev)); goto abort; } - if (raid_conf->failed_disks > 1) { - printk(KERN_ERR "raid5: not enough operational devices for %s (%d/%d failed)\n", kdevname(MKDEV(MD_MAJOR, minor)), raid_conf->failed_disks, raid_conf->raid_disks); + if (conf->failed_disks > 1) { + printk(KERN_ERR "raid5: not enough operational devices for md%d (%d/%d failed)\n", mdidx(mddev), conf->failed_disks, conf->raid_disks); goto abort; } - if ((sb->state & (1 << MD_SB_CLEAN)) && check_consistency(mddev)) { - printk(KERN_ERR "raid5: detected raid-5 xor inconsistenty -- run ckraid\n"); - sb->state |= 1 << MD_SB_ERRORS; - goto abort; + if (conf->working_disks != sb->raid_disks) { + printk(KERN_ALERT "raid5: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); + start_recovery = 1; } - if ((raid_conf->thread = md_register_thread(raid5d, raid_conf)) == NULL) { - printk(KERN_ERR "raid5: couldn't allocate thread for %s\n", kdevname(MKDEV(MD_MAJOR, minor))); - goto abort; + if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN)) && + check_consistency(mddev)) { + printk(KERN_ERR "raid5: detected raid-5 superblock xor inconsistency -- running resync\n"); + sb->state &= ~(1 << MD_SB_CLEAN); } -#if SUPPORT_RECONSTRUCTION - if ((raid_conf->resync_thread = md_register_thread(raid5syncd, raid_conf)) == NULL) { - printk(KERN_ERR "raid5: couldn't allocate thread for %s\n", kdevname(MKDEV(MD_MAJOR, minor))); - goto abort; + { + const char * name = "raid5d"; + + conf->thread = md_register_thread(raid5d, conf, name); + if (!conf->thread) { + printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); + goto abort; + } } -#endif /* SUPPORT_RECONSTRUCTION */ - memory = raid_conf->max_nr_stripes * (sizeof(struct stripe_head) + - raid_conf->raid_disks * (sizeof(struct buffer_head) + + memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + + conf->raid_disks * (sizeof(struct buffer_head) + 2 * (sizeof(struct buffer_head) + PAGE_SIZE))) / 1024; - if (grow_stripes(raid_conf, raid_conf->max_nr_stripes, GFP_KERNEL)) { + if (grow_stripes(conf, conf->max_nr_stripes, GFP_KERNEL)) { printk(KERN_ERR "raid5: couldn't allocate %dkB for buffers\n", memory); - shrink_stripes(raid_conf, raid_conf->max_nr_stripes); + shrink_stripes(conf, conf->max_nr_stripes); goto abort; } else - printk(KERN_INFO "raid5: allocated %dkB for %s\n", memory, kdevname(MKDEV(MD_MAJOR, minor))); + printk(KERN_INFO "raid5: allocated %dkB for md%d\n", memory, mdidx(mddev)); /* * Regenerate the "device is in sync with the raid set" bit for * each device. */ - for (i = 0; i < sb->nr_disks ; i++) { - sb->disks[i].state &= ~(1 << MD_SYNC_DEVICE); + for (i = 0; i < MD_SB_DISKS ; i++) { + mark_disk_nonsync(sb->disks + i); for (j = 0; j < sb->raid_disks; j++) { - if (!raid_conf->disks[j].operational) + if (!conf->disks[j].operational) continue; - if (sb->disks[i].number == raid_conf->disks[j].number) - sb->disks[i].state |= 1 << MD_SYNC_DEVICE; + if (sb->disks[i].number == conf->disks[j].number) + mark_disk_sync(sb->disks + i); } } - sb->active_disks = raid_conf->working_disks; + sb->active_disks = conf->working_disks; if (sb->active_disks == sb->raid_disks) - printk("raid5: raid level %d set %s active with %d out of %d devices, algorithm %d\n", raid_conf->level, kdevname(MKDEV(MD_MAJOR, minor)), sb->active_disks, sb->raid_disks, raid_conf->algorithm); + printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); else - printk(KERN_ALERT "raid5: raid level %d set %s active with %d out of %d devices, algorithm %d\n", raid_conf->level, kdevname(MKDEV(MD_MAJOR, minor)), sb->active_disks, sb->raid_disks, raid_conf->algorithm); + printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); + + if (!start_recovery && ((sb->state & (1 << MD_SB_CLEAN))==0)) { + const char * name = "raid5syncd"; + + conf->resync_thread = md_register_thread(raid5syncd, conf,name); + if (!conf->resync_thread) { + printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); + goto abort; + } - if ((sb->state & (1 << MD_SB_CLEAN)) == 0) { - printk("raid5: raid set %s not clean; re-constructing parity\n", kdevname(MKDEV(MD_MAJOR, minor))); - raid_conf->resync_parity = 1; -#if SUPPORT_RECONSTRUCTION - md_wakeup_thread(raid_conf->resync_thread); -#endif /* SUPPORT_RECONSTRUCTION */ + printk("raid5: raid set md%d not clean; reconstructing parity\n", mdidx(mddev)); + conf->resync_parity = 1; + md_wakeup_thread(conf->resync_thread); } + print_raid5_conf(conf); + if (start_recovery) + md_recover_arrays(); + print_raid5_conf(conf); + /* Ok, everything is just fine now */ return (0); abort: - if (raid_conf) { - if (raid_conf->stripe_hashtbl) - free_pages((unsigned long) raid_conf->stripe_hashtbl, HASH_PAGES_ORDER); - kfree(raid_conf); + if (conf) { + print_raid5_conf(conf); + if (conf->stripe_hashtbl) + free_pages((unsigned long) conf->stripe_hashtbl, + HASH_PAGES_ORDER); + kfree(conf); } mddev->private = NULL; - printk(KERN_ALERT "raid5: failed to run raid set %s\n", kdevname(MKDEV(MD_MAJOR, minor))); + printk(KERN_ALERT "raid5: failed to run raid set md%d\n", mdidx(mddev)); MOD_DEC_USE_COUNT; return -EIO; } -static int raid5_stop (int minor, struct md_dev *mddev) +static int raid5_stop_resync (mddev_t *mddev) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + mdk_thread_t *thread = conf->resync_thread; + + if (thread) { + if (conf->resync_parity) { + conf->resync_parity = 2; + md_interrupt_thread(thread); + printk(KERN_INFO "raid5: parity resync was not fully finished, restarting next time.\n"); + return 1; + } + return 0; + } + return 0; +} + +static int raid5_restart_resync (mddev_t *mddev) { - struct raid5_data *raid_conf = (struct raid5_data *) mddev->private; + raid5_conf_t *conf = mddev_to_conf(mddev); - shrink_stripe_cache(raid_conf, raid_conf->max_nr_stripes); - shrink_stripes(raid_conf, raid_conf->max_nr_stripes); - md_unregister_thread(raid_conf->thread); -#if SUPPORT_RECONSTRUCTION - md_unregister_thread(raid_conf->resync_thread); -#endif /* SUPPORT_RECONSTRUCTION */ - free_pages((unsigned long) raid_conf->stripe_hashtbl, HASH_PAGES_ORDER); - kfree(raid_conf); + if (conf->resync_parity) { + if (!conf->resync_thread) { + MD_BUG(); + return 0; + } + printk("raid5: waking up raid5resync.\n"); + conf->resync_parity = 1; + md_wakeup_thread(conf->resync_thread); + return 1; + } else + printk("raid5: no restart-resync needed.\n"); + return 0; +} + + +static int raid5_stop (mddev_t *mddev) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + + shrink_stripe_cache(conf, conf->max_nr_stripes); + shrink_stripes(conf, conf->max_nr_stripes); + md_unregister_thread(conf->thread); + if (conf->resync_thread) + md_unregister_thread(conf->resync_thread); + free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); + kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; return 0; } -static int raid5_status (char *page, int minor, struct md_dev *mddev) +static int raid5_status (char *page, mddev_t *mddev) { - struct raid5_data *raid_conf = (struct raid5_data *) mddev->private; - md_superblock_t *sb = mddev->sb; + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + mdp_super_t *sb = mddev->sb; int sz = 0, i; - sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->parity_algorithm); - sz += sprintf (page+sz, " [%d/%d] [", raid_conf->raid_disks, raid_conf->working_disks); - for (i = 0; i < raid_conf->raid_disks; i++) - sz += sprintf (page+sz, "%s", raid_conf->disks[i].operational ? "U" : "_"); + sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout); + sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks); + for (i = 0; i < conf->raid_disks; i++) + sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_"); sz += sprintf (page+sz, "]"); return sz; } -static int raid5_mark_spare(struct md_dev *mddev, md_descriptor_t *spare, int state) +static void print_raid5_conf (raid5_conf_t *conf) +{ + int i; + struct disk_info *tmp; + + printk("RAID5 conf printout:\n"); + if (!conf) { + printk("(conf==NULL)\n"); + return; + } + printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, + conf->working_disks, conf->failed_disks); + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + i, tmp->spare,tmp->operational, + tmp->number,tmp->raid_disk,tmp->used_slot, + partition_name(tmp->dev)); + } +} + +static int raid5_diskop(mddev_t *mddev, mdp_disk_t **d, int state) { - int i = 0, failed_disk = -1; - struct raid5_data *raid_conf = mddev->private; - struct disk_info *disk = raid_conf->disks; + int err = 0; + int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; + raid5_conf_t *conf = mddev->private; + struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; unsigned long flags; - md_superblock_t *sb = mddev->sb; - md_descriptor_t *descriptor; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *failed_desc, *spare_desc, *added_desc; - for (i = 0; i < MD_SB_DISKS; i++, disk++) { - if (disk->spare && disk->number == spare->number) - goto found; - } - return 1; -found: - for (i = 0, disk = raid_conf->disks; i < raid_conf->raid_disks; i++, disk++) - if (!disk->operational) - failed_disk = i; - if (failed_disk == -1) - return 1; save_flags(flags); cli(); + + print_raid5_conf(conf); + /* + * find the disk ... + */ switch (state) { - case SPARE_WRITE: - disk->operational = 1; - disk->write_only = 1; - raid_conf->spare = disk; - break; - case SPARE_INACTIVE: - disk->operational = 0; - disk->write_only = 0; - raid_conf->spare = NULL; - break; - case SPARE_ACTIVE: - disk->spare = 0; - disk->write_only = 0; - descriptor = &sb->disks[raid_conf->disks[failed_disk].number]; - i = spare->raid_disk; - disk->raid_disk = spare->raid_disk = descriptor->raid_disk; - if (disk->raid_disk != failed_disk) - printk("raid5: disk->raid_disk != failed_disk"); - descriptor->raid_disk = i; - - raid_conf->spare = NULL; - raid_conf->working_disks++; - raid_conf->failed_disks--; - raid_conf->disks[failed_disk] = *disk; - break; - default: - printk("raid5_mark_spare: bug: state == %d\n", state); - restore_flags(flags); - return 1; + case DISKOP_SPARE_ACTIVE: + + /* + * Find the failed disk within the RAID5 configuration ... + * (this can only be in the first conf->raid_disks part) + */ + for (i = 0; i < conf->raid_disks; i++) { + tmp = conf->disks + i; + if ((!tmp->operational && !tmp->spare) || + !tmp->used_slot) { + failed_disk = i; + break; + } + } + /* + * When we activate a spare disk we _must_ have a disk in + * the lower (active) part of the array to replace. + */ + if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + /* fall through */ + + case DISKOP_SPARE_WRITE: + case DISKOP_SPARE_INACTIVE: + + /* + * Find the spare disk ... (can only be in the 'high' + * area of the array) + */ + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (tmp->spare && tmp->number == (*d)->number) { + spare_disk = i; + break; + } + } + if (spare_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_REMOVE_DISK: + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (tmp->used_slot && (tmp->number == (*d)->number)) { + if (tmp->operational) { + err = -EBUSY; + goto abort; + } + removed_disk = i; + break; + } + } + if (removed_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_ADD_DISK: + + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (!tmp->used_slot) { + added_disk = i; + break; + } + } + if (added_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + } + + switch (state) { + /* + * Switch the spare disk to write-only mode: + */ + case DISKOP_SPARE_WRITE: + if (conf->spare) { + MD_BUG(); + err = 1; + goto abort; + } + sdisk = conf->disks + spare_disk; + sdisk->operational = 1; + sdisk->write_only = 1; + conf->spare = sdisk; + break; + /* + * Deactivate a spare disk: + */ + case DISKOP_SPARE_INACTIVE: + sdisk = conf->disks + spare_disk; + sdisk->operational = 0; + sdisk->write_only = 0; + /* + * Was the spare being resynced? + */ + if (conf->spare == sdisk) + conf->spare = NULL; + break; + /* + * Activate (mark read-write) the (now sync) spare disk, + * which means we switch it's 'raid position' (->raid_disk) + * with the failed disk. (only the first 'conf->raid_disks' + * slots are used for 'real' disks and we must preserve this + * property) + */ + case DISKOP_SPARE_ACTIVE: + if (!conf->spare) { + MD_BUG(); + err = 1; + goto abort; + } + sdisk = conf->disks + spare_disk; + fdisk = conf->disks + failed_disk; + + spare_desc = &sb->disks[sdisk->number]; + failed_desc = &sb->disks[fdisk->number]; + + if (spare_desc != *d) { + MD_BUG(); + err = 1; + goto abort; + } + + if (spare_desc->raid_disk != sdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (sdisk->raid_disk != spare_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (failed_desc->raid_disk != fdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (fdisk->raid_disk != failed_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + /* + * do the switch finally + */ + xchg_values(*spare_desc, *failed_desc); + xchg_values(*fdisk, *sdisk); + + /* + * (careful, 'failed' and 'spare' are switched from now on) + * + * we want to preserve linear numbering and we want to + * give the proper raid_disk number to the now activated + * disk. (this means we switch back these values) + */ + + xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); + xchg_values(sdisk->raid_disk, fdisk->raid_disk); + xchg_values(spare_desc->number, failed_desc->number); + xchg_values(sdisk->number, fdisk->number); + + *d = failed_desc; + + if (sdisk->dev == MKDEV(0,0)) + sdisk->used_slot = 0; + + /* + * this really activates the spare. + */ + fdisk->spare = 0; + fdisk->write_only = 0; + + /* + * if we activate a spare, we definitely replace a + * non-operational disk slot in the 'low' area of + * the disk array. + */ + conf->failed_disks--; + conf->working_disks++; + conf->spare = NULL; + + break; + + case DISKOP_HOT_REMOVE_DISK: + rdisk = conf->disks + removed_disk; + + if (rdisk->spare && (removed_disk < conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + rdisk->dev = MKDEV(0,0); + rdisk->used_slot = 0; + + break; + + case DISKOP_HOT_ADD_DISK: + adisk = conf->disks + added_disk; + added_desc = *d; + + if (added_disk != added_desc->number) { + MD_BUG(); + err = 1; + goto abort; + } + + adisk->number = added_desc->number; + adisk->raid_disk = added_desc->raid_disk; + adisk->dev = MKDEV(added_desc->major,added_desc->minor); + + adisk->operational = 0; + adisk->write_only = 0; + adisk->spare = 1; + adisk->used_slot = 1; + + + break; + + default: + MD_BUG(); + err = 1; + goto abort; } +abort: restore_flags(flags); - return 0; + print_raid5_conf(conf); + return err; } -static struct md_personality raid5_personality= +static mdk_personality_t raid5_personality= { "raid5", raid5_map, @@ -1648,14 +2072,19 @@ NULL, /* no ioctls */ 0, raid5_error, - /* raid5_hot_add_disk, */ NULL, - /* raid1_hot_remove_drive */ NULL, - raid5_mark_spare + raid5_diskop, + raid5_stop_resync, + raid5_restart_resync }; int raid5_init (void) { - return register_md_personality (RAID5, &raid5_personality); + int err; + + err = register_md_personality (RAID5, &raid5_personality); + if (err) + return err; + return 0; } #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/rd.c linux.ac/drivers/block/rd.c --- linux.vanilla/drivers/block/rd.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/block/rd.c Thu Jul 8 06:14:11 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/smart1,2.h linux.ac/drivers/block/smart1,2.h --- linux.vanilla/drivers/block/smart1,2.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/smart1,2.h Mon Jul 5 05:11:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/translucent.c linux.ac/drivers/block/translucent.c --- linux.vanilla/drivers/block/translucent.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/translucent.c Mon Jul 19 03:26:58 1999 @@ -0,0 +1,136 @@ +/* + translucent.c : Translucent RAID driver for Linux + Copyright (C) 1998 Ingo Molnar + + Translucent mode management functions. + + 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. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include + +#include + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER +#define MD_PERSONALITY + +static int translucent_run (mddev_t *mddev) +{ + translucent_conf_t *conf; + mdk_rdev_t *rdev; + int i; + + MOD_INC_USE_COUNT; + + conf = kmalloc (sizeof (*conf), GFP_KERNEL); + if (!conf) + goto out; + mddev->private = conf; + + if (mddev->nb_dev != 2) { + printk("translucent: this mode needs 2 disks, aborting!\n"); + goto out; + } + + if (md_check_ordering(mddev)) { + printk("translucent: disks are not ordered, aborting!\n"); + goto out; + } + + ITERATE_RDEV_ORDERED(mddev,rdev,i) { + dev_info_t *disk = conf->disks + i; + + disk->dev = rdev->dev; + disk->size = rdev->size; + } + + return 0; + +out: + if (conf) + kfree(conf); + + MOD_DEC_USE_COUNT; + return 1; +} + +static int translucent_stop (mddev_t *mddev) +{ + translucent_conf_t *conf = mddev_to_conf(mddev); + + kfree(conf); + + MOD_DEC_USE_COUNT; + + return 0; +} + + +static int translucent_map (mddev_t *mddev, kdev_t dev, kdev_t *rdev, + unsigned long *rsector, unsigned long size) +{ + translucent_conf_t *conf = mddev_to_conf(mddev); + + *rdev = conf->disks[0].dev; + + return 0; +} + +static int translucent_status (char *page, mddev_t *mddev) +{ + int sz = 0; + + sz += sprintf(page+sz, " %d%% full", 10); + return sz; +} + + +static mdk_personality_t translucent_personality= +{ + "translucent", + translucent_map, + NULL, + NULL, + translucent_run, + translucent_stop, + translucent_status, + NULL, + 0, + NULL, + NULL, + NULL, + NULL +}; + +#ifndef MODULE + +md__initfunc(void translucent_init (void)) +{ + register_md_personality (TRANSLUCENT, &translucent_personality); +} + +#else + +int init_module (void) +{ + return (register_md_personality (TRANSLUCENT, &translucent_personality)); +} + +void cleanup_module (void) +{ + unregister_md_personality (TRANSLUCENT); +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/block/xor.c linux.ac/drivers/block/xor.c --- linux.vanilla/drivers/block/xor.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/block/xor.c Mon Jul 19 19:48:18 1999 @@ -0,0 +1,1480 @@ +/* + * xor.c : Multiple Devices driver for Linux + * + * Copyright (C) 1996, 1997, 1998, 1999 Ingo Molnar, Matti Aarnio, Jakub Jelinek + * + * + * optimized RAID-5 checksumming functions. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#ifdef __sparc_v9__ +#include +#include +#include +#endif + +/* + * we use the 'XOR function template' to register multiple xor + * functions runtime. The kernel measures their speed upon bootup + * and decides which one to use. (compile-time registration is + * not enough as certain CPU features like MMX can only be detected + * runtime) + * + * this architecture makes it pretty easy to add new routines + * that are faster on certain CPUs, without killing other CPU's + * 'native' routine. Although the current routines are belived + * to be the physically fastest ones on all CPUs tested, but + * feel free to prove me wrong and add yet another routine =B-) + * --mingo + */ + +#define MAX_XOR_BLOCKS 5 + +#define XOR_ARGS (unsigned int count, struct buffer_head **bh_ptr) + +typedef void (*xor_block_t) XOR_ARGS; +xor_block_t xor_block = NULL; + +#ifndef __sparc_v9__ + +struct xor_block_template; + +struct xor_block_template { + char * name; + xor_block_t xor_block; + int speed; + struct xor_block_template * next; +}; + +struct xor_block_template * xor_functions = NULL; + +#define XORBLOCK_TEMPLATE(x) \ +static void xor_block_##x XOR_ARGS; \ +static struct xor_block_template t_xor_block_##x = \ + { #x, xor_block_##x, 0, NULL }; \ +static void xor_block_##x XOR_ARGS + +#ifdef __i386__ + +#ifdef CONFIG_X86_XMM +/* + * Cache avoiding checksumming functions utilizing KNI instructions + * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) + */ + +XORBLOCK_TEMPLATE(pIII_kni) +{ + char xmm_save[16*4]; + int cr0; + int lines = (bh_ptr[0]->b_size>>8); + + __asm__ __volatile__ ( + "movl %%cr0,%0 ;\n\t" + "clts ;\n\t" + "movups %%xmm0,(%1) ;\n\t" + "movups %%xmm1,0x10(%1) ;\n\t" + "movups %%xmm2,0x20(%1) ;\n\t" + "movups %%xmm3,0x30(%1) ;\n\t" + : "=r" (cr0) + : "r" (xmm_save) + : "memory" ); + +#define OFFS(x) "8*("#x"*2)" +#define PF0(x) \ + " prefetcht0 "OFFS(x)"(%1) ;\n" +#define LD(x,y) \ + " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n" +#define ST(x,y) \ + " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n" +#define PF1(x) \ + " prefetchnta "OFFS(x)"(%2) ;\n" +#define PF2(x) \ + " prefetchnta "OFFS(x)"(%3) ;\n" +#define PF3(x) \ + " prefetchnta "OFFS(x)"(%4) ;\n" +#define PF4(x) \ + " prefetchnta "OFFS(x)"(%5) ;\n" +#define PF5(x) \ + " prefetchnta "OFFS(x)"(%6) ;\n" +#define XO1(x,y) \ + " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n" +#define XO2(x,y) \ + " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n" +#define XO3(x,y) \ + " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n" +#define XO4(x,y) \ + " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n" +#define XO5(x,y) \ + " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n" + + switch(count) { + case 2: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + PF1(i) \ + PF1(i+2) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF0(i+4) \ + PF0(i+6) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory" ); + break; + case 3: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory" ); + break; + case 4: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + PF3(i) \ + PF3(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " addl $256, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory" ); + break; + case 5: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + PF3(i) \ + PF3(i+2) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + PF4(i) \ + PF4(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + XO4(i,0) \ + XO4(i+1,1) \ + XO4(i+2,2) \ + XO4(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " addl $256, %4 ;\n" + " addl $256, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory"); + break; + } + + __asm__ __volatile__ ( + "sfence ;\n\t" + "movups (%1),%%xmm0 ;\n\t" + "movups 0x10(%1),%%xmm1 ;\n\t" + "movups 0x20(%1),%%xmm2 ;\n\t" + "movups 0x30(%1),%%xmm3 ;\n\t" + "movl %0,%%cr0 ;\n\t" + : + : "r" (cr0), "r" (xmm_save) + : "memory" ); +} + +#undef OFFS +#undef LD +#undef ST +#undef PF0 +#undef PF1 +#undef PF2 +#undef PF3 +#undef PF4 +#undef PF5 +#undef XO1 +#undef XO2 +#undef XO3 +#undef XO4 +#undef XO5 +#undef BLOCK + +#endif /* CONFIG_X86_XMM */ + +/* + * high-speed RAID5 checksumming functions utilizing MMX instructions + * Copyright (C) 1998 Ingo Molnar + */ +XORBLOCK_TEMPLATE(pII_mmx) +{ + char fpu_save[108]; + int lines = (bh_ptr[0]->b_size>>7); + + if (!(current->flags & PF_USEDFPU)) + __asm__ __volatile__ ( " clts;\n"); + + __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); + +#define LD(x,y) \ + " movq 8*("#x")(%1), %%mm"#y" ;\n" +#define ST(x,y) \ + " movq %%mm"#y", 8*("#x")(%1) ;\n" +#define XO1(x,y) \ + " pxor 8*("#x")(%2), %%mm"#y" ;\n" +#define XO2(x,y) \ + " pxor 8*("#x")(%3), %%mm"#y" ;\n" +#define XO3(x,y) \ + " pxor 8*("#x")(%4), %%mm"#y" ;\n" +#define XO4(x,y) \ + " pxor 8*("#x")(%5), %%mm"#y" ;\n" + + switch(count) { + case 2: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + ST(i,0) \ + XO1(i+1,1) \ + ST(i+1,1) \ + XO1(i+2,2) \ + ST(i+2,2) \ + XO1(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory"); + break; + case 3: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + ST(i,0) \ + XO2(i+1,1) \ + ST(i+1,1) \ + XO2(i+2,2) \ + ST(i+2,2) \ + XO2(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory"); + break; + case 4: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + ST(i,0) \ + XO3(i+1,1) \ + ST(i+1,1) \ + XO3(i+2,2) \ + ST(i+2,2) \ + XO3(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " addl $128, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory"); + break; + case 5: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + XO4(i,0) \ + ST(i,0) \ + XO4(i+1,1) \ + ST(i+1,1) \ + XO4(i+2,2) \ + ST(i+2,2) \ + XO4(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " addl $128, %4 ;\n" + " addl $128, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory"); + break; + } + + __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); + + if (!(current->flags & PF_USEDFPU)) + stts(); +} + +#undef LD +#undef XO1 +#undef XO2 +#undef XO3 +#undef XO4 +#undef ST +#undef BLOCK + +XORBLOCK_TEMPLATE(p5_mmx) +{ + char fpu_save[108]; + int lines = (bh_ptr[0]->b_size>>6); + + if (!(current->flags & PF_USEDFPU)) + __asm__ __volatile__ ( " clts;\n"); + + __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); + + switch(count) { + case 2: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 8(%2), %%mm1 ;\n" + " movq 24(%1), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " pxor 16(%2), %%mm2 ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq 40(%1), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%2), %%mm4 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq 56(%1), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%2), %%mm6 ;\n" + " pxor 56(%2), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory" ); + break; + case 3: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " movq 24(%1), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 32(%2), %%mm4 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " movq 56(%1), %%mm7 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 56(%2), %%mm7 ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory" ); + break; + case 4: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor (%4), %%mm0 ;\n" + " movq 24(%1), %%mm3 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " pxor 8(%4), %%mm1 ;\n" + " movq %%mm0, (%1) ;\n" + " movq 32(%1), %%mm4 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " pxor 16(%4), %%mm2 ;\n" + " movq %%mm1, 8(%1) ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 32(%2), %%mm4 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 40(%2), %%mm5 ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 24(%4), %%mm3 ;\n" + " movq %%mm3, 24(%1) ;\n" + " movq 56(%1), %%mm7 ;\n" + " movq 48(%1), %%mm6 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " pxor 32(%4), %%mm4 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 56(%2), %%mm7 ;\n" + " pxor 40(%4), %%mm5 ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%4), %%mm6 ;\n" + " pxor 56(%4), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " addl $64, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory" ); + break; + case 5: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " pxor (%4), %%mm0 ;\n" + " pxor 8(%4), %%mm1 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " movq 24(%1), %%mm3 ;\n" + " pxor (%5), %%mm0 ;\n" + " pxor 8(%5), %%mm1 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 16(%4), %%mm2 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " pxor 16(%5), %%mm2 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 24(%4), %%mm3 ;\n" + " pxor 32(%2), %%mm4 ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 24(%5), %%mm3 ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%4), %%mm4 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq 56(%1), %%mm7 ;\n" + " pxor 32(%5), %%mm4 ;\n" + " pxor 40(%4), %%mm5 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " pxor 56(%2), %%mm7 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " pxor 40(%5), %%mm5 ;\n" + " pxor 48(%4), %%mm6 ;\n" + " pxor 56(%4), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%5), %%mm6 ;\n" + " pxor 56(%5), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " addl $64, %4 ;\n" + " addl $64, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory" ); + break; + } + + __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); + + if (!(current->flags & PF_USEDFPU)) + stts(); +} +#endif /* __i386__ */ +#endif /* !__sparc_v9__ */ + +#ifdef __sparc_v9__ +/* + * High speed xor_block operation for RAID4/5 utilizing the + * UltraSparc Visual Instruction Set. + * + * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * Requirements: + * !(((long)destp | (long)sourcep) & (64 - 1)) && + * !(len & 127) && len >= 256 + * + * It is done in pure assembly, as otherwise gcc makes it + * a non-leaf function, which is not what we want. + * Also, we don't measure the speeds as on other architectures, + * as the measuring routine does not take into account cold caches + * and the fact that xor_block_VIS bypasses the caches. + * xor_block_32regs might be 5% faster if caches are hot and things + * just right, but I think it is better not to pollute the caches. + * Actually, if I'd just fight for speed for hot caches, I could + * write a hybrid VIS/integer routine, which would do always two + * 64B blocks in VIS and two in IEUs, but I really care more about + * caches. + */ +extern void *VISenter(void); +extern void xor_block_VIS SRCDEST; + +void __xor_block_VIS(void) +{ +__asm__ (" + .globl xor_block_VIS +xor_block_VIS: + ldx [%%o1 + %0], %%o1 + ldx [%%o0 + %1], %%o2 + ldx [%%o0 + %0], %%o0 + rd %%fprs, %%o5 + andcc %%o5, %2, %%g0 + be,pt %%icc, 297f + sethi %%hi(%5), %%g1 + jmpl %%g1 + %%lo(%5), %%g7 + add %%g7, 8, %%g7 +297: wr %%g0, %4, %%fprs + wr %%g0, %3, %%asi + membar #LoadStore|#StoreLoad|#StoreStore + sub %%o2, 128, %%o2 + ldda [%%o0] %3, %%f0 + ldda [%%o1] %3, %%f16 +1: ldda [%%o0 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o0] %3 + ldda [%%o1 + 64] %%asi, %%f48 + ldda [%%o0 + 128] %%asi, %%f0 + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + add %%o0, 128, %%o0 + fxor %%f36, %%f52, %%f52 + add %%o1, 128, %%o1 + fxor %%f38, %%f54, %%f54 + subcc %%o2, 128, %%o2 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o0 - 64] %%asi + bne,pt %%xcc, 1b + ldda [%%o1] %3, %%f16 + ldda [%%o0 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o0] %3 + ldda [%%o1 + 64] %%asi, %%f48 + membar #Sync + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + fxor %%f36, %%f52, %%f52 + fxor %%f38, %%f54, %%f54 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o0 + 64] %%asi + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + " : : + "i" (&((struct buffer_head *)0)->b_data), + "i" (&((struct buffer_head *)0)->b_size), + "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P), + "i" (FPRS_FEF), "i" (VISenter)); +} +#endif /* __sparc_v9__ */ + +#if defined(__sparc__) && !defined(__sparc_v9__) +/* + * High speed xor_block operation for RAID4/5 utilizing the + * ldd/std SPARC instructions. + * + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + */ + +XORBLOCK_TEMPLATE(SPARC) +{ + int size = dest->b_size; + int lines = size / (sizeof (long)) / 8, i; + long *destp = (long *) dest->b_data; + long *sourcep = (long *) source->b_data; + + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (sourcep) : "g2", "g3", "g4", "g5", "o0", + "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5"); + + destp += 8; + sourcep += 8; + } +} +#endif /* __sparc_v[78]__ */ + +#ifndef __sparc_v9__ + +/* + * this one works reasonably on any x86 CPU + * (send me an assembly version for inclusion if you can make it faster) + * + * this one is just as fast as written in pure assembly on x86. + * the reason for this separate version is that the + * fast open-coded xor routine "32reg" produces suboptimal code + * on x86, due to lack of registers. + */ +XORBLOCK_TEMPLATE(8regs) +{ + int len = bh_ptr[0]->b_size; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1, *source2, *source3, *source4; + long lines = len / (sizeof (long)) / 8, i; + + switch(count) { + case 2: + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 7) ^= *(source1 + 7); + source1 += 8; + destp += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + source1 += 8; + source2 += 8; + destp += 8; + } + break; + case 4: + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 0) ^= *(source3 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 1) ^= *(source3 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 2) ^= *(source3 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 3) ^= *(source3 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 4) ^= *(source3 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 5) ^= *(source3 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 6) ^= *(source3 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + *(destp + 7) ^= *(source3 + 7); + source1 += 8; + source2 += 8; + source3 += 8; + destp += 8; + } + break; + case 5: + source4 = (long *) bh_ptr[4]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 0) ^= *(source3 + 0); + *(destp + 0) ^= *(source4 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 1) ^= *(source3 + 1); + *(destp + 1) ^= *(source4 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 2) ^= *(source3 + 2); + *(destp + 2) ^= *(source4 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 3) ^= *(source3 + 3); + *(destp + 3) ^= *(source4 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 4) ^= *(source3 + 4); + *(destp + 4) ^= *(source4 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 5) ^= *(source3 + 5); + *(destp + 5) ^= *(source4 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 6) ^= *(source3 + 6); + *(destp + 6) ^= *(source4 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + *(destp + 7) ^= *(source3 + 7); + *(destp + 7) ^= *(source4 + 7); + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + destp += 8; + } + break; + } +} + +/* + * platform independent RAID5 checksum calculation, this should + * be very fast on any platform that has a decent amount of + * registers. (32 or more) + */ +XORBLOCK_TEMPLATE(32regs) +{ + int size = bh_ptr[0]->b_size; + int lines = size / (sizeof (long)) / 8, i; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1, *source2, *source3, *source4; + + /* LOTS of registers available... + We do explicite loop-unrolling here for code which + favours RISC machines. In fact this is almoast direct + RISC assembly on Alpha and SPARC :-) */ + + + switch(count) { + case 2: + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + destp += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + destp += 8; + } + break; + case 4: + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + d0 ^= source3[0]; + d1 ^= source3[1]; + d2 ^= source3[2]; + d3 ^= source3[3]; + d4 ^= source3[4]; + d5 ^= source3[5]; + d6 ^= source3[6]; + d7 ^= source3[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + source3 += 8; + destp += 8; + } + break; + case 5: + source4 = (long *) bh_ptr[4]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + d0 ^= source3[0]; + d1 ^= source3[1]; + d2 ^= source3[2]; + d3 ^= source3[3]; + d4 ^= source3[4]; + d5 ^= source3[5]; + d6 ^= source3[6]; + d7 ^= source3[7]; + d0 ^= source4[0]; + d1 ^= source4[1]; + d2 ^= source4[2]; + d3 ^= source4[3]; + d4 ^= source4[4]; + d5 ^= source4[5]; + d6 ^= source4[6]; + d7 ^= source4[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + destp += 8; + } + break; + } +} + +/* + * (the -6*32 shift factor colors the cache) + */ +#define SIZE (PAGE_SIZE-6*32) + +static void xor_speed ( struct xor_block_template * func, + struct buffer_head *b1, struct buffer_head *b2) +{ + int speed; + unsigned long now; + int i, count, max; + struct buffer_head *bh_ptr[6]; + + func->next = xor_functions; + xor_functions = func; + bh_ptr[0] = b1; + bh_ptr[1] = b2; + + /* + * count the number of XORs done during a whole jiffy. + * calculate the speed of checksumming from this. + * (we use a 2-page allocation to have guaranteed + * color L1-cache layout) + */ + max = 0; + for (i = 0; i < 5; i++) { + now = jiffies; + count = 0; + while (jiffies == now) { + mb(); + func->xor_block(2,bh_ptr); + mb(); + count++; + mb(); + } + if (count > max) + max = count; + } + + speed = max * (HZ*SIZE/1024); + func->speed = speed; + + printk( " %-10s: %5d.%03d MB/sec\n", func->name, + speed / 1000, speed % 1000); +} + +static inline void pick_fastest_function(void) +{ + struct xor_block_template *f, *fastest; + + fastest = xor_functions; + for (f = fastest; f; f = f->next) { + if (f->speed > fastest->speed) + fastest = f; + } +#ifdef CONFIG_X86_XMM + if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) { + fastest = &t_xor_block_pIII_kni; + } +#endif + xor_block = fastest->xor_block; + printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name, + fastest->speed / 1000, fastest->speed % 1000); +} + + +void calibrate_xor_block(void) +{ + struct buffer_head b1, b2; + + memset(&b1,0,sizeof(b1)); + b2 = b1; + + b1.b_data = (char *) md__get_free_pages(GFP_KERNEL,2); + if (!b1.b_data) { + pick_fastest_function(); + return; + } + b2.b_data = b1.b_data + 2*PAGE_SIZE + SIZE; + + b1.b_size = SIZE; + + printk(KERN_INFO "raid5: measuring checksumming speed\n"); + + sti(); /* should be safe */ + +#if defined(__sparc__) && !defined(__sparc_v9__) + printk(KERN_INFO "raid5: using high-speed SPARC checksum routine\n"); + xor_speed(&t_xor_block_SPARC,&b1,&b2); +#endif + +#ifdef CONFIG_X86_XMM + if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) { + printk(KERN_INFO + "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n"); + /* we force the use of the KNI xor block because it + can write around l2. we may also be able + to load into the l1 only depending on how + the cpu deals with a load to a line that is + being prefetched. + */ + xor_speed(&t_xor_block_pIII_kni,&b1,&b2); + } +#endif /* CONFIG_X86_XMM */ + +#ifdef __i386__ + + if (md_cpu_has_mmx()) { + printk(KERN_INFO + "raid5: MMX detected, trying high-speed MMX checksum routines\n"); + xor_speed(&t_xor_block_pII_mmx,&b1,&b2); + xor_speed(&t_xor_block_p5_mmx,&b1,&b2); + } + +#endif /* __i386__ */ + + + xor_speed(&t_xor_block_8regs,&b1,&b2); + xor_speed(&t_xor_block_32regs,&b1,&b2); + + free_pages((unsigned long)b1.b_data,2); + pick_fastest_function(); +} + +#else /* __sparc_v9__ */ + +void calibrate_xor_block(void) +{ + printk(KERN_INFO "raid5: using high-speed VIS checksum routine\n"); + xor_block = xor_block_VIS; +} + +#endif /* __sparc_v9__ */ + +MD_EXPORT_SYMBOL(xor_block); + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/cdrom/cdrom.c linux.ac/drivers/cdrom/cdrom.c --- linux.vanilla/drivers/cdrom/cdrom.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/cdrom/cdrom.c Mon Jul 19 03:29:53 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Config.in linux.ac/drivers/char/Config.in --- linux.vanilla/drivers/char/Config.in Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Config.in Fri Jul 2 23:14:12 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 @@ -145,6 +148,11 @@ 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 if [ "$CONFIG_RADIO_TYPHOON" != "n" ]; then @@ -159,6 +167,9 @@ if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi + dep_tristate 'Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV + dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN + #dep_tristate ' Include support for LML33' CONFIG_VIDEO_LML33 $CONFIG_VIDEO_ZORAN fi endmenu @@ -173,6 +184,8 @@ endmenu tristate 'Double Talk PC internal speech card support' CONFIG_DTLK + +tristate 'Mappable DMA driver for 3D graphics cards' CONFIG_DMARAM mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/Makefile linux.ac/drivers/char/Makefile --- linux.vanilla/drivers/char/Makefile Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/Makefile Mon Jul 19 19:39:12 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 @@ -278,6 +294,14 @@ endif endif +ifeq ($(CONFIG_DMARAM),y) +L_OBJS += dmaram.o +else + ifeq ($(CONFIG_DMARAM),m) + M_OBJS += dmaram.o + endif +endif + ifeq ($(CONFIG_RTC),y) L_OBJS += rtc.o endif @@ -346,6 +370,30 @@ endif endif +ifeq ($(CONFIG_VIDEO_ZORAN),y) +L_OBJS += buz.o +else + ifeq ($(CONFIG_VIDEO_ZORAN),m) + M_OBJS += buz.o + endif +endif + +ifeq ($(CONFIG_VIDEO_LML33),y) +L_OBJS += bt856.o bt819.o +else + ifeq ($(CONFIG_VIDEO_LML33),m) + M_OBJS += bt856.o bt819.o + endif +endif + +ifeq ($(CONFIG_VIDEO_BUZ),y) +L_OBJS += saa7111.o saa7185.o +else + ifeq ($(CONFIG_VIDEO_BUZ),m) + M_OBJS += saa7111.o saa7185.o + endif +endif + ifeq ($(CONFIG_VIDEO_PMS),y) L_OBJS += pms.o else @@ -362,6 +410,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 +533,10 @@ MOD_SUB_DIRS += hfmodem endif +endif + +ifeq ($(CONFIG_DZ),y) + L_OBJS += dz.o endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/adbmouse.c linux.ac/drivers/char/adbmouse.c --- linux.vanilla/drivers/char/adbmouse.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/adbmouse.c Mon Jul 19 19:48:18 1999 @@ -38,7 +38,7 @@ #ifdef __powerpc__ #include #endif -#ifdef __mc68000__ +#if defined(__mc68000__) || defined(MODULE) #include #endif @@ -282,7 +282,6 @@ } #ifdef MODULE -#include int init_module(void) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/amigamouse.c linux.ac/drivers/char/amigamouse.c --- linux.vanilla/drivers/char/amigamouse.c Sun Nov 8 15:07:43 1998 +++ linux.ac/drivers/char/amigamouse.c Mon Jul 19 19:48:18 1999 @@ -333,7 +333,6 @@ } #ifdef MODULE -#include int init_module(void) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.c linux.ac/drivers/char/bttv.c --- linux.vanilla/drivers/char/bttv.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/bttv.c Mon Jul 19 19:48:18 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 */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ -static inline unsigned long uvirt_to_phys(unsigned long adr) +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) { - pgd_t *pgd; + unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; - pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) - return 0; - pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) - return 0; - ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); - pte = *ptep; - if(pte_present(pte)) - return - virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); - return 0; + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; } static inline unsigned long uvirt_to_bus(unsigned long adr) { - return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); -} + unsigned long kva, ret; -/* convert virtual kernel memory address to physical address */ -/* (virt_to_phys only works for kmalloced kernel memory) */ + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} -static inline unsigned long kvirt_to_phys(unsigned long adr) +static inline unsigned long kvirt_to_bus(unsigned long adr) { - return uvirt_to_phys(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; } -static inline unsigned long kvirt_to_bus(unsigned long adr) +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) { - return uvirt_to_bus(VMALLOC_VMADDR(adr)); + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; } static void * rvmalloc(unsigned long size) @@ -188,8 +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; } @@ -541,13 +569,15 @@ /* 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, 2, 0xc00, { 0, 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; @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bttv.h linux.ac/drivers/char/bttv.h --- linux.vanilla/drivers/char/bttv.h Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/bttv.h Mon Jul 19 21:16:51 1999 @@ -102,9 +102,9 @@ #else struct pci_dev *dev; #endif - unsigned char irq; /* IRQ used by Bt848 card */ + unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; - unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ unsigned long busriscmem; u32 *riscmem; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/buz.c linux.ac/drivers/char/buz.c --- linux.vanilla/drivers/char/buz.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/buz.c Mon Jul 19 03:45:43 1999 @@ -0,0 +1,3481 @@ +#define MAX_KMALLOC_MEM (512*1024) +/* + buz - Iomega Buz driver version 1.0 + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.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 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include "buz.h" +#include +#include + +#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) +#define GPIO_MASK 0xdf + +/* + + BUZ + + GPIO0 = 1, take board out of reset + GPIO1 = 1, take JPEG codec out of sleep mode + GPIO3 = 1, deassert FRAME# to 36060 + + + GIRQ0 signals a vertical sync of the video signal + GIRQ1 signals that ZR36060's DATERR# line is asserted. + + SAA7111A + + In their infinite wisdom, the Iomega engineers decided to + use the same input line for composite and S-Video Color, + although there are two entries not connected at all! + Through this ingenious strike, it is not possible to + keep two running video sources connected at the same time + to Composite and S-VHS input! + + mode 0 - N/C + mode 1 - S-Video Y + mode 2 - noise or something I don't know + mode 3 - Composite and S-Video C + mode 4 - N/C + mode 5 - S-Video (gain C independently selectable of gain Y) + mode 6 - N/C + mode 7 - S-Video (gain C adapted to gain Y) + */ + +#define MAJOR_VERSION 1 /* driver major version */ +#define MINOR_VERSION 0 /* driver minor version */ + +#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define IOCTL_DEBUG(x) + + +/* The parameters for this driver */ + +/* + The video mem address of the video card. + The driver has a little database for some videocards + to determine it from there. If your video card is not in there + you have either to give it to the driver as a parameter + or set in in a VIDIOCSFBUF ioctl + */ + +static unsigned long vidmem = 0; /* Video memory base address */ + +/* Special purposes only: */ + +static int triton = 0; /* 0=no, 1=yes */ +static int natoma = 0; /* 0=no, 1=yes */ + +/* + Number and size of grab buffers for Video 4 Linux + The vast majority of applications should not need more than 2, + the very popular BTTV driver actually does ONLY have 2. + Time sensitive applications might need more, the maximum + is VIDEO_MAX_FRAME (defined in ). + + The size is set so that the maximum possible request + can be satisfied. Decrease it, if bigphys_area alloc'd + memory is low. If you don't have the bigphys_area patch, + set it to 128 KB. Will you allow only to grab small + images with V4L, but that's better than nothing. + + v4l_bufsize has to be given in KB ! + + */ + +static int v4l_nbufs = 2; +static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ + +/* + Default input and video norm at startup of the driver. + */ + +static int default_input = 0; /* 0=Composite, 1=S-VHS */ +static int default_norm = 0; /* 0=PAL, 1=NTSC */ + +MODULE_PARM(vidmem, "i"); +MODULE_PARM(triton, "i"); +MODULE_PARM(natoma, "i"); +MODULE_PARM(v4l_nbufs, "i"); +MODULE_PARM(v4l_bufsize, "i"); +MODULE_PARM(default_input, "i"); +MODULE_PARM(default_norm, "i"); + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +static int zoran_num; /* number of Buzs in use */ +static struct zoran zoran[BUZ_MAX]; + +/* forward references */ + +static void v4l_fbuffer_free(struct zoran *zr); +static void jpg_fbuffer_free(struct zoran *zr); +static void zoran_feed_stat_com(struct zoran *zr); + + + +/* + * Allocate the V4L grab buffers + * + * These have to be pysically contiguous. + * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + */ + +static int v4l_fbuffer_alloc(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (zr->v4l_gbuf[i].fbuffer) + printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); + + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + /* Use kmalloc */ + + mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); + } else { + return -ENOBUFS; + } + } + + return 0; +} + +/* free the V4L grab buffers */ +static void v4l_fbuffer_free(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (!zr->v4l_gbuf[i].fbuffer) + continue; + + mem = zr->v4l_gbuf[i].fbuffer; + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) zr->v4l_gbuf[i].fbuffer); + zr->v4l_gbuf[i].fbuffer = NULL; + } +} + +/* + * Allocate the MJPEG grab buffers. + * + * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * kmalloc is used to request a physically contiguous area, + * else we allocate the memory in framgents with get_free_page. + * + * If a Natoma chipset is present and this is a revision 1 zr36057, + * each MJPEG buffer needs to be physically contiguous. + * (RJ: This statement is from Dave Perks' original driver, + * I could never check it because I have a zr36067) + * The driver cares about this because it reduces the buffer + * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * + * RJ: The contents grab buffers needs never be accessed in the driver. + * Therefore there is no need to allocate them with vmalloc in order + * to get a contiguous virtual memory space. + * I don't understand why many other drivers first allocate them with + * vmalloc (which uses internally also get_free_page, but delivers you + * virtual addresses) and then again have to make a lot of efforts + * to get the physical address. + * + */ + +static int jpg_fbuffer_alloc(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned long mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->jpg_gbuf[i].frag_tab) + printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); + + /* Allocate fragment table for this buffer */ + + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + memset((void *) mem, 0, PAGE_SIZE); + zr->jpg_gbuf[i].frag_tab = (u32 *) mem; + zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); + + if (alloc_contig) { + mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + } else { + /* jpg_bufsize is alreay page aligned */ + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; + mem_map_reserve(MAP_NR(mem)); + } + + zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; + } + } + + DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", + (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); + zr->jpg_buffers_allocated = 1; + return 0; +} + +/* free the MJPEG grab buffers */ +static void jpg_fbuffer_free(struct zoran *zr) +{ + int i, j, off, alloc_contig; + unsigned char *mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (!zr->jpg_gbuf[i].frag_tab) + continue; + + if (alloc_contig) { + if (zr->jpg_gbuf[i].frag_tab[0]) { + mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) mem); + zr->jpg_gbuf[i].frag_tab[0] = 0; + zr->jpg_gbuf[i].frag_tab[1] = 0; + } + } else { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + if (!zr->jpg_gbuf[i].frag_tab[2 * j]) + break; + mem_map_unreserve(MAP_NR(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); + free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); + zr->jpg_gbuf[i].frag_tab[2 * j] = 0; + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; + } + } + + free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); + zr->jpg_gbuf[i].frag_tab = NULL; + } + zr->jpg_buffers_allocated = 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* I2C functions */ + +#define I2C_DELAY 10 + + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) +{ + struct zoran *zr = (struct zoran *) bus->data; + btwrite((data << 1) | ctrl, ZR36057_I2CBR); + btread(ZR36057_I2CBR); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *zr = (struct zoran *) bus->data; + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +void attach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); +} + +void detach_inform(struct i2c_bus *bus, int id) +{ + DEBUG(struct zoran *zr = (struct zoran *) bus->data); + DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); +} + +static struct i2c_bus zoran_i2c_bus_template = +{ + "zr36057", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + + +/* ----------------------------------------------------------------------- */ + +static void GPIO(struct zoran *zr, unsigned bit, unsigned value) +{ + u32 reg; + u32 mask; + + mask = 1 << (24 + bit); + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) { + reg |= mask; + } + btwrite(reg, ZR36057_GPPGCR1); + /* Stop any PCI posting on the GPIO bus */ + btread(ZR36057_I2CBR); +} + + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.zoran.com - nicely done those folks. + */ + +struct tvnorm { + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = +{ + /* PAL-BDGHI */ + {864, 720, 625, 576, 31, 16}, + /* NTSC */ + {858, 720, 525, 480, 21, 8}, +}; +#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) + +static int format2bpp(int format) +{ + int bpp; + + /* Determine the number of bytes per pixel for the video format requested */ + + switch (format) { + + case VIDEO_PALETTE_YUV422: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB555: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB565: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB24: + bpp = 3; + break; + + case VIDEO_PALETTE_RGB32: + bpp = 4; + break; + + default: + bpp = 0; + } + + return bpp; +} + +/* + * set geometry + */ +static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, + unsigned int video_format) +{ + struct tvnorm *tvn; + unsigned HStart, HEnd, VStart, VEnd; + unsigned DispMode; + unsigned VidWinWid, VidWinHt; + unsigned hcrop1, hcrop2, vcrop1, vcrop2; + unsigned Wa, We, Ha, He; + unsigned X, Y, HorDcm, VerDcm; + u32 reg; + unsigned mask_line_size; + + if (zr->params.norm < 0 || zr->params.norm > 1) { + printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); + return; + } + if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { + printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); + return; + } + tvn = &tvnorms[zr->params.norm]; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + /* if window has more than half of active height, + switch on interlacing - we want the full information */ + + zr->video_interlace = (video_height > Ha / 2); + +/**** zr36057 ****/ + + /* horizontal */ + VidWinWid = video_width; + X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; + We = (VidWinWid * 64) / X; + HorDcm = 64 - X; + hcrop1 = 2 * ((tvn->Wa - We) / 4); + hcrop2 = tvn->Wa - We - hcrop1; + HStart = tvn->HStart | 1; + HEnd = HStart + tvn->Wa - 1; + HStart += hcrop1; + HEnd -= hcrop2; + reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) + | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); + reg |= ZR36057_VFEHCR_HSPol; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + DispMode = !zr->video_interlace; + VidWinHt = DispMode ? video_height : video_height / 2; + Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; + He = (VidWinHt * 64) / Y; + VerDcm = 64 - Y; + vcrop1 = (tvn->Ha / 2 - He) / 2; + vcrop2 = tvn->Ha / 2 - He - vcrop1; + VStart = tvn->VStart; + VEnd = VStart + tvn->Ha / 2 - 1; + VStart += vcrop1; + VEnd -= vcrop2; + reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) + | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); + reg |= ZR36057_VFEVCR_VSPol; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ + | (HorDcm << ZR36057_VFESPFR_HorDcm) + | (VerDcm << ZR36057_VFESPFR_VerDcm) + | (DispMode << ZR36057_VFESPFR_DispMode) + | ZR36057_VFESPFR_LittleEndian; + /* RJ: I don't know, why the following has to be the opposite + of the corresponding ZR36060 setting, but only this way + we get the correct colors when uncompressing to the screen */ + reg |= ZR36057_VFESPFR_VCLKPol; + /* RJ: Don't know if that is needed for NTSC also */ + reg |= ZR36057_VFESPFR_TopField; + switch (video_format) { + + case VIDEO_PALETTE_YUV422: + reg |= ZR36057_VFESPFR_YUV422; + break; + + case VIDEO_PALETTE_RGB555: + reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB565: + reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB24: + reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; + break; + + case VIDEO_PALETTE_RGB32: + reg |= ZR36057_VFESPFR_RGB888; + break; + + default: + printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); + return; + + } + if (HorDcm >= 48) { + reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ + } else if (HorDcm >= 32) { + reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ + } else if (HorDcm >= 16) { + reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ + } + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + + reg = (16 << ZR36057_VDCR_MinPix) + | (VidWinHt << ZR36057_VDCR_VidWinHt) + | (VidWinWid << ZR36057_VDCR_VidWinWid); + if (triton) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); + + /* Write overlay clipping mask data, but don't enable overlay clipping */ + /* RJ: since this makes only sense on the screen, we use + zr->window.width instead of video_width */ + + mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + reg = virt_to_bus(zr->overlay_mask); + btwrite(reg, ZR36057_MMTR); + reg = virt_to_bus(zr->overlay_mask + mask_line_size); + btwrite(reg, ZR36057_MMBR); + reg = mask_line_size - (zr->window.width + 31) / 32; + if (DispMode == 0) + reg += mask_line_size; + reg <<= ZR36057_OCR_MaskStride; + btwrite(reg, ZR36057_OCR); + +} + +/* + * Switch overlay on or off + */ + +static void zr36057_overlay(struct zoran *zr, int on) +{ + int fmt, bpp; + u32 reg; + + if (on) { + /* do the necessary settings ... */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ + + switch (zr->buffer.depth) { + case 15: + fmt = VIDEO_PALETTE_RGB555; + bpp = 2; + break; + case 16: + fmt = VIDEO_PALETTE_RGB565; + bpp = 2; + break; + case 24: + fmt = VIDEO_PALETTE_RGB24; + bpp = 3; + break; + case 32: + fmt = VIDEO_PALETTE_RGB32; + bpp = 4; + break; + default: + fmt = 0; + bpp = 0; + } + + zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); + + /* Start and length of each line MUST be 4-byte aligned. + This should be allready checked before the call to this routine. + All error messages are internal driver checking only! */ + + /* video display top and bottom registers */ + + reg = (u32) zr->buffer.base + + zr->window.x * bpp + + zr->window.y * zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDTR); + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = zr->buffer.bytesperline - zr->window.width * bpp; + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + if (reg & 3) + printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ + btwrite(reg, ZR36057_VSSFGR); + + /* Set overlay clipping */ + + if (zr->window.clipcount) + btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); + + /* ... and switch it on */ + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } else { + /* Switch it off */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + } +} + +/* + * The overlay mask has one bit for each pixel on a scan line, + * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. + */ +static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) +{ + unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + u32 *mask; + int x, y, width, height; + unsigned i, j, k; + u32 reg; + + /* fill mask with one bits */ + memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); + reg = 0; + + for (i = 0; i < count; ++i) { + /* pick up local copy of clip */ + x = vp[i].x; + y = vp[i].y; + width = vp[i].width; + height = vp[i].height; + + /* trim clips that extend beyond the window */ + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > zr->window.width) { + width = zr->window.width - x; + } + if (y + height > zr->window.height) { + height = zr->window.height - y; + } + /* ignore degenerate clips */ + if (height <= 0) { + continue; + } + if (width <= 0) { + continue; + } + /* apply clip for each scan line */ + for (j = 0; j < height; ++j) { + /* reset bit for each pixel */ + /* this can be optimized later if need be */ + mask = zr->overlay_mask + (y + j) * mask_line_size; + for (k = 0; k < width; ++k) { + mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); + } + } + } +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ + +static void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) + printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); + + /* switch on VSync interrupts */ + + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + + btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* enable SnapShot */ + + btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + +#ifdef XAWTV_HACK + zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); +#else + zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); +#endif + + zr->v4l_memgrab_active = 1; + } else { + zr->v4l_memgrab_active = 0; + + /* switch off VSync interrupts */ + + btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); + + /* reenable grabbing to screen if it was running */ + + if (zr->v4l_overlay_active) { + zr36057_overlay(zr, 1); + } else { + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + } + } +} + +static int wait_grab_pending(struct zoran *zr) +{ + unsigned long flags; + + /* wait until all pending grabs are finished */ + + if (!zr->v4l_memgrab_active) + return 0; + + while (zr->v4l_pend_tail != zr->v4l_pend_head) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + zr36057_set_memgrab(zr, 0); + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* + * V4L Buffer grabbing + */ + +static int v4l_grab(struct zoran *zr, struct video_mmap *mp) +{ + unsigned long flags; + int res, bpp; + + /* + * There is a long list of limitations to what is allowed to be grabbed + * We don't output error messages her, since some programs (e.g. xawtv) + * just try several settings to find out what is valid or not. + */ + + /* No grabbing outside the buffer range! */ + + if (mp->frame >= v4l_nbufs || mp->frame < 0) + return -EINVAL; + + /* Check size and format of the grab wanted */ + + if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) + return -EINVAL; + if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) + return -EINVAL; + + bpp = format2bpp(mp->format); + if (bpp == 0) + return -EINVAL; + + /* Check against available buffer size */ + + if (mp->height * mp->width * bpp > v4l_bufsize) + return -EINVAL; + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) + return -EINVAL; + + /* + * To minimize the time spent in the IRQ routine, we avoid setting up + * the video front end there. + * If this grab has different parameters from a running streaming capture + * we stop the streaming capture and start it over again. + */ + + if (zr->v4l_memgrab_active && + (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { + res = wait_grab_pending(zr); + if (res) + return res; + } + zr->gwidth = mp->width; + zr->gheight = mp->height; + zr->gformat = mp->format; + zr->gbpl = bpp * zr->gwidth; + + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->v4l_gbuf[mp->frame].state) { + + default: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + case BUZ_STATE_DONE: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; + zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; + res = 0; + break; + + } + + /* put the 36057 into frame grabbing mode */ + + if (!res && !zr->v4l_memgrab_active) + zr36057_set_memgrab(zr, 1); + + spin_unlock_irqrestore(&zr->lock, flags); + + return res; +} + +/* + * Sync on a V4L buffer + */ + +static int v4l_sync(struct zoran *zr, int frame) +{ + unsigned long flags; + + + /* check passed-in frame number */ + if (frame >= v4l_nbufs || frame < 0) { + printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); + return -EINVAL; + } + /* Check if is buffer was queued at all */ + + if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { +// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); + return -EINVAL; + } + /* wait on this buffer to get ready */ + + while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); + + /* Check if streaming capture has finished */ + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->v4l_pend_tail == zr->v4l_pend_head) + zr36057_set_memgrab(zr, 0); + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +/* + * Wait til post office is no longer busy + */ + +static int post_office_wait(struct zoran *zr) +{ + u32 por; + u32 ct=0; + + while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { + ct++; + if(ct>100000) + { + printk(KERN_ERR "%s: timeout on post office.\n", zr->name); + return -1; + } + /* wait for something to happen */ + } + if ((por & ZR36057_POR_POPen) != 0) { + printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); + return -1; + } +#if 0 + /* The LML 33 gets this bit wrong */ + + if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { + printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); + return -1; + } +#endif + return 0; +} + +static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + return post_office_wait(zr); +} + +static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) +{ + u32 por; + + post_office_wait(zr); + por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) { + return -1; + } + return btread(ZR36057_POR) & 0xFF; +} + +static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_write(zr, 0, 3, val); +} + +static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 8)) { + return -1; + } + return zr36060_write_8(zr, reg + 1, val >> 0); +} + +static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 1, val >> 0); +} + +static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_16(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 2, val >> 0); +} + +static u32 zr36060_read_8(struct zoran *zr, unsigned reg) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_read(zr, 0, 3) & 0xFF; +} + +static int zr36060_reset(struct zoran *zr) +{ + return post_office_write(zr, 3, 0, 0); +} + +static void zr36060_sleep(struct zoran *zr, int sleep) +{ + GPIO(zr, 1, !sleep); +} + + +static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int size; + + reg = (1 << 0) /* CodeMstr */ + |(0 << 2) /* CFIS=0 */ + |(0 << 6) /* Endian=0 */ + |(0 << 7); /* Code16=0 */ + zr36060_write_8(zr, 0x002, reg); + + switch (mode) { + + case BUZ_MODE_MOTION_DECOMPRESS: + case BUZ_MODE_STILL_DECOMPRESS: + reg = 0x00; /* Codec mode = decompression */ + break; + + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_STILL_COMPRESS: + default: + reg = 0xa4; /* Codec mode = compression with variable scale factor */ + break; + + } + zr36060_write_8(zr, 0x003, reg); + + reg = 0x00; /* reserved, mbz */ + zr36060_write_8(zr, 0x004, reg); + + reg = 0xff; /* 510 bits/block */ + zr36060_write_8(zr, 0x005, reg); + + /* JPEG markers */ + reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ + if (zr->params.COM_len) + reg |= JPEG_MARKER_COM; + if (zr->params.APP_len) + reg |= JPEG_MARKER_APP; + zr36060_write_8(zr, 0x006, reg); + + reg = (0 << 3) /* DATERR=0 */ + |(0 << 2) /* END=0 */ + |(0 << 1) /* EOI=0 */ + |(0 << 0); /* EOAV=0 */ + zr36060_write_8(zr, 0x007, reg); + + /* code volume */ + + /* Target field size in pixels: */ + tvn = &tvnorms[zr->params.norm]; + size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); + + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ + + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + + /* Upper limit: 7/8 of the code buffers */ + if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) + size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; + + reg = size; + zr36060_write_32(zr, 0x009, reg); + + /* how do we set initial SF as a function of quality parameter? */ + reg = 0x0100; /* SF=1.0 */ + zr36060_write_16(zr, 0x011, reg); + + reg = 0x00ffffff; /* AF=max */ + zr36060_write_24(zr, 0x013, reg); + + reg = 0x0000; /* test */ + zr36060_write_16(zr, 0x024, reg); +} + +static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + + reg = (0 << 7) /* Video8=0 */ + |(0 << 6) /* Range=0 */ + |(0 << 3) /* FlDet=0 */ + |(1 << 2) /* FlVedge=1 */ + |(0 << 1) /* FlExt=0 */ + |(0 << 0); /* SyncMstr=0 */ + + /* According to ZR36067 documentation, FlDet should correspond + to the odd_even flag of the ZR36067 */ + if (zr->params.odd_even) + reg |= (1 << 3); + + if (mode != BUZ_MODE_STILL_DECOMPRESS) { + /* limit pixels to range 16..235 as per CCIR-601 */ + reg |= (1 << 6); /* Range=1 */ + } + zr36060_write_8(zr, 0x030, reg); + + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(0 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + zr36060_write_8(zr, 0x031, reg); + + switch (zr->params.HorDcm) { + default: + case 1: + reg = (0 << 0); + break; /* HScale = 0 */ + + case 2: + reg = (1 << 0); + break; /* HScale = 1 */ + + case 4: + reg = (2 << 0); + break; /* HScale = 2 */ + } + if (zr->params.VerDcm == 2) + reg |= (1 << 2); + zr36060_write_8(zr, 0x032, reg); + + reg = 0x80; /* BackY */ + zr36060_write_8(zr, 0x033, reg); + + reg = 0xe0; /* BackU */ + zr36060_write_8(zr, 0x034, reg); + + reg = 0xe0; /* BackV */ + zr36060_write_8(zr, 0x035, reg); + + /* sync generator */ + + tvn = &tvnorms[zr->params.norm]; + + reg = tvn->Ht - 1; /* Vtotal */ + zr36060_write_16(zr, 0x036, reg); + + reg = tvn->Wt - 1; /* Htotal */ + zr36060_write_16(zr, 0x038, reg); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write_8(zr, 0x03a, reg); + + reg = 100 - 1; /* HsyncSize */ + zr36060_write_8(zr, 0x03b, reg); + + reg = tvn->VStart - 1; /* BVstart */ + zr36060_write_8(zr, 0x03c, reg); + + reg += tvn->Ha / 2; /* BVend */ + zr36060_write_16(zr, 0x03e, reg); + + reg = tvn->HStart - 1; /* BHstart */ + zr36060_write_8(zr, 0x03d, reg); + + reg += tvn->Wa; /* BHend */ + zr36060_write_16(zr, 0x040, reg); + + /* active area */ + reg = zr->params.img_y + tvn->VStart; /* Vstart */ + zr36060_write_16(zr, 0x042, reg); + + reg += zr->params.img_height; /* Vend */ + zr36060_write_16(zr, 0x044, reg); + + reg = zr->params.img_x + tvn->HStart; /* Hstart */ + zr36060_write_16(zr, 0x046, reg); + + reg += zr->params.img_width; /* Hend */ + zr36060_write_16(zr, 0x048, reg); + + /* subimage area */ + reg = zr->params.img_y + tvn->VStart; /* SVstart */ + zr36060_write_16(zr, 0x04a, reg); + + reg += zr->params.img_height; /* SVend */ + zr36060_write_16(zr, 0x04c, reg); + + reg = zr->params.img_x + tvn->HStart; /* SHstart */ + zr36060_write_16(zr, 0x04e, reg); + + reg += zr->params.img_width; /* SHend */ + zr36060_write_16(zr, 0x050, reg); +} + +static void zr36060_set_jpg_SOF(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffc0; /* SOF marker */ + zr36060_write_16(zr, 0x060, reg); + + reg = 17; /* SOF length */ + zr36060_write_16(zr, 0x062, reg); + + reg = 8; /* precision 8 bits */ + zr36060_write_8(zr, 0x064, reg); + + reg = zr->params.img_height / zr->params.VerDcm; /* image height */ + zr36060_write_16(zr, 0x065, reg); + + reg = zr->params.img_width / zr->params.HorDcm; /* image width */ + zr36060_write_16(zr, 0x067, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x069, reg); + + reg = 0x002100; /* Y component */ + zr36060_write_24(zr, 0x06a, reg); + + reg = 0x011101; /* U component */ + zr36060_write_24(zr, 0x06d, reg); + + reg = 0x021101; /* V component */ + zr36060_write_24(zr, 0x070, reg); +} + +static void zr36060_set_jpg_SOS(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffda; /* SOS marker */ + zr36060_write_16(zr, 0x07a, reg); + + reg = 12; /* SOS length */ + zr36060_write_16(zr, 0x07c, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x07e, reg); + + reg = 0x0000; /* Y component */ + zr36060_write_16(zr, 0x07f, reg); + + reg = 0x0111; /* U component */ + zr36060_write_16(zr, 0x081, reg); + + reg = 0x0211; /* V component */ + zr36060_write_16(zr, 0x083, reg); + + reg = 0x003f00; /* Start, end spectral scans */ + zr36060_write_24(zr, 0x085, reg); +} + +static void zr36060_set_jpg_DRI(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffdd; /* DRI marker */ + zr36060_write_16(zr, 0x0c0, reg); + + reg = 4; /* DRI length */ + zr36060_write_16(zr, 0x0c2, reg); + + reg = 8; /* length in MCUs */ + zr36060_write_16(zr, 0x0c4, reg); +} + +static void zr36060_set_jpg_DQT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dqt[] = + { + 0xff, 0xdb, /* DHT marker */ + 0x00, 0x84, /* DHT length */ + 0x00, /* table ID 0 */ + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, /* table ID 1 */ + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }; + + /* write fixed quantitization tables */ + adr = 0x0cc; + for (i = 0; i < sizeof(dqt); ++i) { + zr36060_write_8(zr, adr++, dqt[i]); + } +} + +static void zr36060_set_jpg_DHT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dht[] = + { + 0xff, 0xc4, /* DHT marker */ + 0x01, 0xa2, /* DHT length */ + 0x00, /* table class 0, ID 0 */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ + 0x00, /* values for codes of length 2 */ + 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ + 0x06, /* values for codes of length 4 */ + 0x07, /* values for codes of length 5 */ + 0x08, /* values for codes of length 6 */ + 0x09, /* values for codes of length 7 */ + 0x0a, /* values for codes of length 8 */ + 0x0b, /* values for codes of length 9 */ + 0x01, /* table class 0, ID 1 */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ + 0x00, 0x01, 0x02, /* values for codes of length 2 */ + 0x03, /* values for codes of length 3 */ + 0x04, /* values for codes of length 4 */ + 0x05, /* values for codes of length 5 */ + 0x06, /* values for codes of length 6 */ + 0x07, /* values for codes of length 7 */ + 0x08, /* values for codes of length 8 */ + 0x09, /* values for codes of length 9 */ + 0x0a, /* values for codes of length 10 */ + 0x0b, /* values for codes of length 11 */ + 0x10, + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, + 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, + 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, + 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, + 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + + /* write fixed Huffman tables */ + adr = 0x1d4; + for (i = 0; i < sizeof(dht); ++i) { + zr36060_write_8(zr, adr++, dht[i]); + } +} + +static void zr36060_set_jpg_APP(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.APP_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + i = zr->params.APPn; + if (i < 0) + i = 0; + if (i > 15) + i = 15; + + reg = 0xffe0 + i; /* APPn marker */ + zr36060_write_16(zr, 0x380, reg); + + reg = len + 2; /* APPn len */ + zr36060_write_16(zr, 0x382, reg); + + /* write APPn data */ + adr = 0x384; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); + } +} + +static void zr36060_set_jpg_COM(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.COM_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + reg = 0xfffe; /* COM marker */ + zr36060_write_16(zr, 0x3c0, reg); + + reg = len + 2; /* COM len */ + zr36060_write_16(zr, 0x3c2, reg); + + /* write COM data */ + adr = 0x3c4; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); + } +} + +static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) +{ + unsigned i; + u32 reg; + + zr36060_reset(zr); + mdelay(10); + + reg = (0 << 7) /* Load=0 */ + |(1 << 0); /* SynRst=1 */ + zr36060_write_8(zr, 0x000, reg); + + zr36060_set_jpg(zr, mode); + zr36060_set_video(zr, mode); + zr36060_set_jpg_SOF(zr); + zr36060_set_jpg_SOS(zr); + zr36060_set_jpg_DRI(zr); + zr36060_set_jpg_DQT(zr); + zr36060_set_jpg_DHT(zr); + zr36060_set_jpg_APP(zr); + zr36060_set_jpg_COM(zr); + + reg = (1 << 7) /* Load=1 */ + |(0 << 0); /* SynRst=0 */ + zr36060_write_8(zr, 0x000, reg); + + /* wait for codec to unbusy */ + for (i = 0; i < 1000; ++i) { + reg = zr36060_read_8(zr, 0x001); + if ((reg & (1 << 7)) == 0) { + DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); + return; + } + udelay(1000); + } + printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int i; + + tvn = &tvnorms[zr->params.norm]; + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { + zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ + } + for (i = 0; i < zr->jpg_nbufs; i++) { + zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* MJPEG compression mode */ + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPGCmpMode; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPGExpMode; + reg |= ZR36057_JMC_SyncMstr; + /* RJ: The following is experimental - improves the output to screen */ + if (zr->params.VFIFO_FB) + reg |= ZR36057_JMC_VFIFO_FB; + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPGCmpMode; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPGExpMode; + break; + + } + reg |= ZR36057_JMC_JPG; + if (zr->params.field_per_buff == 1) + reg |= ZR36057_JMC_Fld_per_buff; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); + reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); + btwrite(reg, ZR36057_VSP); + reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) + | (zr->params.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); + reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); + btwrite(reg, ZR36057_HSP); + reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) + | (zr->params.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->params.odd_even) + reg = ZR36057_FPP_Odd_Even; + else + reg = 0; + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); + + /* code base address and FIFO threshold */ + reg = virt_to_bus(zr->stat_com); + btwrite(reg, ZR36057_JCBA); + reg = 0x50; + btwrite(reg, ZR36057_JCFT); + + /* JPEG codec guest ID */ + reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); + btwrite(reg, ZR36057_JCGI); + + /* Code transfer guest ID */ + reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); + reg |= ZR36057_MCTCR_CFlush; + btwrite(reg, ZR36057_MCTCR); + + /* deassert P_Reset */ + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); +} + +static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + static int zero = 0; + static int one = 1; + + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); + zr36060_set_cap(zr, mode); + zr36057_set_jpg(zr, mode); + + /* deassert P_Reset, assert Code transfer enable */ + btwrite(IRQ_MASK, ZR36057_ISR); + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(0, ZR36057_ISR); + zr36060_reset(zr); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); + break; + + } + zr->codec_mode = mode; +} + +/* + * Queue a MJPEG buffer for capture/playback + */ + +static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) +{ + unsigned long flags; + int res; + + /* Check if buffers are allocated */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); + return -ENOMEM; + } + /* Does the user want to stop streaming? */ + + if (frame < 0) { + if (zr->codec_mode == mode) { + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + return 0; + } else { + printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); + return -EINVAL; + } + } + /* No grabbing outside the buffer range! */ + + if (frame >= zr->jpg_nbufs) { + printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); + return -EINVAL; + } + /* what is the codec mode right now? */ + + if (zr->codec_mode == BUZ_MODE_IDLE) { + /* Ok load up the zr36060 and go */ + zr36057_enable_jpg(zr, mode); + } else if (zr->codec_mode != mode) { + /* wrong codec mode active - invalid */ + printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); + return -EINVAL; + } + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->jpg_gbuf[frame].state) { + + default: + case BUZ_STATE_DMA: + case BUZ_STATE_PEND: + case BUZ_STATE_DONE: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; + zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; + zoran_feed_stat_com(zr); + res = 0; + break; + + } + + spin_unlock_irqrestore(&zr->lock, flags); + + /* Start the zr36060 when the first frame is queued */ + if (zr->jpg_que_head == 1) { + btor(ZR36057_JMC_Go_en, ZR36057_JMC); + btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); + } + return res; +} + +/* + * Sync on a MJPEG buffer + */ + +static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) +{ + unsigned long flags; + int frame; + + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && + zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + return -EINVAL; + } + while (zr->jpg_que_tail == zr->jpg_dma_tail) { + interruptible_sleep_on(&zr->jpg_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + + frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); + + *bs = zr->jpg_gbuf[frame].bs; + zr->jpg_gbuf[frame].state = BUZ_STATE_USER; + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* when this is called the spinlock must be held */ +static void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int frame, i, max_stat_com; + + max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com + && zr->jpg_dma_head != zr->jpg_que_head) { + + frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; + if (zr->params.TmpDcm == 1) { + /* fill 1 stat_com entry */ + i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + } else { + /* fill 2 stat_com entries */ + i = (zr->jpg_dma_head & 1) * 2; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; + } + zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; + zr->jpg_dma_head++; + + } +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + int frame; + struct zoran_gbuffer *gbuf; + + /* In motion decompress we don't have a hardware frame counter, + we just count the interrupts here */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_seq_num++; + + while (zr->jpg_dma_tail != zr->jpg_dma_head) { + if (zr->params.TmpDcm == 1) + i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; + else + i = (zr->jpg_dma_tail & 1) * 2 + 1; + + stat_com = zr->stat_com[i]; + + if ((stat_com & 1) == 0) { + return; + } + frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; + gbuf = &zr->jpg_gbuf[frame]; + get_fast_time(&gbuf->bs.timestamp); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + gbuf->bs.length = (stat_com & 0x7fffff) >> 1; + + /* update sequence number with the help of the counter in stat_com */ + + seq = stat_com >> 24; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } else { + gbuf->bs.length = 0; + } + gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + gbuf->state = BUZ_STATE_DONE; + + zr->jpg_dma_tail++; + } +} + +static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, astat; + int count; + struct zoran *zr; + unsigned long flags; + + zr = (struct zoran *) dev_id; + count = 0; + + spin_lock_irqsave(&zr->lock, flags); + while (1) { + /* get/clear interrupt status bits */ + stat = btread(ZR36057_ISR); + astat = stat & IRQ_MASK; + if (!astat) { + break; + } + btwrite(astat, ZR36057_ISR); + IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); + +#if (IRQ_MASK & ZR36057_ISR_GIRQ0) + if (astat & ZR36057_ISR_GIRQ0) { + + /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. + We simply ignore them */ + + if (zr->v4l_memgrab_active) { + +/* A lot more checks should be here ... */ + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) + printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); + + if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { + /* There is a grab on a frame going on, check if it has finished */ + + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { + /* it is finished, notify the user */ + + zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq++; + zr->v4l_pend_tail++; + } + } + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) + wake_up_interruptible(&zr->v4l_capq); + + /* Check if there is another grab queued */ + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && + zr->v4l_pend_tail != zr->v4l_pend_head) { + + int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; + u32 reg; + + zr->v4l_grab_frame = frame; + + /* Set zr36057 video front end and enable video */ + + /* Buffer address */ + + reg = zr->v4l_gbuf[frame].fbuffer_bus; + btwrite(reg, ZR36057_VDTR); + if (zr->video_interlace) + reg += zr->gbpl; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + +#ifdef XAWTV_HACK + reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; +#else + reg = 0; +#endif + if (zr->video_interlace) + reg += zr->gbpl; + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; + reg |= ZR36057_VSSFGR_SnapShot; + reg |= ZR36057_VSSFGR_FrameGrab; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } + } + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ + +#if (IRQ_MASK & ZR36057_ISR_GIRQ1) + if (astat & ZR36057_ISR_GIRQ1) { + unsigned csr = zr36060_read_8(zr, 0x001); + unsigned isr = zr36060_read_8(zr, 0x008); + + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", + zr->name, csr, isr)); + + btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + } +#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ + +#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) + if (astat & ZR36057_ISR_CodRepIRQ) { + IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); + btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); + } +#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ + +#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) + if ((astat & ZR36057_ISR_JPEGRepIRQ) && + (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || + zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + } +#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ + + count++; + if (count > 10) { + printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); + if (count > 20) { + btwrite(0, ZR36057_ICR); + printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); + break; + } + } + } + spin_unlock_irqrestore(&zr->lock, flags); +} + +/* Check a zoran_params struct for correctness, insert default params */ + +static int zoran_check_params(struct zoran *zr, struct zoran_params *params) +{ + int err = 0, err0 = 0; + + /* insert constant params */ + + params->major_version = MAJOR_VERSION; + params->minor_version = MINOR_VERSION; + + /* Check input and norm */ + + if (params->input != 0 && params->input != 1) { + err++; + } + if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { + err++; + } + /* Check decimation, set default values for decimation = 1, 2, 4 */ + + switch (params->decimation) { + case 1: + + params->HorDcm = 1; + params->VerDcm = 1; + params->TmpDcm = 1; + params->field_per_buff = 2; + + params->img_x = 0; + params->img_y = 0; + params->img_width = 720; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 2: + + params->HorDcm = 2; + params->VerDcm = 1; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 4: + + params->HorDcm = 4; + params->VerDcm = 2; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = 704; + params->img_height = tvnorms[params->norm].Ha / 2; + break; + + case 0: + + /* We have to check the data the user has set */ + + if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) + err0++; + if (params->VerDcm != 1 && params->VerDcm != 2) + err0++; + if (params->TmpDcm != 1 && params->TmpDcm != 2) + err0++; + if (params->field_per_buff != 1 && params->field_per_buff != 2) + err0++; + + if (params->img_x < 0) + err0++; + if (params->img_y < 0) + err0++; + if (params->img_width < 0) + err0++; + if (params->img_height < 0) + err0++; + if (params->img_x + params->img_width > 720) + err0++; + if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) + err0++; + if (params->img_width % (16 * params->HorDcm) != 0) + err0++; + if (params->img_height % (8 * params->VerDcm) != 0) + err0++; + + if (err0) { + err++; + } + break; + + default: + err++; + break; + } + + if (params->quality > 100) + params->quality = 100; + if (params->quality < 5) + params->quality = 5; + + if (params->APPn < 0) + params->APPn = 0; + if (params->APPn > 15) + params->APPn = 15; + if (params->APP_len < 0) + params->APP_len = 0; + if (params->APP_len > 60) + params->APP_len = 60; + if (params->COM_len < 0) + params->COM_len = 0; + if (params->COM_len > 60) + params->COM_len = 60; + + if (err) + return -EINVAL; + + return 0; + +} +static void zoran_open_init_params(struct zoran *zr) +{ + int i; + + /* Per default, map the V4L Buffers */ + + zr->map_mjpeg_buffers = 0; + + /* User must explicitly set a window */ + + zr->window_set = 0; + + zr->window.x = 0; + zr->window.y = 0; + zr->window.width = 0; + zr->window.height = 0; + zr->window.chromakey = 0; + zr->window.flags = 0; + zr->window.clips = NULL; + zr->window.clipcount = 0; + + zr->video_interlace = 0; + + zr->v4l_memgrab_active = 0; + zr->v4l_overlay_active = 0; + + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq = 0; + + zr->gwidth = 0; + zr->gheight = 0; + zr->gformat = 0; + zr->gbpl = 0; + + /* DMA ring stuff for V4L */ + + zr->v4l_pend_tail = 0; + zr->v4l_pend_head = 0; + for (i = 0; i < v4l_nbufs; i++) { + zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* Set necessary params and call zoran_check_params to set the defaults */ + + zr->params.decimation = 1; + + zr->params.quality = 50; /* default compression factor 8 */ + zr->params.odd_even = 1; + + zr->params.APPn = 0; + zr->params.APP_len = 0; /* No APPn marker */ + for (i = 0; i < 60; i++) + zr->params.APP_data[i] = 0; + + zr->params.COM_len = 0; /* No COM marker */ + for (i = 0; i < 60; i++) + zr->params.COM_data[i] = 0; + + zr->params.VFIFO_FB = 0; + + memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); + + zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; + + i = zoran_check_params(zr, &zr->params); + if (i) + printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); +} + +/* + * Open a buz card. Right now the flags stuff is just playing + */ + +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_open\n")); + + switch (flags) { + + case 0: + if (zr->user) + return -EBUSY; + zr->user++; + + if (v4l_fbuffer_alloc(zr) < 0) { + zr->user--; + return -ENOMEM; + } + /* default setup */ + + zoran_open_init_params(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts + + btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); + + break; + + default: + return -EBUSY; + + } + MOD_INC_USE_COUNT; + return 0; +} + +static void zoran_close(struct video_device *dev) +{ + struct zoran *zr = (struct zoran *) dev; + + DEBUG(printk(KERN_INFO ": zoran_close\n")); + + /* disable interrupts */ + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + + /* wake up sleeping beauties */ + wake_up_interruptible(&zr->v4l_capq); + wake_up_interruptible(&zr->jpg_capq); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + zr36057_set_memgrab(zr, 0); + if (zr->v4l_overlay_active) + zr36057_overlay(zr, 0); + + zr->user--; + + v4l_fbuffer_free(zr); + jpg_fbuffer_free(zr); + zr->jpg_nbufs = 0; + + MOD_DEC_USE_COUNT; + DEBUG(printk(KERN_INFO ": zoran_close done\n")); +} + + +static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +/* + * ioctl routine + */ + + +static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran *zr = (struct zoran *) dev; + + switch (cmd) { + + case VIDIOCGCAP: + { + struct video_capability b; + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); + strncpy(b.name, zr->video_dev.name, sizeof(b.name)); + b.type = VID_TYPE_CAPTURE | + VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + /* theoretically we could also flag VID_TYPE_SUBCAPTURE + but this is not even implemented in the BTTV driver */ + + b.channels = 2; /* composite, svhs */ + b.audios = 0; + b.maxwidth = BUZ_MAX_WIDTH; + b.maxheight = BUZ_MAX_HEIGHT; + b.minwidth = BUZ_MIN_WIDTH; + b.minheight = BUZ_MIN_HEIGHT; + if (copy_to_user(arg, &b, sizeof(b))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); + switch (v.channel) { + case 0: + strcpy(v.name, "Composite"); + break; + case 1: + strcpy(v.name, "SVHS"); + break; + default: + return -EINVAL; + } + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = zr->params.norm; + if (copy_to_user(arg, &v, sizeof(v))) { + return -EFAULT; + } + return 0; + } + + /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: + + * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." + * ^^^^^^^ + * The famos BTTV driver has it implemented with a struct video_channel argument + * and we follow it for compatibility reasons + * + * BTW: this is the only way the user can set the norm! + */ + + case VIDIOCSCHAN: + { + struct video_channel v; + int input; + int on, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); + switch (v.channel) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + if (v.norm != VIDEO_MODE_PAL + && v.norm != VIDEO_MODE_NTSC) { + return -EINVAL; + } + zr->params.norm = v.norm; + zr->params.input = v.channel; + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGTUNER: + case VIDIOCSTUNER: + return -EINVAL; + + case VIDIOCGPICT: + { + struct video_picture p = zr->picture; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); + p.depth = zr->buffer.depth; + switch (zr->buffer.depth) { + case 15: + p.palette = VIDEO_PALETTE_RGB555; + break; + + case 16: + p.palette = VIDEO_PALETTE_RGB565; + break; + + case 24: + p.palette = VIDEO_PALETTE_RGB24; + break; + + case 32: + p.palette = VIDEO_PALETTE_RGB32; + break; + } + + if (copy_to_user(arg, &p, sizeof(p))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) { + return -EFAULT; + } + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", + p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); + /* The depth and palette values have no meaning to us, + should we return -EINVAL if they don't fit ? */ + zr->picture = p; + return 0; + } + + case VIDIOCCAPTURE: + { + int v, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); + /* If there is nothing to do, return immediatly */ + + if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) + return 0; + + if (v == 0) { + zr->v4l_overlay_active = 0; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 0); + /* When a grab is running, the video simply won't be switched on any more */ + } else { + if (!zr->buffer_set || !zr->window_set) { + return -EINVAL; + } + zr->v4l_overlay_active = 1; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 1); + /* When a grab is running, the video will be switched on when grab is finished */ + } + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + return 0; + } + + case VIDIOCGWIN: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); + if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSWIN: + { + struct video_clip *vcp; + struct video_window vw; + int on, end, res; + + if (copy_from_user(&vw, arg, sizeof(vw))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); + if (!zr->buffer_set) { + return -EINVAL; + } + /* + * The video front end needs 4-byte alinged line sizes, we correct that + * silently here if necessary + */ + + if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { + end = (vw.x + vw.width) & ~1; /* round down */ + vw.x = (vw.x + 1) & ~1; /* round up */ + vw.width = end - vw.x; + } + if (zr->buffer.depth == 24) { + end = (vw.x + vw.width) & ~3; /* round down */ + vw.x = (vw.x + 3) & ~3; /* round up */ + vw.width = end - vw.x; + } +#if 0 + // At least xawtv seems to care about the following - just leave it away + /* + * Also corrected silently (as long as window fits at all): + * video not fitting the screen + */ +#if 0 + if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || + vw.y + vw.height > zr->buffer.height) { + printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", + vw.width, vw.height, vw.x, vw.y); + return -EINVAL; + } +#else + if (vw.x < 0) + vw.x = 0; + if (vw.y < 0) + vw.y = 0; + if (vw.x + vw.width > zr->buffer.width) + vw.width = zr->buffer.width - vw.x; + if (vw.y + vw.height > zr->buffer.height) + vw.height = zr->buffer.height - vw.y; +#endif +#endif + + /* Check for vaild parameters */ + if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || + vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { + return -EINVAL; + } +#ifdef XAWTV_HACK + if (vw.width > 720) + vw.width = 720; +#endif + + zr->window.x = vw.x; + zr->window.y = vw.y; + zr->window.width = vw.width; + zr->window.height = vw.height; + zr->window.chromakey = 0; + zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? + + zr->window.clips = NULL; + zr->window.clipcount = vw.clipcount; + + /* + * If an overlay is running, we have to switch it off + * and switch it on again in order to get the new settings in effect. + * + * We also want to avoid that the overlay mask is written + * when an overlay is running. + */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + /* + * Write the overlay mask if clips are wanted. + */ + if (vw.clipcount) { + vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); + if (vcp == NULL) { + return -ENOMEM; + } + if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + write_overlay_mask(zr, vcp, vw.clipcount); + vfree(vcp); + } + if (on) + zr36057_overlay(zr, 1); + zr->window_set = 1; + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + + case VIDIOCGFBUF: + { + IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); + if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCSFBUF: + { + struct video_buffer v; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); + if (zr->v4l_overlay_active) { + /* Has the user gotten crazy ... ? */ + return -EINVAL; + } + if (v.depth != 15 + && v.depth != 16 + && v.depth != 24 + && v.depth != 32) { + return -EINVAL; + } + if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { + return -EINVAL; + } + if (v.bytesperline & 3) { + return -EINVAL; + } + if (v.base) { + zr->buffer.base = (void *) ((unsigned long) v.base & ~3); + } + zr->buffer.height = v.height; + zr->buffer.width = v.width; + zr->buffer.depth = v.depth; + zr->buffer.bytesperline = v.bytesperline; + + if (zr->buffer.base) + zr->buffer_set = 1; + zr->window_set = 0; /* The user should set new window parameters */ + return 0; + } + + /* RJ: what is VIDIOCKEY intended to do ??? */ + + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + + case VIDIOCSYNC: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); + return v4l_sync(zr, v); + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", + vm.frame, vm.height, vm.width, vm.format)); + return v4l_grab(zr, &vm); + } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); + + vm.size = v4l_nbufs * v4l_bufsize; + vm.frames = v4l_nbufs; + for (i = 0; i < v4l_nbufs; i++) { + vm.offsets[i] = i * v4l_bufsize; + } + + /* The next mmap will map the V4L buffers */ + zr->map_mjpeg_buffers = 0; + + if (copy_to_user(arg, &vm, sizeof(vm))) { + return -EFAULT; + } + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + + IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); + vu.video = zr->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user(arg, &vu, sizeof(vu))) + return -EFAULT; + return 0; + } + + /* + * RJ: In principal we could support subcaptures for V4L grabbing. + * Not even the famous BTTV driver has them, however. + * If there should be a strong demand, one could consider + * to implement them. + */ + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + return -EINVAL; + + case BUZIOC_G_PARAMS: + { + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); + if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) + return -EFAULT; + return 0; + } + + case BUZIOC_S_PARAMS: + { + struct zoran_params bp; + int input, on; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bp, arg, sizeof(bp))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); + + /* Check the params first before overwriting our internal values */ + + if (zoran_check_params(zr, &bp)) + return -EINVAL; + + zr->params = bp; + + /* Make changes of input and norm go into effect immediatly */ + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + if (on) + zr36057_overlay(zr, 1); + + if (copy_to_user(arg, &bp, sizeof(bp))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_REQBUFS: + { + struct zoran_requestbuffers br; + + if (zr->jpg_buffers_allocated) { + return -EINVAL; + } + if (copy_from_user(&br, arg, sizeof(br))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", + br.count, br.size)); + /* Enforce reasonable lower and upper limits */ + if (br.count < 4) + br.count = 4; /* Could be choosen smaller */ + if (br.count > BUZ_MAX_FRAME) + br.count = BUZ_MAX_FRAME; + br.size = PAGE_ALIGN(br.size); + if (br.size < 8192) + br.size = 8192; /* Arbitrary */ + /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ + if (br.size > (512 * 1024)) + br.size = (512 * 1024); /* 512 K should be enough */ + if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM) + br.size = MAX_KMALLOC_MEM; + + zr->jpg_nbufs = br.count; + zr->jpg_bufsize = br.size; + + if (jpg_fbuffer_alloc(zr)) + return -ENOMEM; + + /* The next mmap will map the MJPEG buffers */ + zr->map_mjpeg_buffers = 1; + + if (copy_to_user(arg, &br, sizeof(br))) { + return -EFAULT; + } + return 0; + } + + case BUZIOC_QBUF_CAPT: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); + } + + case BUZIOC_QBUF_PLAY: + { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); + } + + case BUZIOC_SYNC: + { + struct zoran_sync bs; + int res; + + IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); + res = jpg_sync(zr, &bs); + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return res; + } + + case BUZIOC_G_STATUS: + { + struct zoran_status bs; + int norm, input, status; + unsigned long timeout; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + return -EINVAL; + } + if (copy_from_user(&bs, arg, sizeof(bs))) { + return -EFAULT; + } + IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); + switch (bs.input) { + case 0: + input = 3; + break; + case 1: + input = 7; + break; + default: + return -EINVAL; + } + + /* Set video norm to VIDEO_MODE_AUTO */ + + norm = VIDEO_MODE_AUTO; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + + /* sleep 1 second */ + + schedule_timeout(HZ); + + /* Get status of video decoder */ + + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); + bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; + bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; + + /* restore previous input and norm */ + input = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return 0; + } + + default: + return -ENOIOCTLCMD; + + } + return 0; +} + + +/* + * This maps the buffers to user space. + * + * Depending on the state of zr->map_mjpeg_buffers + * the V4L or the MJPEG buffers are mapped + * + */ + +static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct zoran *zr = (struct zoran *) dev; + unsigned long start = (unsigned long) adr; + unsigned long page, pos, todo, fraglen; + int i, j; + + if (zr->map_mjpeg_buffers) { + /* Map the MJPEG buffers */ + + if (!zr->jpg_buffers_allocated) { + return -ENOMEM; + } + if (size > zr->jpg_nbufs * zr->jpg_bufsize) { + return -EINVAL; + } + + for (i = 0; i < zr->jpg_nbufs; i++) { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; + todo = size; + if (todo > fraglen) + todo = fraglen; + pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; + page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) + break; /* was last fragment */ + } + if (size == 0) + break; + } + } else { + /* Map the V4L buffers */ + + if (size > v4l_nbufs * v4l_bufsize) { + return -EINVAL; + } + + for (i = 0; i < v4l_nbufs; i++) { + todo = size; + if (todo > v4l_bufsize) + todo = v4l_bufsize; + page = zr->v4l_gbuf[i].fbuffer_phys; + DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); + if (remap_page_range(start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + } + } + return 0; +} + +static int zoran_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device zoran_template = +{ + BUZ_NAME, + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | + VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + VID_HARDWARE_BT848, /* Not true, but the buz is not yet in the list */ + zoran_open, + zoran_close, + zoran_read, + zoran_write, + NULL, + zoran_ioctl, + zoran_mmap, + zoran_init_done, + NULL, + 0, + 0 +}; + +static int zr36057_init(int i) +{ + struct zoran *zr = &zoran[i]; + unsigned long mem; + unsigned mem_needed; + int j; + int rev; + + /* reset zr36057 */ + btwrite(0, ZR36057_SPGPPCR); + mdelay(10); + + /* default setup of all parameters which will persist beetween opens */ + + zr->user = 0; + + zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ + + zr->jpg_nbufs = 0; + zr->jpg_bufsize = 0; + zr->jpg_buffers_allocated = 0; + + zr->buffer_set = 0; /* Flag if frame buffer has been set */ + zr->buffer.base = (void *) vidmem; + zr->buffer.width = 0; + zr->buffer.height = 0; + zr->buffer.depth = 0; + zr->buffer.bytesperline = 0; + + zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ + zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ + zr->video_interlace = 0; + + /* Should the following be reset at every open ? */ + + zr->picture.colour = 32768; + zr->picture.brightness = 32768; + zr->picture.hue = 32768; + zr->picture.contrast = 32768; + zr->picture.whiteness = 0; + zr->picture.depth = 0; + zr->picture.palette = 0; + + for (j = 0; j < VIDEO_MAX_FRAME; j++) { + zr->v4l_gbuf[i].fbuffer = 0; + zr->v4l_gbuf[i].fbuffer_phys = 0; + zr->v4l_gbuf[i].fbuffer_bus = 0; + } + + zr->stat_com = 0; + + /* default setup (will be repeated at every open) */ + + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + + /* STAT_COM table and overlay mask */ + + mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; + mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); + if (!mem) { + return -ENOMEM; + } + memset((void *) mem, 0, mem_needed); + + zr->stat_com = (u32 *) mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } + zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); + + /* Initialize zr->jpg_gbuf */ + + for (j = 0; j < BUZ_MAX_FRAME; j++) { + zr->jpg_gbuf[j].frag_tab = 0; + zr->jpg_gbuf[j].frag_tab_bus = 0; + zr->jpg_gbuf[j].state = BUZ_STATE_USER; + zr->jpg_gbuf[j].bs.frame = j; + } + + /* take zr36057 out of reset now */ + btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); + mdelay(10); + + /* stop all DMA processes */ + btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + switch(zr->board) + { + case BOARD_BUZ: + + /* set up GPIO direction */ + btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); + + /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ + btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); + mdelay(10); + + /* reset video decoder */ + + GPIO(zr, 0, 0); + mdelay(10); + GPIO(zr, 0, 1); + mdelay(10); + + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + mdelay(10); + zr36060_reset(zr); + mdelay(10); + zr36060_sleep(zr, 1); + mdelay(10); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); + kfree((void *) zr->stat_com); + return -1; + } + break; + + case BOARD_LML33: +// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(100); +// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); +// udelay(1000); + + /* + * Set up the GPIO direction + */ + btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); + /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ + btwrite(0xFF00F888, ZR36057_GPPGCR1); + mdelay(10); + GPIO(zr, 5, 0); /* Analog video bypass */ + udelay(3000); + GPIO(zr, 0, 0); /* Reset 819 */ + udelay(3000); + GPIO(zr, 0, 1); /* 819 back */ + udelay(3000); + /* reset JPEG codec */ + zr36060_sleep(zr, 0); + udelay(3000); + zr36060_reset(zr); + udelay(3000); + zr36060_sleep(zr, 1); + udelay(3000); + + /* display codec revision */ + if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); +// kfree((void *) zr->stat_com); +// return -1; + } + break; + } + /* i2c */ + memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); + sprintf(zr->i2c.name, "zoran%u%u", zr->id); + zr->i2c.data = zr; + if (i2c_register_bus(&zr->i2c) < 0) { + kfree((void *) zr->stat_com); + return -1; + } + /* + * Now add the template and register the device unit. + */ + memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); + sprintf(zr->video_dev.name, "zoran%u", zr->id); + if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + /* toggle JPEG codec sleep to sync PLL */ + zr36060_sleep(zr, 1); + mdelay(10); + zr36060_sleep(zr, 0); + mdelay(10); + + /* Enable bus-mastering */ + pci_set_master(zr->pci_dev); + + j = zr->params.input == 0 ? 3 : 7; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + + /* set individual interrupt enables (without GIRQ0) + but don't global enable until zoran_open() */ + + btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); + + if(request_irq(zr->pci_dev->irq, zoran_irq, + SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) + { + printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); + video_unregister_device(&zr->video_dev); + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + zr->initialized = 1; + return 0; +} + + + +static void release_zoran(void) +{ + u8 command; + int i; + struct zoran *zr; + + for (i = 0; i < zoran_num; i++) { + zr = &zoran[i]; + + if (!zr->initialized) + continue; + + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); + + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + + free_irq(zr->pci_dev->irq, zr); + + /* unmap and free memory */ + + kfree((void *) zr->stat_com); + + iounmap(zr->zr36057_mem); + + video_unregister_device(&zr->video_dev); + } +} + +/* + * Scan for a Buz card (actually for the PCI controller ZR36057), + * request the irq and map the io memory + */ + +static int find_zr36057(void) +{ + unsigned char latency; + struct zoran *zr; + struct pci_dev *dev = NULL; + int result; + + zoran_num = 0; + + while (zoran_num < BUZ_MAX + && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { + zr = &zoran[zoran_num]; + zr->pci_dev = dev; + zr->zr36057_mem = NULL; + zr->id = zoran_num; + sprintf(zr->name, "zoran%u", zr->id); + + spin_lock_init(&zr->lock); + + zr->zr36057_adr = zr->pci_dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); + if (zr->revision < 2) { + printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + } else { + unsigned short ss_vendor_id, ss_id; + + pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor_id); + pci_read_config_word(zr->pci_dev, PCI_SUBSYSTEM_ID, &ss_id); + printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); + printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", + zr->name, ss_vendor_id, ss_id); + if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) + { + zr->board = BOARD_LML33; + printk(KERN_INFO "%s: LML33 detected.\n", zr->name); + } + } + + zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); + if (latency != 48) { + printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); + latency = 48; + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); + } + zoran_num++; + } + if (zoran_num == 0) + printk(KERN_INFO "zoran: no cards found.\n"); + + return zoran_num; +} + +#include "chipsets.h" + +static void handle_chipset(void) +{ + int index; + struct pci_dev *dev = NULL; + + for (index = 0; index < sizeof(black) / sizeof(black[0]); index++) { + if ((dev = pci_find_device(black[index].vendor, black[index].device, dev)) != NULL) { + printk(KERN_INFO ": Host bridge: %s, ", black[index].name); + switch (black[index].action) { + + case TRITON: + printk("enabling Triton support.\n"); + triton = 1; + break; + + case NATOMA: + printk("enabling Natoma workaround.\n"); + natoma = 1; + break; + } + } + } +} + +#ifdef MODULE +int init_module(void) +#else +int init_zoran_cards(struct video_init *unused) +#endif +{ + int i; + + + printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); + + /* Look for Buz cards */ + + if (find_zr36057() <= 0) { + return -EIO; + } + printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); + + if (zoran_num == 0) + return -ENXIO; + + + /* check the parameters we have been given, adjust if necessary */ + + if (v4l_nbufs < 0) + v4l_nbufs = 0; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specfies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + + printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); + + /* Use parameter for vidmem or try to find a video card */ + + if (vidmem) { + printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); + } + + /* check if we have a Triton or Natome chipset */ + + handle_chipset(); + + /* take care of Natoma chipset and a revision 1 zr36057 */ + + for (i = 0; i < zoran_num; i++) { + if (natoma && zoran[i].revision <= 1) { + zoran[i].need_contiguous = 1; + printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); + } else { + zoran[i].need_contiguous = 0; + } + } + + /* initialize the Buzs */ + + /* We have to know which ones must be released if an error occurs */ + for (i = 0; i < zoran_num; i++) + zoran[i].initialized = 0; + + for (i = 0; i < zoran_num; i++) { + if (zr36057_init(i) < 0) { + release_zoran(); + return -EIO; + } + } + + return 0; +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + release_zoran(); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/buz.h linux.ac/drivers/char/buz.h --- linux.vanilla/drivers/char/buz.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/buz.h Thu Jul 1 23:20:12 1999 @@ -0,0 +1,319 @@ +/* + buz - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni + + based on + + buz.0.0.3 Copyright (C) 1998 Dave Perks + + and + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +#define XAWTV_HACK + +#ifdef XAWTV_HACK +#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#else +#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +#endif +#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* + Private IOCTL to set up for displaying MJPEG + */ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +#define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +#define V4L_MAX_FRAME 64 +#else +#error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + int board; /* Board type */ +#define BOARD_BUZ 0 +#define BOARD_LML33 1 + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + + struct wait_queue *v4l_capq; /* wait here for grab to finish */ + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + struct wait_queue *jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile. */ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7185 0x88 + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/bw-qcam.c linux.ac/drivers/char/bw-qcam.c --- linux.vanilla/drivers/char/bw-qcam.c Mon Mar 29 10:25:55 1999 +++ linux.ac/drivers/char/bw-qcam.c Mon Jul 5 04:39:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/c-qcam.c linux.ac/drivers/char/c-qcam.c --- linux.vanilla/drivers/char/c-qcam.c Tue Dec 22 23:19:37 1998 +++ linux.ac/drivers/char/c-qcam.c Mon Jul 5 04:38:51 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/chipsets.h linux.ac/drivers/char/chipsets.h --- linux.vanilla/drivers/char/chipsets.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/chipsets.h Thu Jul 1 19:05:50 1999 @@ -0,0 +1,41 @@ +static const struct { + unsigned short vendor; + unsigned short device; + enum { + TRITON, + NATOMA + } action; + const char *name; +} black[] = { + + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, TRITON, "82437" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX, TRITON, "82437VX Triton II" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439, TRITON, "82439HX Triton II" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, TRITON, "82439TX" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, NATOMA, "82441FX Natoma" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_0, NATOMA, "440LX - 82443LX PAC Host" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443LX_1, NATOMA, "440LX - 82443LX PAC AGP" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0, NATOMA, "440BX - 82443BX Host" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_1, NATOMA, "440BX - 82443BX AGP" + }, + { + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, NATOMA, "440BX - 82443BX Host (no AGP)" + }, +}; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/cyclades.c linux.ac/drivers/char/cyclades.c --- linux.vanilla/drivers/char/cyclades.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/cyclades.c Wed Jun 30 00:15:32 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dmaram.c linux.ac/drivers/char/dmaram.c --- linux.vanilla/drivers/char/dmaram.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/dmaram.c Mon Jul 19 03:45:43 1999 @@ -0,0 +1,235 @@ +/* + * A simple DMA memory driver for the Linux kernel. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define MAX_DMARAM 32 + +#define DMA_MAJOR 125 + + +struct dmaram +{ + int buffsize; + void *raw_buf; + unsigned long raw_buf_phys; +}; + +struct dmaram *dma_dev[MAX_DMARAM]; + +static int dmaram_create(struct dmaram *dp) +{ + char *start_addr, *end_addr; + int size, sz, i; + if(dp->buffsize < PAGE_SIZE) + dp->buffsize = PAGE_SIZE; + dp->raw_buf = NULL; + start_addr = NULL; + + while (start_addr == NULL && dp->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + { + dp->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_KERNEL, sz); + if (start_addr == NULL) + dp->buffsize /= 2; + } + } + if (start_addr == NULL) { + return -ENOMEM; + } else { + /* make some checks */ + end_addr = start_addr + dp->buffsize - 1; + } + dp->raw_buf = start_addr; + dp->raw_buf_phys = virt_to_bus(start_addr); + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags);; + return 0; +} + +static void dmaram_destroy(struct dmaram *dp) +{ + int sz, size, i; + unsigned long start_addr, end_addr; + + if (dp->raw_buf == NULL) + return; + for (sz = 0, size = PAGE_SIZE; size < dp->buffsize; sz++, size <<= 1); + + start_addr = (unsigned long) dp->raw_buf; + end_addr = start_addr + dp->buffsize; + + for (i = MAP_NR(start_addr); i < MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; + + free_pages((unsigned long) dp->raw_buf, sz); + dp->raw_buf = NULL; +} + + +static int dma_open(struct inode *inode, struct file *file) +{ + void *ram; + int minor = MINOR(inode->i_rdev); + if(minor >= MAX_DMARAM) + return -ENXIO; + + /* + * The allocate may sleep - avoid races + */ + + ram = (struct dmaram *)kmalloc(sizeof(struct dmaram), GFP_KERNEL); + if(ram==NULL) + return -ENOMEM; + + if(dma_dev[minor] != NULL) + { + kfree(ram); + return -EBUSY; + } + + dma_dev[minor]=ram; + MOD_INC_USE_COUNT; + memset(dma_dev[minor], 0, sizeof(struct dmaram)); + return 0; +} + + +static int dma_release(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct dmaram *dp = dma_dev[minor]; + if(dp->raw_buf) + dmaram_destroy(dp); + kfree(dma_dev[minor]); + dma_dev[minor]=NULL; + MOD_DEC_USE_COUNT; + return 0; +} + +static long long dma_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct dmaram *dp = dma_dev[MINOR(inode->i_rdev)]; + switch(cmd) + { + case DMAIOCSET: + { + long size; + if(dp->raw_buf) + return -EBUSY; + if(get_user(size, (long *)arg)) + return -EFAULT; + if(size < PAGE_SIZE || size%PAGE_SIZE) + return -EINVAL; + if(size > 32 * PAGE_SIZE) + size = 32 *PAGE_SIZE; + + dp->buffsize = size; + + return dmaram_create(dp); + } + + case DMAIOCGET: + { + struct dma_info dmi; + dmi.size = dp->buffsize; + dmi.phys = dp->raw_buf_phys; + if(copy_to_user((void *)arg, &dmi, sizeof(dmi))) + return -EFAULT; + return 0; + } + } + return -ENOTTY; +} + + +static int dma_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dmaram *dp = dma_dev[MINOR(file->f_dentry->d_inode->i_rdev)]; + int size; + + if(dp->raw_buf == NULL) + return -EIO; + size = vma->vm_end - vma->vm_start; + if(size != dp->buffsize) + return -EINVAL; + if(remap_page_range(vma->vm_start, dp->raw_buf_phys, + size, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +static ssize_t dma_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t dma_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static struct file_operations dma_fops= +{ + dma_lseek, + dma_read, + dma_write, + NULL, /* readdir */ + NULL, + dma_ioctl, + dma_mmap, + dma_open, + NULL, /* flush */ + dma_release +}; + +/* + * Initialise DMAram for Linux + */ + +int dmaram_init(void) +{ + printk(KERN_INFO "Linux DMA memory interface v0.02 (c) 1999 Red Hat Software\n"); + if(register_chrdev(DMA_MAJOR,"dmaram", &dma_fops)) + { + printk("dma_dev: unable to get major %d\n", DMA_MAJOR); + return -EIO; + } + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return dmaram_init(); +} + +void cleanup_module(void) +{ + unregister_chrdev(DMA_MAJOR, "dmaram"); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dz.c linux.ac/drivers/char/dz.c --- linux.vanilla/drivers/char/dz.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/dz.c Mon Jul 19 19:48:18 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 + */ + +#define DEBUG_DZ 1 + +#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 +#include +/* for definition of SERIAL */ +#include + +/* for definition of struct console */ +#ifdef CONFIG_SERIAL_CONSOLE +#define CONSOLE_LINE (3) +#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) +#include +#endif /* if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_DZ) */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef DEBUG_DZ +#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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/dz.h linux.ac/drivers/char/dz.h --- linux.vanilla/drivers/char/dz.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/dz.h Tue Jun 22 01:41:18 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/esp.c linux.ac/drivers/char/esp.c --- linux.vanilla/drivers/char/esp.c Sun Nov 8 15:10:12 1998 +++ linux.ac/drivers/char/esp.c Fri Jun 4 23:52:41 1999 @@ -2186,7 +2186,7 @@ if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_before(orig_jiffies + timeout, jiffies)) break; serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/hfmodem/main.c linux.ac/drivers/char/hfmodem/main.c --- linux.vanilla/drivers/char/hfmodem/main.c Tue Jan 19 02:57:26 1999 +++ linux.ac/drivers/char/hfmodem/main.c Mon Jul 19 19:48:18 1999 @@ -62,7 +62,6 @@ #if LINUX_VERSION_CODE >= 0x20100 #include #else -#include #include #undef put_user diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/i2c.c linux.ac/drivers/char/i2c.c --- linux.vanilla/drivers/char/i2c.c Tue Jan 19 02:57:26 1999 +++ linux.ac/drivers/char/i2c.c Thu Jul 1 19:12:16 1999 @@ -40,6 +40,14 @@ extern int i2c_tuner_init(void); extern int msp3400c_init(void); #endif +#ifdef CONFIG_VIDEO_BUZ +extern int saa7111_init(void); +extern int saa7185_init(void); +#endif +#ifdef CONFIG_VIDEO_LML33 +extern int bt819_init(void); +extern int bt856_init(void); +#endif int i2c_init(void) { @@ -50,6 +58,14 @@ i2c_tuner_init(); msp3400c_init(); #endif +#ifdef CONFIG_VIDEO_BUZ + saa7111_init(); + saa7185_init(); +#endif +#ifdef CONFIG_VIDEO_LML33 + bt819_init(); + bt856_init(); +#endif return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/isicom.c linux.ac/drivers/char/isicom.c --- linux.vanilla/drivers/char/isicom.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/isicom.c Thu Jul 8 01:47:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/keyboard.c linux.ac/drivers/char/keyboard.c --- linux.vanilla/drivers/char/keyboard.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/keyboard.c Mon Jul 19 19:48:18 1999 @@ -155,6 +155,7 @@ #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; +int sysrq_enabled = 1; #endif /* @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/lp_intern.c linux.ac/drivers/char/lp_intern.c --- linux.vanilla/drivers/char/lp_intern.c Sun Nov 8 15:07:43 1998 +++ linux.ac/drivers/char/lp_intern.c Mon Jul 19 19:48:18 1999 @@ -28,7 +28,6 @@ #endif #ifdef CONFIG_ATARI #include -#include #include #include #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/mem.c linux.ac/drivers/char/mem.c --- linux.vanilla/drivers/char/mem.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/char/mem.c Sun Jun 6 01:42:54 1999 @@ -250,11 +250,14 @@ count -= read; } - virtr = vread(buf, (char *)p, count); - if (virtr < 0) - return virtr; - *ppos += p + virtr; - return virtr + read; + if(count) { + if((virtr = vread(buf, (char *)p, count)) < 0) + return virtr; + read += virtr; + } + + *ppos += read; + return read; } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/misc.c linux.ac/drivers/char/misc.c --- linux.vanilla/drivers/char/misc.c Mon Mar 29 10:25:55 1999 +++ linux.ac/drivers/char/misc.c Tue Jun 22 01:41:18 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/n_hdlc.c linux.ac/drivers/char/n_hdlc.c --- linux.vanilla/drivers/char/n_hdlc.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/n_hdlc.c Mon Jul 19 19:48:18 1999 @@ -100,7 +100,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.c linux.ac/drivers/char/pc_keyb.c --- linux.vanilla/drivers/char/pc_keyb.c Wed Apr 28 19:14:26 1999 +++ linux.ac/drivers/char/pc_keyb.c Tue Jun 29 02:27:52 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc_keyb.h linux.ac/drivers/char/pc_keyb.h --- linux.vanilla/drivers/char/pc_keyb.h Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/char/pc_keyb.h Thu Jan 1 01:00:00 1970 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/qpmouse.c linux.ac/drivers/char/qpmouse.c --- linux.vanilla/drivers/char/qpmouse.c Sun Nov 8 15:10:12 1998 +++ linux.ac/drivers/char/qpmouse.c Tue Jun 29 02:26:47 1999 @@ -42,7 +42,7 @@ #include #include -#include "pc_keyb.h" /* mouse enable command.. */ +#include /* mouse enable command.. */ /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/radio-cadet.c linux.ac/drivers/char/radio-cadet.c --- linux.vanilla/drivers/char/radio-cadet.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/radio-cadet.c Mon Jun 21 13:12:14 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;i #endif -#include #else /* !NEW_MODULES */ #ifdef MODVERSIONS #define MODULE #endif -#include #endif /* NEW_MODULES */ +#include #include #include #include @@ -154,7 +153,6 @@ /* * NB. we must include the kernel idenfication string in to install the module. */ -#include /*static*/ char kernel_version[] = UTS_RELEASE; #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/saa7111.c linux.ac/drivers/char/saa7111.c --- linux.vanilla/drivers/char/saa7111.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/saa7111.c Thu Jul 1 19:18:01 1999 @@ -0,0 +1,421 @@ +/* + saa7111 - Philips SAA7111A video decoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7111 { + struct i2c_bus *bus; + int addr; + unsigned char reg[32]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7111 0x48 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) +{ + int ack; + unsigned subaddr; + unsigned long flags; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) +{ + int data; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr | 1, I2C_DELAY); + data = i2c_readbyte(dev->bus, 1); + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ + +static int saa7111_attach(struct i2c_device *device) +{ + int i; + struct saa7111 *decoder; + + static const unsigned char init[] = + { + 0x00, 0x00, /* 00 - ID byte */ + 0x01, 0x00, /* 01 - reserved */ + + /*front end */ + 0x02, 0xd0, /* 02 - FUSE=3, GUDL=2, MODE=0 */ + 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */ + 0x04, 0x00, /* 04 - GAI1=256 */ + 0x05, 0x00, /* 05 - GAI2=256 */ + + /* decoder */ + 0x06, 0xf6, /* 06 - HSB at 13(50Hz) / 17(60Hz) pixels after end of last line */ + 0x07, 0xdd, /* 07 - HSS at 113(50Hz) / 117(60Hz) pixels after end of last line */ + 0x08, 0xc8, /* 08 - AUFD=1, FSEL=1, EXFIL=0, VTRC=1, HPLL=0, VNOI=0 */ + 0x09, 0x01, /* 09 - BYPS=0, PREF=0, BPSS=0, VBLB=0, UPTCV=0, APER=1 */ + 0x0a, 0x80, /* 0a - BRIG=128 */ + 0x0b, 0x47, /* 0b - CONT=1.109 */ + 0x0c, 0x40, /* 0c - SATN=1.0 */ + 0x0d, 0x00, /* 0d - HUE=0 */ + 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ + 0x0f, 0x00, /* 0f - reserved */ + 0x10, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ + 0x11, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ + 0x12, 0x00, /* 12 - output control 2 */ + 0x13, 0x00, /* 13 - output control 3 */ + 0x14, 0x00, /* 14 - reserved */ + 0x15, 0x00, /* 15 - VBI */ + 0x16, 0x00, /* 16 - VBI */ + 0x17, 0x00, /* 17 - VBI */ + }; + + device->data = decoder = kmalloc(sizeof(struct saa7111), GFP_KERNEL); + if (decoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(decoder, 0, sizeof(struct saa7111)); + strcpy(device->name, "saa7111"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_NTSC; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + i = saa7111_write_block(decoder, init, sizeof(init)); + if (i < 0) { + printk(KERN_ERR "%s_attach: init status %d\n", device->name, i); + } else { + printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7111_read(decoder, 0x00)); + } + return 0; +} + + +static int saa7111_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7111_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7111 *decoder = device->data; + + switch (cmd) { + +#if defined(DECODER_DUMP) + case DECODER_DUMP: + { + int i; + + for (i = 0; i < 32; i += 16) { + int j; + + printk("KERN_DEBUG %s: %03x", device->name, i); + for (j = 0; j < 16; ++j) { + printk(" %02x", saa7111_read(decoder, i + j)); + } + printk("\n"); + } + } + break; +#endif /* defined(DECODER_DUMP) */ + + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *cap = arg; + + cap->flags + = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + cap->inputs = 8; + cap->outputs = 1; + } + break; + + case DECODER_GET_STATUS: + { + int *iarg = arg; + int status; + int res; + + status = saa7111_read(decoder, 0x1f); + res = 0; + if ((status & (1 << 6)) == 0) { + res |= DECODER_STATUS_GOOD; + } + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + default: + case VIDEO_MODE_AUTO: + if ((status & (1 << 5)) != 0) { + res |= DECODER_STATUS_NTSC; + } else { + res |= DECODER_STATUS_PAL; + } + break; + } + if ((status & (1 << 0)) != 0) { + res |= DECODER_STATUS_COLOR; + } + *iarg = res; + } + break; + + case DECODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40); + break; + + case VIDEO_MODE_PAL: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00); + break; + + case VIDEO_MODE_AUTO: + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80); + break; + + default: + return -EINVAL; + + } + decoder->norm = *iarg; + } + break; + + case DECODER_SET_INPUT: + { + int *iarg = arg; + + if (*iarg < 0 || *iarg > 7) { + return -EINVAL; + } + if (decoder->input != *iarg) { + decoder->input = *iarg; + /* select mode */ + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + /* bypass chrominance trap for modes 4..7 */ + saa7111_write(decoder, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0)); + } + } + break; + + case DECODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case DECODER_ENABLE_OUTPUT: + { + int *iarg = arg; + int enable = (*iarg != 0); + + if (decoder->enable != enable) { + decoder->enable = enable; + +// RJ: If output should be disabled (for playing videos), we also need a open PLL. + // The input is set to 0 (where no input source is connected), although this + // is not necessary. + // + // If output should be enabled, we have to reverse the above. + + if (decoder->enable) { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb)); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c); + } else { + saa7111_write(decoder, 0x02, (decoder->reg[0x02] & 0xf8)); + saa7111_write(decoder, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04); + saa7111_write(decoder, 0x11, (decoder->reg[0x11] & 0xf3)); + } + } + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7111_write(decoder, 0x0a, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7111_write(decoder, 0x0b, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7111_write(decoder, 0x0c, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7111_write(decoder, 0x0d, (decoder->hue - 32768) >> 8); + } + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7111 = +{ + "saa7111", /* name */ + I2C_DRIVERID_VIDEODECODER, /* ID */ + I2C_SAA7111, I2C_SAA7111 + 1, + + saa7111_attach, + saa7111_detach, + saa7111_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7111_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7111); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7111); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/saa7185.c linux.ac/drivers/char/saa7185.c --- linux.vanilla/drivers/char/saa7185.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/saa7185.c Thu Jul 1 19:18:14 1999 @@ -0,0 +1,379 @@ +/* + saa7185 - Philips SAA7185B video encoder driver version 0.0.3 + + Copyright (C) 1998 Dave Perks + + 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define DEBUG(x) x /* Debug driver */ + +/* ----------------------------------------------------------------------- */ + +struct saa7185 { + struct i2c_bus *bus; + int addr; + unsigned char reg[128]; + + int norm; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +#define I2C_SAA7185 0x88 + +#define I2C_DELAY 10 + +/* ----------------------------------------------------------------------- */ + +static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) +{ + int ack; + unsigned long flags; + + LOCK_I2C_BUS(dev->bus); + + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + i2c_sendbyte(dev->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, data, I2C_DELAY); + dev->reg[subaddr] = data; + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + return ack; +} + +static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) +{ + int ack; + unsigned subaddr; + unsigned long flags; + + while (len > 1) { + LOCK_I2C_BUS(dev->bus); + i2c_start(dev->bus); + i2c_sendbyte(dev->bus, dev->addr, I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (subaddr = *data++), I2C_DELAY); + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + while (len > 1 && *data == ++subaddr) { + data++; + ack = i2c_sendbyte(dev->bus, (dev->reg[subaddr] = *data++), I2C_DELAY); + len -= 2; + } + i2c_stop(dev->bus); + UNLOCK_I2C_BUS(dev->bus); + } + return ack; +} + +/* ----------------------------------------------------------------------- */ + +static const unsigned char init_common[] = +{ + 0x3a, 0x0f, /* CBENB=0, V656=0, VY2C=1, YUV2C=1, MY2C=1, MUV2C=1 */ + + 0x42, 0x6b, /* OVLY0=107 */ + 0x43, 0x00, /* OVLU0=0 white */ + 0x44, 0x00, /* OVLV0=0 */ + 0x45, 0x22, /* OVLY1=34 */ + 0x46, 0xac, /* OVLU1=172 yellow */ + 0x47, 0x0e, /* OVLV1=14 */ + 0x48, 0x03, /* OVLY2=3 */ + 0x49, 0x1d, /* OVLU2=29 cyan */ + 0x4a, 0xac, /* OVLV2=172 */ + 0x4b, 0xf0, /* OVLY3=240 */ + 0x4c, 0xc8, /* OVLU3=200 green */ + 0x4d, 0xb9, /* OVLV3=185 */ + 0x4e, 0xd4, /* OVLY4=212 */ + 0x4f, 0x38, /* OVLU4=56 magenta */ + 0x50, 0x47, /* OVLV4=71 */ + 0x51, 0xc1, /* OVLY5=193 */ + 0x52, 0xe3, /* OVLU5=227 red */ + 0x53, 0x54, /* OVLV5=84 */ + 0x54, 0xa3, /* OVLY6=163 */ + 0x55, 0x54, /* OVLU6=84 blue */ + 0x56, 0xf2, /* OVLV6=242 */ + 0x57, 0x90, /* OVLY7=144 */ + 0x58, 0x00, /* OVLU7=0 black */ + 0x59, 0x00, /* OVLV7=0 */ + + 0x5a, 0x00, /* CHPS=0 */ + 0x5b, 0x76, /* GAINU=118 */ + 0x5c, 0xa5, /* GAINV=165 */ + 0x5d, 0x3c, /* BLCKL=60 */ + 0x5e, 0x3a, /* BLNNL=58 */ + 0x5f, 0x3a, /* CCRS=0, BLNVB=58 */ + 0x60, 0x00, /* NULL */ + +/* 0x61 - 0x66 set according to norm */ + + 0x67, 0x00, /* 0 : caption 1st byte odd field */ + 0x68, 0x00, /* 0 : caption 2nd byte odd field */ + 0x69, 0x00, /* 0 : caption 1st byte even field */ + 0x6a, 0x00, /* 0 : caption 2nd byte even field */ + + 0x6b, 0x91, /* MODIN=2, PCREF=0, SCCLN=17 */ + 0x6c, 0x20, /* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0, CBLF=0, ORCV2=0, PRCV2=0 */ + 0x6d, 0x00, /* SRCM1=0, CCEN=0 */ + + 0x6e, 0x0e, /* HTRIG=0x00e, approx. centered, at least for PAL */ + 0x6f, 0x00, /* HTRIG upper bits */ + 0x70, 0x20, /* PHRES=0, SBLN=1, VTRIG=0 */ + +/* The following should not be needed */ + + 0x71, 0x15, /* BMRQ=0x115 */ + 0x72, 0x90, /* EMRQ=0x690 */ + 0x73, 0x61, /* EMRQ=0x690, BMRQ=0x115 */ + 0x74, 0x00, /* NULL */ + 0x75, 0x00, /* NULL */ + 0x76, 0x00, /* NULL */ + 0x77, 0x15, /* BRCV=0x115 */ + 0x78, 0x90, /* ERCV=0x690 */ + 0x79, 0x61, /* ERCV=0x690, BRCV=0x115 */ + +/* Field length controls */ + + 0x7a, 0x70, /* FLC=0 */ + +/* The following should not be needed if SBLN = 1 */ + + 0x7b, 0x16, /* FAL=22 */ + 0x7c, 0x35, /* LAL=244 */ + 0x7d, 0x20, /* LAL=244, FAL=22 */ +}; + +static const unsigned char init_pal[] = +{ + 0x61, 0x1e, /* FISE=0, PAL=1, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xc8, /* DECTYP=1, BSTA=72 */ + 0x63, 0xcb, /* FSC0 */ + 0x64, 0x8a, /* FSC1 */ + 0x65, 0x09, /* FSC2 */ + 0x66, 0x2a, /* FSC3 */ +}; + +static const unsigned char init_ntsc[] = +{ + 0x61, 0x1d, /* FISE=1, PAL=0, SCBW=1, RTCE=1, YGS=1, INPI=0, DOWN=0 */ + 0x62, 0xe6, /* DECTYP=1, BSTA=102 */ + 0x63, 0x1f, /* FSC0 */ + 0x64, 0x7c, /* FSC1 */ + 0x65, 0xf0, /* FSC2 */ + 0x66, 0x21, /* FSC3 */ +}; + +static int saa7185_attach(struct i2c_device *device) +{ + int i; + struct saa7185 *encoder; + + device->data = encoder = kmalloc(sizeof(struct saa7185), GFP_KERNEL); + if (encoder == NULL) { + return -ENOMEM; + } + MOD_INC_USE_COUNT; + + memset(encoder, 0, sizeof(struct saa7185)); + strcpy(device->name, "saa7185"); + encoder->bus = device->bus; + encoder->addr = device->addr; + encoder->norm = VIDEO_MODE_NTSC; + encoder->enable = 1; + + i = saa7185_write_block(encoder, init_common, sizeof(init_common)); + if (i >= 0) { + i = saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + } + if (i < 0) { + printk(KERN_ERR "%s_attach: init error %d\n", device->name, i); + } + return 0; +} + + +static int saa7185_detach(struct i2c_device *device) +{ + kfree(device->data); + MOD_DEC_USE_COUNT; + return 0; +} + +static int saa7185_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7185 *encoder = device->data; + + switch (cmd) { + + case ENCODER_GET_CAPABILITIES: + { + struct video_encoder_capability *cap = arg; + + cap->flags + = VIDEO_ENCODER_PAL + | VIDEO_ENCODER_NTSC + | VIDEO_ENCODER_SECAM + | VIDEO_ENCODER_CCIR; + cap->inputs = 1; + cap->outputs = 1; + } + break; + + case ENCODER_SET_NORM: + { + int *iarg = arg; + + switch (*iarg) { + + case VIDEO_MODE_NTSC: + saa7185_write_block(encoder, init_ntsc, sizeof(init_ntsc)); + break; + + case VIDEO_MODE_PAL: + saa7185_write_block(encoder, init_pal, sizeof(init_pal)); + break; + + case VIDEO_MODE_SECAM: + default: + return -EINVAL; + + } + encoder->norm = *iarg; + } + break; + + case ENCODER_SET_INPUT: + { + int *iarg = arg; + +#if 0 + /* not much choice of inputs */ + if (*iarg != 0) { + return -EINVAL; + } +#else + /* RJ: *iarg = 0: input is from SA7111 + *iarg = 1: input is from ZR36060 */ + + switch (*iarg) { + + case 0: + /* Switch RTCE to 1 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); + break; + + case 1: + /* Switch RTCE to 0 */ + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); + break; + + default: + return -EINVAL; + + } +#endif + } + break; + + case ENCODER_SET_OUTPUT: + { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) { + return -EINVAL; + } + } + break; + + case ENCODER_ENABLE_OUTPUT: + { + int *iarg = arg; + + encoder->enable = !!*iarg; + saa7185_write(encoder, 0x61, (encoder->reg[0x61] & 0xbf) | (encoder->enable ? 0x00 : 0x40)); + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7185 = +{ + "saa7185", /* name */ + I2C_DRIVERID_VIDEOENCODER, /* ID */ + I2C_SAA7185, I2C_SAA7185 + 1, + + saa7185_attach, + saa7185_detach, + saa7185_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7185_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7185); +} + + + +#ifdef MODULE + +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7185); +} + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/serial.c linux.ac/drivers/char/serial.c --- linux.vanilla/drivers/char/serial.c Wed Mar 24 10:55:16 1999 +++ linux.ac/drivers/char/serial.c Wed Jun 30 00:50:36 1999 @@ -103,7 +103,8 @@ #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 -#define IRQ_T(info) ((info->flags & 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/sysrq.c linux.ac/drivers/char/sysrq.c --- linux.vanilla/drivers/char/sysrq.c Sun Nov 8 15:07:40 1998 +++ linux.ac/drivers/char/sysrq.c Mon Jun 7 00:10:10 1999 @@ -21,13 +21,12 @@ #include #include #include - -#include - #ifdef CONFIG_APM #include #endif +#include + extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; @@ -85,7 +84,7 @@ #ifdef CONFIG_APM case 'o': /* O -- power off */ printk("Power off\n"); - apm_power_off(); + apm_power_off(1); break; #endif case 's': /* S -- emergency sync */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/videodev.c linux.ac/drivers/char/videodev.c --- linux.vanilla/drivers/char/videodev.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/videodev.c Thu Jul 1 19:13:11 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/vino.c linux.ac/drivers/char/vino.c --- linux.vanilla/drivers/char/vino.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/vino.c Mon Jul 19 03:45:43 1999 @@ -0,0 +1,275 @@ +/* $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 "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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/vino.h linux.ac/drivers/char/vino.h --- linux.vanilla/drivers/char/vino.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/vino.h Tue Jun 22 01:41:18 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/vt.c linux.ac/drivers/char/vt.c --- linux.vanilla/drivers/char/vt.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/char/vt.c Tue Jun 22 01:41:31 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/wdt.c linux.ac/drivers/char/wdt.c --- linux.vanilla/drivers/char/wdt.c Tue Jun 15 16:49:48 1999 +++ linux.ac/drivers/char/wdt.c Mon Jun 7 22:24:09 1999 @@ -51,27 +51,44 @@ static int wdt_is_open=0; /* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. + * There is no sane way to probe for this board. + * You can use wdt=x,y,n to set these values + * or you can use 'insmod wdt io=x irq=y timeout=n' */ static int io=0x240; static int irq=11; +static int timeout=60; /* seconds */ -#define WD_TIMO (100*60) /* 1 minute */ +#ifdef MODULE + +EXPORT_NO_SYMBOLS; +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O port for Watchdog WDT500/501 board"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ for Watchdog WDT500/501 board"); +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, + "Timeout value for Watchdog WDT500/501 board (in seconds)"); + +#endif /* * Setup options */ -__initfunc(void wdt_setup(char *str, int *ints)) +void __init wdt_setup(char *str, int *ints) { if(ints[0]>0) { io=ints[1]; if(ints[0]>1) irq=ints[2]; + if(ints[0]>2) + timeout=ints[3]; } + + timeout *= 100; } /* @@ -168,7 +185,7 @@ /* Write a watchdog value */ inb_p(WDT_DC); wdt_ctr_mode(1,2); - wdt_ctr_load(1,WD_TIMO); /* Timeout */ + wdt_ctr_load(1,timeout); /* Timeout */ outb_p(0, WDT_DC); } @@ -260,7 +277,7 @@ wdt_ctr_mode(1,2); wdt_ctr_mode(2,0); wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */ + wdt_ctr_load(1,timeout); /* Timeout */ wdt_ctr_load(2,65535); outb_p(0, WDT_DC); /* Enable */ return 0; @@ -365,9 +382,9 @@ #endif -__initfunc(int wdt_init(void)) +int __init wdt_init(void) { - printk("WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); + printk("WDT500/501-P driver 0.08 at %X (Interrupt %d)\n", io,irq); if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL)) { printk("IRQ %d is not free.\n", irq); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/zr36057.h linux.ac/drivers/char/zr36057.h --- linux.vanilla/drivers/char/zr36057.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/zr36057.h Thu Jul 1 19:05:24 1999 @@ -0,0 +1,168 @@ +/* + zr36057.h - zr36057 register offsets + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ZR36057_H_ +#define _ZR36057_H_ + + +/* Zoran ZR36057 registers */ + +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR_HSPol (1<<30) +#define ZR36057_VFEHCR_HStart 10 +#define ZR36057_VFEHCR_HEnd 0 +#define ZR36057_VFEHCR_Hmask 0x3ff + +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR_VSPol (1<<30) +#define ZR36057_VFEVCR_VStart 10 +#define ZR36057_VFEVCR_VEnd 0 +#define ZR36057_VFEVCR_Vmask 0x3ff + +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR_ExtFl (1<<26) +#define ZR36057_VFESPFR_TopField (1<<25) +#define ZR36057_VFESPFR_VCLKPol (1<<24) +#define ZR36057_VFESPFR_HFilter 21 +#define ZR36057_VFESPFR_HorDcm 14 +#define ZR36057_VFESPFR_VerDcm 8 +#define ZR36057_VFESPFR_DispMode 6 +#define ZR36057_VFESPFR_YUV422 (0<<3) +#define ZR36057_VFESPFR_RGB888 (1<<3) +#define ZR36057_VFESPFR_RGB565 (2<<3) +#define ZR36057_VFESPFR_RGB555 (3<<3) +#define ZR36057_VFESPFR_ErrDif (1<<2) +#define ZR36057_VFESPFR_Pack24 (1<<1) +#define ZR36057_VFESPFR_LittleEndian (1<<0) + +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ + +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ + +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR_DispStride 16 +#define ZR36057_VSSFGR_VidOvf (1<<8) +#define ZR36057_VSSFGR_SnapShot (1<<1) +#define ZR36057_VSSFGR_FrameGrab (1<<0) + +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR_VidEn (1<<31) +#define ZR36057_VDCR_MinPix 24 +#define ZR36057_VDCR_Triton (1<<24) +#define ZR36057_VDCR_VidWinHt 12 +#define ZR36057_VDCR_VidWinWid 0 + +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ + +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ + +#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR_OvlEnable (1 << 15) +#define ZR36057_OCR_MaskStride 0 + +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR_SoftReset (1<<24) + +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ + +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ + +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR_CodTime (1 << 30) +#define ZR36057_MCTCR_CEmpty (1 << 29) +#define ZR36057_MCTCR_CFlush (1 << 28) +#define ZR36057_MCTCR_CodGuestID 20 +#define ZR36057_MCTCR_CodGuestReg 16 + +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ + +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR_GIRQ1 (1<<30) +#define ZR36057_ISR_GIRQ0 (1<<29) +#define ZR36057_ISR_CodRepIRQ (1<<28) +#define ZR36057_ISR_JPEGRepIRQ (1<<27) + +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR_GIRQ1 (1<<30) +#define ZR36057_ICR_GIRQ0 (1<<29) +#define ZR36057_ICR_CodRepIRQ (1<<28) +#define ZR36057_ICR_JPEGRepIRQ (1<<27) +#define ZR36057_ICR_IntPinEn (1<<24) + +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR_SDA (1<<1) +#define ZR36057_I2CBR_SCL (1<<0) + +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC_JPG (1 << 31) +#define ZR36057_JMC_JPGExpMode (0 << 29) +#define ZR36057_JMC_JPGCmpMode (1 << 29) +#define ZR36057_JMC_MJPGExpMode (2 << 29) +#define ZR36057_JMC_MJPGCmpMode (3 << 29) +#define ZR36057_JMC_RTBUSY_FB (1 << 6) +#define ZR36057_JMC_Go_en (1 << 5) +#define ZR36057_JMC_SyncMstr (1 << 4) +#define ZR36057_JMC_Fld_per_buff (1 << 3) +#define ZR36057_JMC_VFIFO_FB (1 << 2) +#define ZR36057_JMC_CFIFO_FB (1 << 1) +#define ZR36057_JMC_Stll_LitEndian (1 << 0) + +#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC_P_Reset (1 << 7) +#define ZR36057_JPC_CodTrnsEn (1 << 5) +#define ZR36057_JPC_Active (1 << 0) + +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP_VsyncSize 16 +#define ZR36057_VSP_FrmTot 0 + +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP_HsyncStart 16 +#define ZR36057_HSP_LineTot 0 + +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP_NAX 16 +#define ZR36057_FHAP_PAX 0 + +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP_NAY 16 +#define ZR36057_FVAP_PAY 0 + +#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP_Odd_Even (1 << 0) + +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ + +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ + +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI_JPEGuestID 4 +#define ZR36057_JCGI_JPEGuestReg 0 + +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ + +#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR_POPen (1<<25) +#define ZR36057_POR_POTime (1<<24) +#define ZR36057_POR_PODir (1<<23) + +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/zr36060.h linux.ac/drivers/char/zr36060.h --- linux.vanilla/drivers/char/zr36060.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/char/zr36060.h Thu Jul 1 19:05:24 1999 @@ -0,0 +1,35 @@ +/* + zr36060.h - zr36060 register offsets + + Copyright (C) 1998 Dave Perks + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ZR36060_H_ +#define _ZR36060_H_ + + +/* Zoran ZR36060 registers */ + +#define ZR36060_LoadParameters 0x000 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#define ZR36060_CodeFifoStatus 0x001 +#define ZR36060_Load (1<<7) +#define ZR36060_SyncRst (1<<0) + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/fc4/socal.c linux.ac/drivers/fc4/socal.c --- linux.vanilla/drivers/fc4/socal.c Mon Mar 29 10:25:55 1999 +++ linux.ac/drivers/fc4/socal.c Mon Jul 19 19:48:18 1999 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/Config.in linux.ac/drivers/isdn/Config.in --- linux.vanilla/drivers/isdn/Config.in Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/Config.in Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/Makefile linux.ac/drivers/isdn/Makefile --- linux.vanilla/drivers/isdn/Makefile Sun Nov 8 15:08:07 1998 +++ linux.ac/drivers/isdn/Makefile Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/act2000.h linux.ac/drivers/isdn/act2000/act2000.h --- linux.vanilla/drivers/isdn/act2000/act2000.h Thu May 27 22:11:53 1999 +++ linux.ac/drivers/isdn/act2000/act2000.h Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.c linux.ac/drivers/isdn/act2000/act2000_isa.c --- linux.vanilla/drivers/isdn/act2000/act2000_isa.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/act2000/act2000_isa.c Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.h linux.ac/drivers/isdn/act2000/act2000_isa.h --- linux.vanilla/drivers/isdn/act2000/act2000_isa.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/act2000/act2000_isa.h Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/capi.c linux.ac/drivers/isdn/act2000/capi.c --- linux.vanilla/drivers/isdn/act2000/capi.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/act2000/capi.c Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/capi.h linux.ac/drivers/isdn/act2000/capi.h --- linux.vanilla/drivers/isdn/act2000/capi.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/act2000/capi.h Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/act2000/module.c linux.ac/drivers/isdn/act2000/module.c --- linux.vanilla/drivers/isdn/act2000/module.c Thu May 27 22:11:53 1999 +++ linux.ac/drivers/isdn/act2000/module.c Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/Makefile linux.ac/drivers/isdn/avmb1/Makefile --- linux.vanilla/drivers/isdn/avmb1/Makefile Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/Makefile Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/avmcard.h linux.ac/drivers/isdn/avmb1/avmcard.h --- linux.vanilla/drivers/isdn/avmb1/avmcard.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/avmcard.h Mon Jul 19 19:34:19 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1.c linux.ac/drivers/isdn/avmb1/b1.c --- linux.vanilla/drivers/isdn/avmb1/b1.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/b1.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1capi.c linux.ac/drivers/isdn/avmb1/b1capi.c --- linux.vanilla/drivers/isdn/avmb1/b1capi.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/avmb1/b1capi.c Mon Jul 19 19:34:20 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1isa.c linux.ac/drivers/isdn/avmb1/b1isa.c --- linux.vanilla/drivers/isdn/avmb1/b1isa.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/b1isa.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1lli.c linux.ac/drivers/isdn/avmb1/b1lli.c --- linux.vanilla/drivers/isdn/avmb1/b1lli.c Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/isdn/avmb1/b1lli.c Mon Jul 19 19:34:20 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1pci.c linux.ac/drivers/isdn/avmb1/b1pci.c --- linux.vanilla/drivers/isdn/avmb1/b1pci.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/b1pci.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c linux.ac/drivers/isdn/avmb1/b1pcmcia.c --- linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/b1pcmcia.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capi.c linux.ac/drivers/isdn/avmb1/capi.c --- linux.vanilla/drivers/isdn/avmb1/capi.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/capi.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capidev.h linux.ac/drivers/isdn/avmb1/capidev.h --- linux.vanilla/drivers/isdn/avmb1/capidev.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/capidev.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capidrv.c linux.ac/drivers/isdn/avmb1/capidrv.c --- linux.vanilla/drivers/isdn/avmb1/capidrv.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/capidrv.c Mon Jul 19 19:36:07 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capidrv.h linux.ac/drivers/isdn/avmb1/capidrv.h --- linux.vanilla/drivers/isdn/avmb1/capidrv.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/capidrv.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capilli.h linux.ac/drivers/isdn/avmb1/capilli.h --- linux.vanilla/drivers/isdn/avmb1/capilli.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/capilli.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/capiutil.c linux.ac/drivers/isdn/avmb1/capiutil.c --- linux.vanilla/drivers/isdn/avmb1/capiutil.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/capiutil.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/compat.h linux.ac/drivers/isdn/avmb1/compat.h --- linux.vanilla/drivers/isdn/avmb1/compat.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/avmb1/compat.h Mon Jul 19 19:34:20 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/kcapi.c linux.ac/drivers/isdn/avmb1/kcapi.c --- linux.vanilla/drivers/isdn/avmb1/kcapi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/kcapi.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/avmb1/t1isa.c linux.ac/drivers/isdn/avmb1/t1isa.c --- linux.vanilla/drivers/isdn/avmb1/t1isa.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/avmb1/t1isa.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/divert/Makefile linux.ac/drivers/isdn/divert/Makefile --- linux.vanilla/drivers/isdn/divert/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/divert/Makefile Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/divert/divert_init.c linux.ac/drivers/isdn/divert/divert_init.c --- linux.vanilla/drivers/isdn/divert/divert_init.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/divert/divert_init.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/divert/divert_procfs.c linux.ac/drivers/isdn/divert/divert_procfs.c --- linux.vanilla/drivers/isdn/divert/divert_procfs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/divert/divert_procfs.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/divert/isdn_divert.c linux.ac/drivers/isdn/divert/isdn_divert.c --- linux.vanilla/drivers/isdn/divert/isdn_divert.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/divert/isdn_divert.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/divert/isdn_divert.h linux.ac/drivers/isdn/divert/isdn_divert.h --- linux.vanilla/drivers/isdn/divert/isdn_divert.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/divert/isdn_divert.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/Makefile linux.ac/drivers/isdn/eicon/Makefile --- linux.vanilla/drivers/isdn/eicon/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/Makefile Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon.h linux.ac/drivers/isdn/eicon/eicon.h --- linux.vanilla/drivers/isdn/eicon/eicon.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_dsp.h linux.ac/drivers/isdn/eicon/eicon_dsp.h --- linux.vanilla/drivers/isdn/eicon/eicon_dsp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_dsp.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.c linux.ac/drivers/isdn/eicon/eicon_idi.c --- linux.vanilla/drivers/isdn/eicon/eicon_idi.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_idi.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.h linux.ac/drivers/isdn/eicon/eicon_idi.h --- linux.vanilla/drivers/isdn/eicon/eicon_idi.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_idi.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_io.c linux.ac/drivers/isdn/eicon/eicon_io.c --- linux.vanilla/drivers/isdn/eicon/eicon_io.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_io.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_isa.c linux.ac/drivers/isdn/eicon/eicon_isa.c --- linux.vanilla/drivers/isdn/eicon/eicon_isa.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_isa.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_isa.h linux.ac/drivers/isdn/eicon/eicon_isa.h --- linux.vanilla/drivers/isdn/eicon/eicon_isa.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_isa.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_mod.c linux.ac/drivers/isdn/eicon/eicon_mod.c --- linux.vanilla/drivers/isdn/eicon/eicon_mod.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_mod.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_pci.c linux.ac/drivers/isdn/eicon/eicon_pci.c --- linux.vanilla/drivers/isdn/eicon/eicon_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_pci.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/eicon/eicon_pci.h linux.ac/drivers/isdn/eicon/eicon_pci.h --- linux.vanilla/drivers/isdn/eicon/eicon_pci.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/eicon/eicon_pci.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/Makefile linux.ac/drivers/isdn/hisax/Makefile --- linux.vanilla/drivers/isdn/hisax/Makefile Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/Makefile Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/amd7930.c linux.ac/drivers/isdn/hisax/amd7930.c --- linux.vanilla/drivers/isdn/hisax/amd7930.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/amd7930.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/arcofi.c linux.ac/drivers/isdn/hisax/arcofi.c --- linux.vanilla/drivers/isdn/hisax/arcofi.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/hisax/arcofi.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/arcofi.h linux.ac/drivers/isdn/hisax/arcofi.h --- linux.vanilla/drivers/isdn/hisax/arcofi.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/arcofi.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/asuscom.c linux.ac/drivers/isdn/hisax/asuscom.c --- linux.vanilla/drivers/isdn/hisax/asuscom.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/hisax/asuscom.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/avm_a1.c linux.ac/drivers/isdn/hisax/avm_a1.c --- linux.vanilla/drivers/isdn/hisax/avm_a1.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/avm_a1.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/avm_a1p.c linux.ac/drivers/isdn/hisax/avm_a1p.c --- linux.vanilla/drivers/isdn/hisax/avm_a1p.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/avm_a1p.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/avm_pci.c linux.ac/drivers/isdn/hisax/avm_pci.c --- linux.vanilla/drivers/isdn/hisax/avm_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/avm_pci.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/bkm_a4t.c linux.ac/drivers/isdn/hisax/bkm_a4t.c --- linux.vanilla/drivers/isdn/hisax/bkm_a4t.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/bkm_a4t.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/bkm_a8.c linux.ac/drivers/isdn/hisax/bkm_a8.c --- linux.vanilla/drivers/isdn/hisax/bkm_a8.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/bkm_a8.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/bkm_ax.h linux.ac/drivers/isdn/hisax/bkm_ax.h --- linux.vanilla/drivers/isdn/hisax/bkm_ax.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/bkm_ax.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/callc.c linux.ac/drivers/isdn/hisax/callc.c --- linux.vanilla/drivers/isdn/hisax/callc.c Mon Dec 28 23:09:42 1998 +++ linux.ac/drivers/isdn/hisax/callc.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/cert.c linux.ac/drivers/isdn/hisax/cert.c --- linux.vanilla/drivers/isdn/hisax/cert.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/cert.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/config.c linux.ac/drivers/isdn/hisax/config.c --- linux.vanilla/drivers/isdn/hisax/config.c Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/config.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/diva.c linux.ac/drivers/isdn/hisax/diva.c --- linux.vanilla/drivers/isdn/hisax/diva.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/hisax/diva.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/elsa.c linux.ac/drivers/isdn/hisax/elsa.c --- linux.vanilla/drivers/isdn/hisax/elsa.c Sun Nov 8 15:10:14 1998 +++ linux.ac/drivers/isdn/hisax/elsa.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/elsa_ser.c linux.ac/drivers/isdn/hisax/elsa_ser.c --- linux.vanilla/drivers/isdn/hisax/elsa_ser.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/elsa_ser.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/foreign.c linux.ac/drivers/isdn/hisax/foreign.c --- linux.vanilla/drivers/isdn/hisax/foreign.c Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/foreign.c Mon Jul 19 19:34:20 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/foreign.h linux.ac/drivers/isdn/hisax/foreign.h --- linux.vanilla/drivers/isdn/hisax/foreign.h Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/foreign.h Mon Jul 19 19:34:20 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/fsm.c linux.ac/drivers/isdn/hisax/fsm.c --- linux.vanilla/drivers/isdn/hisax/fsm.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/fsm.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/gazel.c linux.ac/drivers/isdn/hisax/gazel.c --- linux.vanilla/drivers/isdn/hisax/gazel.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/gazel.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c linux.ac/drivers/isdn/hisax/hfc_2bds0.c --- linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/hfc_2bds0.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c linux.ac/drivers/isdn/hisax/hfc_2bs0.c --- linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/hfc_2bs0.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.c linux.ac/drivers/isdn/hisax/hfc_pci.c --- linux.vanilla/drivers/isdn/hisax/hfc_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/hfc_pci.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.h linux.ac/drivers/isdn/hisax/hfc_pci.h --- linux.vanilla/drivers/isdn/hisax/hfc_pci.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/hfc_pci.h Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hfcscard.c linux.ac/drivers/isdn/hisax/hfcscard.c --- linux.vanilla/drivers/isdn/hisax/hfcscard.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/hfcscard.c Mon Jul 19 19:34:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hisax.h linux.ac/drivers/isdn/hisax/hisax.h --- linux.vanilla/drivers/isdn/hisax/hisax.h Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/hisax.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hscx.c linux.ac/drivers/isdn/hisax/hscx.c --- linux.vanilla/drivers/isdn/hisax/hscx.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/hscx.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hscx.h linux.ac/drivers/isdn/hisax/hscx.h --- linux.vanilla/drivers/isdn/hisax/hscx.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/hscx.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/hscx_irq.c linux.ac/drivers/isdn/hisax/hscx_irq.c --- linux.vanilla/drivers/isdn/hisax/hscx_irq.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/hscx_irq.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/ipac.h linux.ac/drivers/isdn/hisax/ipac.h --- linux.vanilla/drivers/isdn/hisax/ipac.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/ipac.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isac.c linux.ac/drivers/isdn/hisax/isac.c --- linux.vanilla/drivers/isdn/hisax/isac.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/isac.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isac.h linux.ac/drivers/isdn/hisax/isac.h --- linux.vanilla/drivers/isdn/hisax/isac.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/isac.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isar.c linux.ac/drivers/isdn/hisax/isar.c --- linux.vanilla/drivers/isdn/hisax/isar.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/isar.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isar.h linux.ac/drivers/isdn/hisax/isar.h --- linux.vanilla/drivers/isdn/hisax/isar.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/isar.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isdnl1.c linux.ac/drivers/isdn/hisax/isdnl1.c --- linux.vanilla/drivers/isdn/hisax/isdnl1.c Wed Mar 24 10:55:17 1999 +++ linux.ac/drivers/isdn/hisax/isdnl1.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isdnl1.h linux.ac/drivers/isdn/hisax/isdnl1.h --- linux.vanilla/drivers/isdn/hisax/isdnl1.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/isdnl1.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isdnl2.c linux.ac/drivers/isdn/hisax/isdnl2.c --- linux.vanilla/drivers/isdn/hisax/isdnl2.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/isdnl2.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isdnl3.c linux.ac/drivers/isdn/hisax/isdnl3.c --- linux.vanilla/drivers/isdn/hisax/isdnl3.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/isdnl3.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isdnl3.h linux.ac/drivers/isdn/hisax/isdnl3.h --- linux.vanilla/drivers/isdn/hisax/isdnl3.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/isdnl3.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/isurf.c linux.ac/drivers/isdn/hisax/isurf.c --- linux.vanilla/drivers/isdn/hisax/isurf.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/isurf.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/ix1_micro.c linux.ac/drivers/isdn/hisax/ix1_micro.c --- linux.vanilla/drivers/isdn/hisax/ix1_micro.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/ix1_micro.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/jade.c linux.ac/drivers/isdn/hisax/jade.c --- linux.vanilla/drivers/isdn/hisax/jade.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/jade.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/jade.h linux.ac/drivers/isdn/hisax/jade.h --- linux.vanilla/drivers/isdn/hisax/jade.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/jade.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/jade_irq.c linux.ac/drivers/isdn/hisax/jade_irq.c --- linux.vanilla/drivers/isdn/hisax/jade_irq.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/jade_irq.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/l3_1tr6.c linux.ac/drivers/isdn/hisax/l3_1tr6.c --- linux.vanilla/drivers/isdn/hisax/l3_1tr6.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/l3_1tr6.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/l3_1tr6.h linux.ac/drivers/isdn/hisax/l3_1tr6.h --- linux.vanilla/drivers/isdn/hisax/l3_1tr6.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/l3_1tr6.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/l3dss1.c linux.ac/drivers/isdn/hisax/l3dss1.c --- linux.vanilla/drivers/isdn/hisax/l3dss1.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/l3dss1.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/l3dss1.h linux.ac/drivers/isdn/hisax/l3dss1.h --- linux.vanilla/drivers/isdn/hisax/l3dss1.h Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/l3dss1.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/lmgr.c linux.ac/drivers/isdn/hisax/lmgr.c --- linux.vanilla/drivers/isdn/hisax/lmgr.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/lmgr.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/md5sums.asc linux.ac/drivers/isdn/hisax/md5sums.asc --- linux.vanilla/drivers/isdn/hisax/md5sums.asc Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/md5sums.asc Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/mic.c linux.ac/drivers/isdn/hisax/mic.c --- linux.vanilla/drivers/isdn/hisax/mic.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/mic.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/netjet.c linux.ac/drivers/isdn/hisax/netjet.c --- linux.vanilla/drivers/isdn/hisax/netjet.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/hisax/netjet.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/niccy.c linux.ac/drivers/isdn/hisax/niccy.c --- linux.vanilla/drivers/isdn/hisax/niccy.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/niccy.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/q931.c linux.ac/drivers/isdn/hisax/q931.c --- linux.vanilla/drivers/isdn/hisax/q931.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/q931.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/rawhdlc.c linux.ac/drivers/isdn/hisax/rawhdlc.c --- linux.vanilla/drivers/isdn/hisax/rawhdlc.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/rawhdlc.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/s0box.c linux.ac/drivers/isdn/hisax/s0box.c --- linux.vanilla/drivers/isdn/hisax/s0box.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/s0box.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/saphir.c linux.ac/drivers/isdn/hisax/saphir.c --- linux.vanilla/drivers/isdn/hisax/saphir.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/saphir.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/sedlbauer.c linux.ac/drivers/isdn/hisax/sedlbauer.c --- linux.vanilla/drivers/isdn/hisax/sedlbauer.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/hisax/sedlbauer.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/sportster.c linux.ac/drivers/isdn/hisax/sportster.c --- linux.vanilla/drivers/isdn/hisax/sportster.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/hisax/sportster.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/tei.c linux.ac/drivers/isdn/hisax/tei.c --- linux.vanilla/drivers/isdn/hisax/tei.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/hisax/tei.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/teleint.c linux.ac/drivers/isdn/hisax/teleint.c --- linux.vanilla/drivers/isdn/hisax/teleint.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/hisax/teleint.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/teles0.c linux.ac/drivers/isdn/hisax/teles0.c --- linux.vanilla/drivers/isdn/hisax/teles0.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/teles0.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/teles3.c linux.ac/drivers/isdn/hisax/teles3.c --- linux.vanilla/drivers/isdn/hisax/teles3.c Sun Nov 8 15:08:09 1998 +++ linux.ac/drivers/isdn/hisax/teles3.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/teles3c.c linux.ac/drivers/isdn/hisax/teles3c.c --- linux.vanilla/drivers/isdn/hisax/teles3c.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/hisax/teles3c.c Mon Jul 19 19:34:21 1999 @@ -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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/hisax/telespci.c linux.ac/drivers/isdn/hisax/telespci.c --- linux.vanilla/drivers/isdn/hisax/telespci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/hisax/telespci.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/icn/icn.c linux.ac/drivers/isdn/icn/icn.c --- linux.vanilla/drivers/isdn/icn/icn.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/icn/icn.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/icn/icn.h linux.ac/drivers/isdn/icn/icn.h --- linux.vanilla/drivers/isdn/icn/icn.h Sat Jan 9 21:50:38 1999 +++ linux.ac/drivers/isdn/icn/icn.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_audio.c linux.ac/drivers/isdn/isdn_audio.c --- linux.vanilla/drivers/isdn/isdn_audio.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/isdn_audio.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_audio.h linux.ac/drivers/isdn/isdn_audio.h --- linux.vanilla/drivers/isdn/isdn_audio.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/isdn_audio.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_bsdcomp.c linux.ac/drivers/isdn/isdn_bsdcomp.c --- linux.vanilla/drivers/isdn/isdn_bsdcomp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/isdn_bsdcomp.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_cards.c linux.ac/drivers/isdn/isdn_cards.c --- linux.vanilla/drivers/isdn/isdn_cards.c Sun Nov 8 15:08:07 1998 +++ linux.ac/drivers/isdn/isdn_cards.c Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_cards.h linux.ac/drivers/isdn/isdn_cards.h --- linux.vanilla/drivers/isdn/isdn_cards.h Sun Nov 8 15:08:07 1998 +++ linux.ac/drivers/isdn/isdn_cards.h Mon Jul 19 19:34:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_common.c linux.ac/drivers/isdn/isdn_common.c --- linux.vanilla/drivers/isdn/isdn_common.c Sun Jan 24 19:55:34 1999 +++ linux.ac/drivers/isdn/isdn_common.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_common.h linux.ac/drivers/isdn/isdn_common.h --- linux.vanilla/drivers/isdn/isdn_common.h Sun Jan 24 19:55:34 1999 +++ linux.ac/drivers/isdn/isdn_common.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_concap.c linux.ac/drivers/isdn/isdn_concap.c --- linux.vanilla/drivers/isdn/isdn_concap.c Sun Nov 8 15:08:10 1998 +++ linux.ac/drivers/isdn/isdn_concap.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_net.c linux.ac/drivers/isdn/isdn_net.c --- linux.vanilla/drivers/isdn/isdn_net.c Sun Jan 24 19:55:34 1999 +++ linux.ac/drivers/isdn/isdn_net.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_net.h linux.ac/drivers/isdn/isdn_net.h --- linux.vanilla/drivers/isdn/isdn_net.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/isdn_net.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_ppp.c linux.ac/drivers/isdn/isdn_ppp.c --- linux.vanilla/drivers/isdn/isdn_ppp.c Sun Jan 24 19:55:34 1999 +++ linux.ac/drivers/isdn/isdn_ppp.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_ppp.h linux.ac/drivers/isdn/isdn_ppp.h --- linux.vanilla/drivers/isdn/isdn_ppp.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/isdn_ppp.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_syms.c linux.ac/drivers/isdn/isdn_syms.c --- linux.vanilla/drivers/isdn/isdn_syms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/isdn/isdn_syms.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_tty.c linux.ac/drivers/isdn/isdn_tty.c --- linux.vanilla/drivers/isdn/isdn_tty.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/isdn_tty.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_tty.h linux.ac/drivers/isdn/isdn_tty.h --- linux.vanilla/drivers/isdn/isdn_tty.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/isdn_tty.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdn_x25iface.c linux.ac/drivers/isdn/isdn_x25iface.c --- linux.vanilla/drivers/isdn/isdn_x25iface.c Sat Jan 9 21:50:38 1999 +++ linux.ac/drivers/isdn/isdn_x25iface.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdnloop/isdnloop.c linux.ac/drivers/isdn/isdnloop/isdnloop.c --- linux.vanilla/drivers/isdn/isdnloop/isdnloop.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/isdnloop/isdnloop.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/isdnloop/isdnloop.h linux.ac/drivers/isdn/isdnloop/isdnloop.h --- linux.vanilla/drivers/isdn/isdnloop/isdnloop.h Sun Nov 8 15:08:10 1998 +++ linux.ac/drivers/isdn/isdnloop/isdnloop.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/pcbit/callbacks.c linux.ac/drivers/isdn/pcbit/callbacks.c --- linux.vanilla/drivers/isdn/pcbit/callbacks.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/pcbit/callbacks.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/pcbit/drv.c linux.ac/drivers/isdn/pcbit/drv.c --- linux.vanilla/drivers/isdn/pcbit/drv.c Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/pcbit/drv.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/pcbit/pcbit.h linux.ac/drivers/isdn/pcbit/pcbit.h --- linux.vanilla/drivers/isdn/pcbit/pcbit.h Sun Nov 8 15:08:08 1998 +++ linux.ac/drivers/isdn/pcbit/pcbit.h Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/isdn/sc/message.c linux.ac/drivers/isdn/sc/message.c --- linux.vanilla/drivers/isdn/sc/message.c Sun Nov 8 15:10:15 1998 +++ linux.ac/drivers/isdn/sc/message.c Mon Jul 19 19:34:22 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Config.in linux.ac/drivers/net/Config.in --- linux.vanilla/drivers/net/Config.in Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Config.in Tue Jun 22 01:34:49 1999 @@ -2,6 +2,9 @@ # Network device configuration # +mainmenu_option next_comment +comment 'ARCnet devices' + tristate 'ARCnet support' CONFIG_ARCNET if [ "$CONFIG_ARCNET" != "n" ]; then bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH @@ -12,6 +15,8 @@ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET fi +endmenu + tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -22,6 +27,10 @@ # # Ethernet # + +mainmenu_option next_comment +comment 'Ethernet (10 or 100Mbit)' + bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET if [ "$CONFIG_NET_ETHERNET" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then @@ -42,7 +51,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 @@ -82,18 +91,15 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN - tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC fi bool 'Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then - tristate 'AT1700/1720 support' CONFIG_AT1700 + tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 tristate 'Cabletron E21xx support' CONFIG_E2100 tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 tristate 'EtherExpress 16 support' CONFIG_EEXPRESS - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - fi + tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN @@ -103,7 +109,7 @@ fi tristate 'NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 fi bool 'SK_G16 support' CONFIG_SK_G16 fi @@ -115,6 +121,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 fi @@ -145,6 +152,8 @@ fi fi +endmenu + bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX @@ -153,25 +162,20 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI if [ "$CONFIG_HIPPI" = "y" ]; then - bool 'CERN HIPPI PCI adapter support' CONFIG_CERN_HIPPI - bool 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER + tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS fi fi fi -tristate 'Frame relay DLCI support' CONFIG_DLCI -if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then - int ' Max open DLCI' CONFIG_DLCI_COUNT 24 - int ' Max DLCI per device' CONFIG_DLCI_MAX 8 - dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI -fi - # # AppleTalk # + if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK if [ "$CONFIG_COPS" != "n" ]; then @@ -183,6 +187,7 @@ bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP fi + endmenu fi if [ ! "$CONFIG_PARPORT" = "n" ]; then @@ -203,23 +208,38 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then - tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP + dep_tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN + fi +mainmenu_option next_comment +comment 'Token ring devices' + bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" = "y" ]; then tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR # tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS + tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL tristate 'SysKonnect adapter support' CONFIG_SKTR fi +endmenu + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi + # # WAN drivers support # + +mainmenu_option next_comment +comment 'Wan interfaces' + + # There is no way to detect a comtrol sv11 - force it modular for now. # dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m @@ -227,8 +247,22 @@ # The COSA/SRP driver has not been tested as non-modular yet. # dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m -tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI # +# There is no way to detect a Sealevel board. Force it modular +# +dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m + +tristate 'Frame relay DLCI support' CONFIG_DLCI +if [ "$CONFIG_DLCI" != "n" ]; then + int ' Max open DLCI' CONFIG_DLCI_COUNT 24 + int ' Max DLCI per device' CONFIG_DLCI_MAX 8 + dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI +fi + +# +# Wan router core. +# + if [ "$CONFIG_WAN_ROUTER" != "n" ]; then bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then @@ -238,14 +272,18 @@ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC fi fi fi + +endmenu + # # X.25 network drivers # if [ "$CONFIG_X25" != "n" ]; then -if [ "$CONFIG_LAPB" != "n" ]; then +if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Makefile linux.ac/drivers/net/Makefile --- linux.vanilla/drivers/net/Makefile Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Makefile Tue Jun 22 01:34:49 1999 @@ -67,6 +67,14 @@ endif endif +ifeq ($(CONFIG_IBMOL),y) +L_OBJS += olympic.o +else + ifeq ($(CONFIG_IBMOL),m) + M_OBJS += olympic.o + endif +endif + ifeq ($(CONFIG_SKTR),y) L_OBJS += sktr.o else @@ -143,14 +151,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o CONFIG_8390_BUILTIN = y @@ -171,14 +171,6 @@ endif endif -ifeq ($(CONFIG_ETHERH),y) -CONFIG_8390_BUILTIN = y -else - ifeq ($(CONFIG_ETHERH),m) - CONFIG_8390_MODULE = y - endif -endif - ifeq ($(CONFIG_NE2K_PCI),y) L_OBJS += ne2k-pci.o CONFIG_8390_BUILTIN = y @@ -438,6 +430,14 @@ endif endif +ifeq ($(CONFIG_SUNBMAC),y) +L_OBJS += sunbmac.o +else + ifeq ($(CONFIG_SUNBMAC),m) + M_OBJS += sunbmac.o + endif +endif + ifeq ($(CONFIG_MYRI_SBUS),y) L_OBJS += myri_sbus.o else @@ -582,6 +582,14 @@ endif endif +ifeq ($(CONFIG_ARLAN),y) +LX_OBJS += arlan.o arlan-proc.o +else + ifeq ($(CONFIG_ARLAN),m) + MX_OBJS += arlan.o arlan-proc.o + endif +endif + ifeq ($(CONFIG_TLAN),y) L_OBJS += tlan.o else @@ -780,6 +788,19 @@ endif endif +ifeq ($(CONFIG_SEALEVEL_4021),y) +L_OBJS += sealevel.o +CONFIG_85230_BUILTIN = y +CONFIG_SYNCPPP_BUILTIN = y +else + ifeq ($(CONFIG_SEALEVEL_4021),m) + CONFIG_85230_MODULE = y + CONFIG_SYNCPPP_MODULE = y + M_OBJS += sealevel.o + endif +endif + + ifeq ($(CONFIG_COSA),y) L_OBJS += cosa.o CONFIG_SYNCPPP_BUILTIN = y @@ -892,10 +913,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/Space.c linux.ac/drivers/net/Space.c --- linux.vanilla/drivers/net/Space.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/Space.c Thu Jul 8 22:22:16 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 *); @@ -111,6 +112,8 @@ extern int epic100_probe(struct device *dev); extern int rtl8139_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); @@ -357,6 +360,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 +449,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 +680,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 +731,7 @@ #ifdef CONFIG_TR /* Token-ring device probe */ extern int ibmtr_probe(struct device *); +extern int olympic_probe(struct device *); static int trif_probe(struct device *dev) @@ -718,6 +739,9 @@ if (1 #ifdef CONFIG_IBMTR && ibmtr_probe(dev) +#endif +#ifdef CONFIG_IBMOL + && olympic_probe(dev) #endif #ifdef CONFIG_SKTR && sktr_probe(dev) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arcnet.c linux.ac/drivers/net/arcnet.c --- linux.vanilla/drivers/net/arcnet.c Sun Nov 8 15:07:21 1998 +++ linux.ac/drivers/net/arcnet.c Mon Jul 5 04:31:20 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan-proc.c linux.ac/drivers/net/arlan-proc.c --- linux.vanilla/drivers/net/arlan-proc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan-proc.c Mon Jul 19 03:45:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.c linux.ac/drivers/net/arlan.c --- linux.vanilla/drivers/net/arlan.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.c Mon Jul 19 03:45:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/arlan.h linux.ac/drivers/net/arlan.h --- linux.vanilla/drivers/net/arlan.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/arlan.h Mon Jul 19 21:20:07 1999 @@ -0,0 +1,574 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * Gnu Public License applies + */ +#include + +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 1 + +#define ARLAN_PROC_INTERFACE +#define MAX_ARLANS 4 /* not more than 4 ! */ +#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ + +#define ARLAN_MAX_MULTICAST_ADDRS 16 +#define ARLAN_RCV_CLEAN 0 +#define ARLAN_RCV_PROMISC 1 +#define ARLAN_RCV_CONTROL 2 + + +#ifdef CONFIG_PROC_FS +extern int init_arlan_proc(void); +#endif + +extern struct device *arlan_device[MAX_ARLANS]; +static int arlan_debug; +static char * siteName; +static int arlan_entry_debug; +static int arlan_exit_debug; +static int arlan_entry_and_exit_debug; +static int testMemory; +static const char* arlan_version; + +#define SIDUNKNOWN -1 +#define radioNodeIdUNKNOWN -1 +#define encryptionKeyUNKNOWN '\0'; +#define irqUNKNOWN 0 +#define memUNKNOWN 0 +#define debugUNKNOWN 0 +#define probeUNKNOWN 1 +#define numDevicesUNKNOWN 1 +#define testMemoryUNKNOWN 1 +#define spreadingCodeUNKNOWN 0 +#define channelNumberUNKNOWN 0 +#define channelSetUNKNOWN 0 +#define systemIdUNKNOWN -1 +#define registrationModeUNKNOWN -1 +#define siteNameUNKNOWN "LinuxSite" + + + +#define IFDEBUG( L ) if ( (L) & arlan_debug ) +#define ARLAN_FAKE_HDR_LEN 12 + +#ifdef DEBUG + #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) +#else + #define ARLAN_DEBUG(a,b) +#endif + +struct arlan_shmem +{ + /* Header Signature */ + volatile char textRegion[48]; + volatile u_char resetFlag; + volatile u_char diagnosticInfo; + volatile u_short diagnosticOffset; + volatile u_char _1[12]; + volatile u_char lanCardNodeId[6]; + volatile u_char broadcastAddress[6]; + volatile u_char hardwareType; + volatile u_char majorHardwareVersion; + volatile u_char minorHardwareVersion; + volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 + volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A + volatile u_char _2[47]; + + /* Control/Status Block - 0x0080 */ + volatile u_char interruptInProgress; /* not used by lancpu */ + volatile u_char cntrlRegImage; /* not used by lancpu */ + volatile u_char _3[13]; + volatile u_char dumpByte; + volatile u_char commandByte; /* non-zero = active */ + volatile u_char commandParameter[15]; + + /* Receive Status - 0x00a0 */ + volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ + volatile u_char rxFrmType; + volatile u_short rxOffset; + volatile u_short rxLength; + volatile u_char rxSrc[6]; + volatile u_char rxBroadcastFlag; + volatile u_char rxQuality; + volatile u_char scrambled; + volatile u_char _4[1]; + + /* Transmit Status - 0x00b0 */ + volatile u_char txStatus; + volatile u_char txAckQuality; + volatile u_char numRetries; + volatile u_char _5[14]; + volatile u_char registeredRouter[6]; + volatile u_char backboneRouter[6]; + volatile u_char registrationStatus; + volatile u_char configuredStatusFlag; + volatile u_char _6[1]; + volatile u_char ultimateDestAddress[6]; + volatile u_char immedDestAddress[6]; + volatile u_char immedSrcAddress[6]; + volatile u_short rxSequenceNumber; + volatile u_char assignedLocaltalkAddress; + volatile u_char _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + volatile u_short txTimeout; + volatile u_short transportTime; + volatile u_char _8[4]; + + /* - Configuration Parameters */ + volatile u_char irqLevel; + volatile u_char spreadingCode; + volatile u_char channelSet; + volatile u_char channelNumber; + volatile u_short radioNodeId; + volatile u_char _9[2]; + volatile u_char scramblingDisable; + volatile u_char radioType; + volatile u_short routerId; + volatile u_char _10[9]; + volatile u_char txAttenuation; + volatile u_char systemId[4]; + volatile u_short globalChecksum; + volatile u_char _11[4]; + volatile u_short maxDatagramSize; + volatile u_short maxFrameSize; + volatile u_char maxRetries; + volatile u_char receiveMode; + volatile u_char priority; + volatile u_char rootOrRepeater; + volatile u_char specifiedRouter[6]; + volatile u_short fastPollPeriod; + volatile u_char pollDecay; + volatile u_char fastPollDelay[2]; + volatile u_char arlThreshold; + volatile u_char arlDecay; + volatile u_char _12[1]; + volatile u_short specRouterTimeout; + volatile u_char _13[5]; + + /* Scrambled Area */ + volatile u_char SID[4]; + volatile u_char encryptionKey[12]; + volatile u_char _14[2]; + volatile u_char waitTime[2]; + volatile u_char lParameter[2]; + volatile u_char _15[3]; + volatile u_short headerSize; + volatile u_short sectionChecksum; + + volatile u_char registrationMode; + volatile u_char registrationFill; + volatile u_short pollPeriod; + volatile u_short refreshPeriod; + volatile u_char name[16]; + volatile u_char NID[6]; + volatile u_char localTalkAddress; + volatile u_char codeFormat; + volatile u_char numChannels; + volatile u_char channel1; + volatile u_char channel2; + volatile u_char channel3; + volatile u_char channel4; + volatile u_char SSCode[59]; + + volatile u_char _16[0xC0]; + volatile u_short auxCmd; + volatile u_char dumpPtr[4]; + volatile u_char dumpVal; + volatile u_char _17[0x6A]; + volatile u_char wireTest; + volatile u_char _18[14]; + + /* Statistics Block - 0x0300 */ + volatile u_char hostcpuLock; + volatile u_char lancpuLock; + volatile u_char resetTime[18]; + + volatile u_char numDatagramsTransmitted[4]; + volatile u_char numReTransmissions[4]; + volatile u_char numFramesDiscarded[4]; + volatile u_char numDatagramsReceived[4]; + volatile u_char numDuplicateReceivedFrames[4]; + volatile u_char numDatagramsDiscarded[4]; + + volatile u_short maxNumReTransmitDatagram; + volatile u_short maxNumReTransmitFrames; + volatile u_short maxNumConsecutiveDuplicateFrames; + /* misaligned here so we have to go to characters */ + + volatile u_char numBytesTransmitted[4]; + volatile u_char numBytesReceived[4]; + volatile u_char numCRCErrors[4]; + volatile u_char numLengthErrors[4]; + volatile u_char numAbortErrors[4]; + volatile u_char numTXUnderruns[4]; + volatile u_char numRXOverruns[4]; + volatile u_char numHoldOffs[4]; + volatile u_char numFramesTransmitted[4]; + volatile u_char numFramesReceived[4]; + volatile u_char numReceiveFramesLost[4]; + volatile u_char numRXBufferOverflows[4]; + volatile u_char numFramesDiscardedAddrMismatch[4]; + volatile u_char numFramesDiscardedSIDMismatch[4]; + volatile u_char numPollsTransmistted[4]; + volatile u_char numPollAcknowledges[4]; + volatile u_char numStatusTimeouts[4]; + volatile u_char numNACKReceived[4]; + + volatile u_char _19[0x86]; + + volatile u_char txBuffer[0x800]; + volatile u_char rxBuffer[0x800]; + + volatile u_char _20[0x800]; + volatile u_char _21[0x3fb]; + volatile u_char configStatus; + volatile u_char _22; + volatile u_char progIOCtrl; + volatile u_char shareMBase; + volatile u_char controlRegister; +}; + +struct arlan_conf_stru { + int spreadingCode; + int channelSet; + int channelNumber; + int scramblingDisable; + int txAttenuation; + int systemId; + int maxDatagramSize; + int maxFrameSize; + int maxRetries; + int receiveMode; + int priority; + int rootOrRepeater; + int SID; + int radioNodeId; + int registrationMode; + int registrationFill; + int localTalkAddress; + int codeFormat; + int numChannels; + int channel1; + int channel2; + int channel3; + int channel4; + int txClear; + int txRetries; + int txRouting; + int txScrambled; + int rxParameter; + int txTimeoutMs; + int txAckTimeoutMs; + int waitCardTimeout; + int waitTime; + int lParameter; + int _15; + int headerSize; + int async; + int retries; + int tx_delay_ms; + int waitReTransmitPacketMaxSize; + int ReTransmitPacketMaxSize; + int fastReTransCount; + int driverRetransmissions; + int registrationInterrupts; + int hardwareType; + int radioType; + int writeRadioType; + int writeEEPROM; + char siteName[17]; + int measure_rate; + int in_speed; + int out_speed; + int in_speed10; + int out_speed10; + int in_speed_max; + int out_speed_max; + int pre_Command_Wait; + int rx_tweak1; + int rx_tweak2; + int tx_queue_len; +}; + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; + +struct TxParam +{ + volatile short offset; + volatile short length; + volatile u_char dest[6]; + volatile unsigned char clear; + volatile unsigned char retries; + volatile unsigned char routing; + volatile unsigned char scrambled; +}; + +struct TxRingPoint { + struct TxParam txParam; + + +}; + +#define TX_RING_SIZE 2 +/* Information that need to be kept for each board. */ +struct arlan_private { + struct enet_statistics stats; + long open_time; /* Useless example local info. */ + struct arlan_shmem * card; + struct arlan_shmem * conf; + struct TxParam txParam; + int multicastLength; + char multicastList[ARLAN_MAX_MULTICAST_ADDRS][6]; + int promiscModeEnabled; + struct arlan_conf_stru * Conf; + int bad; + int reset; + long long lastReset; + struct timer_list timer; + struct timer_list tx_delay_timer; + struct timer_list tx_retry_timer; + struct timer_list rx_check_timer; + struct semaphore card_lock; + atomic_t card_users; + atomic_t delay_on; + atomic_t retr_on; + int registrationLostCount; + int reRegisterExp; + int nof_tx; + int nof_tx_ack; + int last_nof_tx; + int last_nof_tx_ack; + int irq_test_done; + int last_command_was_rx; + struct TxParam txRing[TX_RING_SIZE]; + char reTransmitBuff[0x800]; + volatile int txLast; + volatile int txNew; + volatile int txOffset; + volatile char ReTransmitRequested; + volatile long long tx_done_delayed; + volatile long long registrationLastSeen; + volatile char under_command; + volatile char under_toggle; + volatile long long tx_last_sent; + volatile long long tx_last_cleared; + volatile u_char under_tx; + volatile int retransmissions; + volatile int tx_chain_active; + volatile int timer_chain_active; + volatile int interrupt_ack_requested; + volatile int command_lock; + volatile int rx_command_needed; + volatile int tx_command_needed; + volatile int waiting_command_mask; + volatile int card_polling_interval; + volatile int last_command_buff_free_time; + volatile int numResets; + volatile int under_reset; + volatile int under_config; + volatile int rx_command_given; + volatile int tx_command_given; + volatile int interrupt_processing_active; + volatile long long last_tx_time; + volatile long long last_rx_time; + volatile long long last_rx_int_ack_time; + int in_bytes; + int out_bytes; + int in_time; + int out_time; + int in_time10; + int out_time10; + int in_bytes10; + int out_bytes10; +}; + + + +#define ARLAN_CLEAR 0x00 +#define ARLAN_RESET 0x01 +#define ARLAN_CHANNEL_ATTENTION 0x02 +#define ARLAN_INTERRUPT_ENABLE 0x04 +#define ARLAN_CLEAR_INTERRUPT 0x08 +#define ARLAN_POWER 0x40 +#define ARLAN_ACCESS 0x80 + +#define ARLAN_COM_CONF 0x01 +#define ARLAN_COM_RX_ENABLE 0x03 +#define ARLAN_COM_RX_ABORT 0x04 +#define ARLAN_COM_TX_ENABLE 0x05 +#define ARLAN_COM_TX_ABORT 0x06 +#define ARLAN_COM_NOP 0x07 +#define ARLAN_COM_STANDBY 0x08 +#define ARLAN_COM_ACTIVATE 0x09 +#define ARLAN_COM_GOTO_SLOW_POLL 0x0a +#define ARLAN_COM_INT 0x80 + + +#define TXLAST(dev) (((struct arlan_private *)dev->priv)->txRing[((struct arlan_private *)dev->priv)->txLast]) +#define TXHEAD(dev) (((struct arlan_private *)dev->priv)->txRing[0]) +#define TXTAIL(dev) (((struct arlan_private *)dev->priv)->txRing[1]) + +#define TXBuffStart(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->txBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) ) +#define TXBuffEnd(dev) \ + ((int)(((struct arlan_private *)dev->priv)->card)->rxBuffer) - ((int)(((struct arlan_private *)dev->priv)->card) + +#define READSHM(to,from,atype) {\ + atype tmp;\ + memcpy_fromio(&(tmp),&(from),sizeof(atype));\ + to = tmp;\ + } + +#define READSHMEM(from,atype)\ + atype from; \ + READSHM(from, arlan->from, atype); + +#define WRITESHM(to,from,atype) \ + { atype tmpSHM = from;\ + memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ + } + +#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ + { atype tmpSHM; \ + memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ + IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ + } + +#define WRITESHMB(to, val) \ + writeb(val,&(to)) +#define READSHMB(to) \ + readb(&(to)) +#define WRITESHMS(to, val) \ + writew(val,&(to)) +#define READSHMS(to) \ + readw(&(to)) +#define WRITESHMI(to, val) \ + writel(val,&(to)) +#define READSHMI(to) \ + readl(&(to)) + + + + + +#define registrationBad(dev)\ + ( ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationMode) > 0) && \ + ( READSHMB(((struct arlan_private *)dev->priv)->card->registrationStatus) == 0) ) + + +#define readControlRegister(dev)\ + READSHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage) + +#define writeControlRegister(dev, v){\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->cntrlRegImage ,((v) &0xF) );\ + WRITESHMB(((struct arlan_private *)dev->priv)->card->controlRegister ,(v) );} + + +#define arlan_interrupt_lancpu(dev) {\ + int cr; \ + \ + priv->under_toggle++; \ + cr = readControlRegister(dev);\ + if (cr & ARLAN_CHANNEL_ATTENTION){ \ + writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ + }else \ + writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ + priv->under_toggle=0; \ +} + +#define clearChannelAttention(dev){ \ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} +#define setHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} +#define clearHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} +#define setInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} +#define clearInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} +#define setClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} +#define clearClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} +#define setPowerOff(dev){\ + writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define setPowerOn(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } +#define arlan_lock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define arlan_unlock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } + + + + +#define ARLAN_COMMAND_RX 0x00001 +#define ARLAN_COMMAND_NOOP 0x00002 +#define ARLAN_COMMAND_NOOPINT 0x00004 +#define ARLAN_COMMAND_TX 0x00008 +#define ARLAN_COMMAND_CONF 0x00010 +#define ARLAN_COMMAND_RESET 0x00020 +#define ARLAN_COMMAND_TX_ABORT 0x00040 +#define ARLAN_COMMAND_RX_ABORT 0x00080 +#define ARLAN_COMMAND_POWERDOWN 0x00100 +#define ARLAN_COMMAND_POWERUP 0x00200 +#define ARLAN_COMMAND_SLOW_POLL 0x00400 +#define ARLAN_COMMAND_ACTIVATE 0x00800 +#define ARLAN_COMMAND_INT_ACK 0x01000 +#define ARLAN_COMMAND_INT_ENABLE 0x02000 +#define ARLAN_COMMAND_WAIT_NOW 0x04000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x08000 +#define ARLAN_COMMAND_STANDBY 0x10000 +#define ARLAN_COMMAND_INT_RACK 0x20000 +#define ARLAN_COMMAND_INT_RENABLE 0x40000 +#define ARLAN_COMMAND_CONF_WAIT 0x80000 +#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_CONF) +#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_RESET) + + + +#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 +#define ARLAN_DEBUG_RESET 0x00002 +#define ARLAN_DEBUG_TIMING 0x00004 +#define ARLAN_DEBUG_CARD_STATE 0x00008 +#define ARLAN_DEBUG_TX_CHAIN 0x00010 +#define ARLAN_DEBUG_MULTICAST 0x00020 +#define ARLAN_DEBUG_HEADER_DUMP 0x00040 +#define ARLAN_DEBUG_INTERRUPT 0x00080 +#define ARLAN_DEBUG_STARTUP 0x00100 +#define ARLAN_DEBUG_SHUTDOWN 0x00200 + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/bagetlance.c linux.ac/drivers/net/bagetlance.c --- linux.vanilla/drivers/net/bagetlance.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/bagetlance.c Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/com90xx.c linux.ac/drivers/net/com90xx.c --- linux.vanilla/drivers/net/com90xx.c Sun Nov 8 15:07:30 1998 +++ linux.ac/drivers/net/com90xx.c Sat Jul 3 20:32:15 1999 @@ -399,7 +399,7 @@ */ airqmask = probe_irq_on(); AINTMASK(NORXflag); - udelay(1); + mdelay(1); AINTMASK(0); airq = probe_irq_off(airqmask); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/de4x5.c linux.ac/drivers/net/de4x5.c --- linux.vanilla/drivers/net/de4x5.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/net/de4x5.c Mon Jul 5 05:05:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/declance.c linux.ac/drivers/net/declance.c --- linux.vanilla/drivers/net/declance.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/declance.c Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/depca.c linux.ac/drivers/net/depca.c --- linux.vanilla/drivers/net/depca.c Thu Dec 3 13:48:35 1998 +++ linux.ac/drivers/net/depca.c Mon Jul 5 05:05:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eepro100.c linux.ac/drivers/net/eepro100.c --- linux.vanilla/drivers/net/eepro100.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/net/eepro100.c Thu Jun 17 16:15:34 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/eql.c linux.ac/drivers/net/eql.c --- linux.vanilla/drivers/net/eql.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/net/eql.c Mon Jul 5 05:05:21 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ewrk3.c linux.ac/drivers/net/ewrk3.c --- linux.vanilla/drivers/net/ewrk3.c Sun Nov 8 15:07:23 1998 +++ linux.ac/drivers/net/ewrk3.c Mon Jul 19 03:39:17 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/Config.in linux.ac/drivers/net/hamradio/Config.in --- linux.vanilla/drivers/net/hamradio/Config.in Thu Dec 31 18:10:42 1998 +++ linux.ac/drivers/net/hamradio/Config.in Thu Jul 8 22:22:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/Makefile linux.ac/drivers/net/hamradio/Makefile --- linux.vanilla/drivers/net/hamradio/Makefile Sun Nov 8 15:07:26 1998 +++ linux.ac/drivers/net/hamradio/Makefile Thu Jul 8 22:22:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/hdlcdrv.c linux.ac/drivers/net/hamradio/hdlcdrv.c --- linux.vanilla/drivers/net/hamradio/hdlcdrv.c Thu Dec 31 18:10:42 1998 +++ linux.ac/drivers/net/hamradio/hdlcdrv.c Mon Jul 19 19:48:19 1999 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/soundmodem/sm.h linux.ac/drivers/net/hamradio/soundmodem/sm.h --- linux.vanilla/drivers/net/hamradio/soundmodem/sm.h Sun Nov 8 15:07:27 1998 +++ linux.ac/drivers/net/hamradio/soundmodem/sm.h Mon Jul 19 21:36:02 1999 @@ -296,8 +296,6 @@ #ifdef __i386__ -#include - #define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC) /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/yam.c linux.ac/drivers/net/hamradio/yam.c --- linux.vanilla/drivers/net/hamradio/yam.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/hamradio/yam.c Thu Jul 8 22:22:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/yam1200.h linux.ac/drivers/net/hamradio/yam1200.h --- linux.vanilla/drivers/net/hamradio/yam1200.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/hamradio/yam1200.h Thu Jul 8 22:22:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hamradio/yam9600.h linux.ac/drivers/net/hamradio/yam9600.h --- linux.vanilla/drivers/net/hamradio/yam9600.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/hamradio/yam9600.h Thu Jul 8 22:22:16 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/hostess_sv11.c linux.ac/drivers/net/hostess_sv11.c --- linux.vanilla/drivers/net/hostess_sv11.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/net/hostess_sv11.c Wed Jun 30 00:25:59 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ibmtr.c linux.ac/drivers/net/ibmtr.c --- linux.vanilla/drivers/net/ibmtr.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/ibmtr.c Mon Jul 19 19:48:19 1999 @@ -138,11 +138,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/smc-ircc.c linux.ac/drivers/net/irda/smc-ircc.c --- linux.vanilla/drivers/net/irda/smc-ircc.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/irda/smc-ircc.c Mon Jul 19 19:48:19 1999 @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/toshoboe.c linux.ac/drivers/net/irda/toshoboe.c --- linux.vanilla/drivers/net/irda/toshoboe.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/irda/toshoboe.c Wed Jun 16 16:28:57 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/irda/uircc.c linux.ac/drivers/net/irda/uircc.c --- linux.vanilla/drivers/net/irda/uircc.c Tue Jun 15 16:49:49 1999 +++ linux.ac/drivers/net/irda/uircc.c Mon Jul 19 19:48:19 1999 @@ -36,8 +36,6 @@ #include #include #include -#include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/jazzsonic.c linux.ac/drivers/net/jazzsonic.c --- linux.vanilla/drivers/net/jazzsonic.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/jazzsonic.c Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lance.c linux.ac/drivers/net/lance.c --- linux.vanilla/drivers/net/lance.c Mon Dec 28 23:09:43 1998 +++ linux.ac/drivers/net/lance.c Mon Jul 5 15:49:54 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/lne390.c linux.ac/drivers/net/lne390.c --- linux.vanilla/drivers/net/lne390.c Tue Dec 22 23:19:46 1998 +++ linux.ac/drivers/net/lne390.c Mon Jul 19 03:45:43 1999 @@ -31,6 +31,7 @@ static const char *version = "lne390.c: Driver revision v0.99, 12/05/98\n"; +#include #include #include #include @@ -316,6 +317,15 @@ lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)hdr&3)!=0) + { + memcpy_fromio_g32a(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ + return; + } +#endif + memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ } @@ -331,6 +341,25 @@ { unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8); +#ifdef CONFIG_ALPHA_JENSEN + if (((long)skb->data&3)!=0) + { + if (xfer_start + count > dev->rmem_end) { + /* Packet wraps over end of ring buffer. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio_g32a(skb->data, xfer_start, semi_count); + count -= semi_count; + memcpy_fromio_g32a(skb->data + semi_count, dev->rmem_start, count); + } else { + /* Packet is in one chunk. */ + memcpy_fromio_g32a(skb->data, xfer_start, count); + } + return; + } +#endif + + /* printk("%s: lne390_block_input is called with unaligned buffer!\n", dev->name); */ + if (xfer_start + count > dev->rmem_end) { /* Packet wraps over end of ring buffer. */ int semi_count = dev->rmem_end - xfer_start; @@ -349,6 +378,15 @@ unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8); count = (count + 3) & ~3; /* Round up to doubleword */ + /* printk ("%s: lne390_block_output is called!", dev->name); */ + +#ifdef CONFIG_ALPHA_JENSEN + if (((long)buf&3)!=0) { + memcpy_toio_g32a(shmem, buf, count); + return; + } +#endif + memcpy_toio(shmem, buf, count); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ne2k-pci.c linux.ac/drivers/net/ne2k-pci.c --- linux.vanilla/drivers/net/ne2k-pci.c Tue Jan 26 09:44:21 1999 +++ linux.ac/drivers/net/ne2k-pci.c Wed Jun 23 03:06:35 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/net_init.c linux.ac/drivers/net/net_init.c --- linux.vanilla/drivers/net/net_init.c Wed Apr 28 19:14:27 1999 +++ linux.ac/drivers/net/net_init.c Mon Jul 5 04:33:02 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/olympic.c linux.ac/drivers/net/olympic.c --- linux.vanilla/drivers/net/olympic.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/olympic.c Mon Jul 19 19:48:19 1999 @@ -0,0 +1,1661 @@ +/* + * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic + * chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their + * assistance and perserverance with the testing of this driver. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * 4/27/99 - Alpha Release 0.1.0 + * First release to the public + * + * 6/8/99 - Official Release 0.2.0 + * Merged into the kernel code + * + * To Do: + * + * Sanitize for smp + * + * If Problems do Occur + * Most problems can be rectified by either closing and opening the interface + * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult + * if compiled into the kernel). + */ + +/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */ + +#define OLYMPIC_DEBUG 0 + +/* Change OLYMPIC_NETWORK_MONITOR to receive mac frames through the arb channel. + * Will also create a /proc/net/olympic_tr entry if proc_fs is compiled into the + * kernel. + * Intended to be used to create a ring-error reporting network module + * i.e. it will give you the source address of beaconers on the ring + */ + +#define OLYMPIC_NETWORK_MONITOR 0 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "olympic.h" + +/* I've got to put some intelligence into the version number so that Peter and I know + * which version of the code somebody has got. + * Version Number = a.b.c.d where a.b.c is the level of code and d is the latest author. + * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike + * + * Official releases will only have an a.b.c version number format. + */ + +static char *version = +"Olympic.c v0.2.0 6/8/99 - Peter De Schrijver & Mike Phillips" ; + +static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", + "Address Verification", "Neighbor Notification (Ring Poll)", + "Request Parameters","FDX Registration Request", + "FDX Duplicate Address Check", "Station registration Query Wait", + "Unknown stage"}; + +static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault", + "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing", + "Duplicate Node Address","Request Parameters","Remove Received", + "Reserved", "Reserved", "No Monitor Detected for RPL", + "Monitor Contention failer for RPL", "FDX Protocol Error"}; + +/* Module paramters */ + +/* Ring Speed 0,4,16,100 + * 0 = Autosense + * 4,16 = Selected speed only, no autosense + * This allows the card to be the first on the ring + * and become the active monitor. + * 100 = Nothing at present, 100mbps is autodetected + * if FDX is turned on. May be implemented in the future to + * fail if 100mpbs is not detected. + * + * WARNING: Some hubs will allow you to insert + * at the wrong speed + */ + +static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(ringspeed, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i"); + +/* Packet buffer size */ + +static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(pkt_buf_sz, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; + +/* Message Level */ + +static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; + +MODULE_PARM(message_level, "1-" __MODULE_STRING(OLYMPIC_MAX_ADAPTERS) "i") ; + +static int olympic_scan(struct device *dev); +static int olympic_init(struct device *dev); +static int olympic_open(struct device *dev); +static int olympic_xmit(struct sk_buff *skb, struct device *dev); +static int olympic_close(struct device *dev); +static void olympic_set_rx_mode(struct device *dev); +static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats * olympic_get_stats(struct device *dev); +static int olympic_set_mac_address(struct device *dev, void *addr) ; +static void olympic_arb_cmd(struct device *dev); +static int olympic_change_mtu(struct device *dev, int mtu); +static void olympic_srb_bh(struct device *dev) ; +static void olympic_asb_bh(struct device *dev) ; +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS +static int sprintf_info(char *buffer, struct device *dev) ; +#endif +#endif + +__initfunc(int olympic_probe(struct device *dev)) +{ + int cards_found; + + cards_found=olympic_scan(dev); + return cards_found ? 0 : -ENODEV; +} + +__initfunc(static int olympic_scan(struct device *dev)) +{ + struct pci_dev *pci_device = NULL ; + struct olympic_private *olympic_priv; + int card_no = 0 ; + if (pci_present()) { + + while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) { + + pci_set_master(pci_device); + + /* Check to see if io has been allocated, if so, we've already done this card, + so continue on the card discovery loop */ + + if (check_region(pci_device->base_address[0] & (~3), OLYMPIC_IO_SPACE)) { + card_no++ ; + continue ; + } + + olympic_priv=kmalloc(sizeof (struct olympic_private), GFP_KERNEL); + memset(olympic_priv, 0, sizeof(struct olympic_private)); +#ifndef MODULE + dev=init_trdev(dev, 0); +#endif + dev->priv=(void *)olympic_priv; +#if OLYMPIC_DEBUG + printk("pci_device: %p, dev:%p, dev->priv: %p\n", pci_device, dev, dev->priv); +#endif + dev->irq=pci_device->irq; + dev->base_addr=pci_device->base_address[0] & (~3); + dev->init=&olympic_init; + olympic_priv->olympic_mmio=ioremap(pci_device->base_address[1],256); + olympic_priv->olympic_lap=ioremap(pci_device->base_address[2],2048); + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) + olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; + else + olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; + + olympic_priv->olympic_ring_speed = ringspeed[card_no] ; + olympic_priv->olympic_message_level = message_level[card_no] ; + olympic_priv->olympic_multicast_set = 0 ; + + if(olympic_init(dev)==-1) { + unregister_netdevice(dev); + kfree(dev->priv); + return 0; + } + + dev->open=&olympic_open; + dev->hard_start_xmit=&olympic_xmit; + dev->change_mtu=&olympic_change_mtu; + + dev->stop=&olympic_close; + dev->do_ioctl=NULL; + dev->set_multicast_list=&olympic_set_rx_mode; + dev->get_stats=&olympic_get_stats ; + dev->set_mac_address=&olympic_set_mac_address ; + return 1; + } + } + return 0 ; +} + + +__initfunc(static int olympic_init(struct device *dev)) +{ + struct olympic_private *olympic_priv; + __u8 *olympic_mmio, *init_srb,*adapter_addr; + unsigned long t; + unsigned int uaa_addr; + + olympic_priv=(struct olympic_private *)dev->priv; + olympic_mmio=olympic_priv->olympic_mmio; + + printk("%s \n", version); + printk("%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n",dev->name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq); + + request_region(dev->base_addr, OLYMPIC_IO_SPACE, "olympic"); + writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL); + t=jiffies; + while((readl(olympic_priv->olympic_mmio+BCTL)) & BCTL_SOFTRESET) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); + release_region(dev->base_addr, OLYMPIC_IO_SPACE) ; + return -1; + } + } + +#if OLYMPIC_DEBUG + printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); + printk("GPR: %x\n",readw(olympic_mmio+GPR)); + printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK)); +#endif + /* Aaaahhh, You have got to be real careful setting GPR, the card + holds the previous values from flash memory, including autosense + and ring speed */ + + writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL); + + if (olympic_priv->olympic_ring_speed == 0) { /* Autosense */ + writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR); + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Ringspeed autosense mode on\n",dev->name); + } else if (olympic_priv->olympic_ring_speed == 16) { + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", dev->name); + writel(GPR_16MBPS, olympic_mmio+GPR); + } else if (olympic_priv->olympic_ring_speed == 4) { + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", dev->name) ; + writel(0, olympic_mmio+GPR); + } + + writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR); + +#if OLYMPIC_DEBUG + printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; +#endif + /* start solo init */ + writel((1<<15),olympic_mmio+SISR_MASK_SUM); + + t=jiffies; + while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) { + schedule(); + if(jiffies-t > 40*HZ) { + printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); + release_region(dev->base_addr, OLYMPIC_IO_SPACE); + return -1; + } + } + + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + +#if OLYMPIC_DEBUG + printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); +#endif + + init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800)); + +#if OLYMPIC_DEBUG +{ + int i; + printk("init_srb(%p): ",init_srb); + for(i=0;i<20;i++) + printk("%x ",readb(init_srb+i)); + printk("\n"); +} +#endif + if(readw(init_srb+6)) { + printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",readw(init_srb+6)); + release_region(dev->base_addr, OLYMPIC_IO_SPACE); + return -1; + } + + uaa_addr=ntohs(readw(init_srb+8)); + +#if OLYMPIC_DEBUG + printk("UAA resides at %x\n",uaa_addr); +#endif + + writel(uaa_addr,olympic_mmio+LAPA); + adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800)); + +#if OLYMPIC_DEBUG + printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n", + readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2), + readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5)); +#endif + + memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); + + olympic_priv->olympic_addr_table_addr = ntohs(readw(init_srb + 12)) ; + olympic_priv->olympic_parms_addr = ntohs(readw(init_srb + 14)) ; + + return 0; + +} + +static int olympic_open(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; + unsigned long flags; + char open_error[255] ; + int i, open_finished = 1 ; + +#if OLYMPIC_NETWORK_MONITOR + __u8 *oat ; + __u8 *opt ; +#endif + + if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { + return -EAGAIN; + } + +#if OLYMPIC_DEBUG + printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); + printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR)); +#endif + + writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); + + writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */ + + writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */ + + /* adapter is closed, so SRB is pointed to by LAPWWO */ + + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800)); + +#if OLYMPIC_DEBUG + printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); + printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK)); + printk("Before the open command \n"); +#endif + do { + int i; + + save_flags(flags); + cli(); + for(i=0;iolympic_laa[0]) { + writeb(olympic_priv->olympic_laa[0],init_srb+12); + writeb(olympic_priv->olympic_laa[1],init_srb+13); + writeb(olympic_priv->olympic_laa[2],init_srb+14); + writeb(olympic_priv->olympic_laa[3],init_srb+15); + writeb(olympic_priv->olympic_laa[4],init_srb+16); + writeb(olympic_priv->olympic_laa[5],init_srb+17); + memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; + } + writeb(1,init_srb+30); + + olympic_priv->srb_queued=1; + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + while(olympic_priv->srb_queued) { + interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ); + if(signal_pending(current)) { + printk(KERN_WARNING "%s: SRB timed out.\n", + dev->name); + printk(KERN_WARNING "SISR=%x MISR=%x\n", + readl(olympic_mmio+SISR), + readl(olympic_mmio+LISR)); + olympic_priv->srb_queued=0; + break; + } + } + restore_flags(flags); +#if OLYMPIC_DEBUG + printk("init_srb(%p): ",init_srb); + for(i=0;i<20;i++) + printk("%x ",readb(init_srb+i)); + printk("\n"); +#endif + + /* If we get the same return response as we set, the interrupt wasn't raised and the open + * timed out. + */ + + if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) { + printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; + return -EIO ; + } + + if(readb(init_srb+2)!=0) { + if (readb(init_srb+2) == 0x07) { + if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */ + printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); + open_finished = 0 ; + } else { + + strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; + strcat(open_error," - ") ; + strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ; + + if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { + printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name); + printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name); + free_irq(dev->irq, dev); + return -EIO ; + } + + printk(KERN_WARNING "%s: %s\n",dev->name,open_error); + free_irq(dev->irq,dev) ; + return -EIO ; + + } /* if autosense && open_finished */ + } else { + printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]); + free_irq(dev->irq, dev); + return -EIO; + } + } else + open_finished = 1 ; + } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ + + if (readb(init_srb+18) & (1<<3)) + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name); + + if (readb(init_srb+18) & (1<<1)) + olympic_priv->olympic_ring_speed = 100 ; + else if (readb(init_srb+18) & 1) + olympic_priv->olympic_ring_speed = 16 ; + else + olympic_priv->olympic_ring_speed = 4 ; + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); + + olympic_priv->asb=ntohs(readw(init_srb+8)); + olympic_priv->srb=ntohs(readw(init_srb+10)); + olympic_priv->arb=ntohs(readw(init_srb+12)); + olympic_priv->trb=ntohs(readw(init_srb+16)); + + olympic_priv->olympic_receive_options = 0x01 ; + olympic_priv->olympic_copy_all_options = 0 ; + + /* setup rx ring */ + + writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ + + writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */ + + for(i=0;ipkt_buf_sz); + if(skb == NULL) + break; + + skb->dev = dev; + + olympic_priv->olympic_rx_ring[i].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_rx_ring[i].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->rx_ring_skb[i]=skb; + } + + if (i==0) { + printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); + free_irq(dev->irq, dev); + return -EIO; + } + + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXDESCQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]),olympic_mmio+RXCDA); + writew(i,olympic_mmio+RXDESCQCNT); + + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXSTATQ); + writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]),olympic_mmio+RXCSA); + + olympic_priv->rx_ring_last_received=OLYMPIC_RX_RING_SIZE-1; /* last processed rx status */ + olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE-1; + + writew(i,olympic_mmio+RXSTATQCNT); + +#if OLYMPIC_DEBUG + printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); + printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); + printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) ); + printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) ); + printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); + + printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]); +#endif + + writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ); + +#if OLYMPIC_DEBUG + printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); + printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); + printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]); +#endif + + writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM); + + /* setup tx ring */ + + writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ + for(i=0;iolympic_tx_ring[i].buffer=0xdeadbeef; + + olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXDESCQ_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]),olympic_mmio+TXCDA_1); + writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXDESCQCNT_1); + + writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1); + writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1); + writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1); + + olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ + olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ + + writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM); + +#if OLYMPIC_DEBUG + printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); + printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK)); +#endif + +#if OLYMPIC_NETWORK_MONITOR + oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + + printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5)); + printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); + + printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5)); + + +#endif + + dev->start = 1; + dev->interrupt=0; + dev->tbusy=0; + + MOD_INC_USE_COUNT ; + return 0; + +} + +/* + * When we enter the rx routine we do not know how many frames have been + * queued on the rx channel. Therefore we start at the next rx status + * position and travel around the receive ring until we have completed + * all the frames. + * + * This means that we may process the frame before we receive the end + * of frame interrupt. This is why we always test the status instead + * of blindly processing the next frame. + * + */ +static void olympic_rx(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + struct olympic_rx_status *rx_status; + struct olympic_rx_desc *rx_desc ; + int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; + struct sk_buff *skb, *skb2; + int i; + + rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; + + while (rx_status->status_buffercnt) { + + olympic_priv->rx_status_last_received++ ; + olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1); +#if OLYMPIC_DEBUG + printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); + printk("rx status: %x rx len: %x \n",rx_status->status_buffercnt,rx_status->fragmentcnt_framelen); +#endif + length=rx_status->fragmentcnt_framelen & 0xffff; + buffer_cnt = rx_status->status_buffercnt & 0xffff ; + i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ + frag_len = rx_status->fragmentcnt_framelen >> 16 ; + +#if OLYMPIC_DEBUG + printk("length: %x, frag_len: %x, buffer_cnt: %x\n",length,frag_len,buffer_cnt); +#endif + + if(rx_status->status_buffercnt & 0xC0000000) { + if (rx_status->status_buffercnt & 0x3B000000) { + if (olympic_priv->olympic_message_level) { + if (rx_status->status_buffercnt & (1<<29)) /* Rx Frame Truncated */ + printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name); + if (rx_status->status_buffercnt & (1<<28)) /*Rx receive overrun */ + printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name); + if (rx_status->status_buffercnt & (1<<27)) /* No receive buffers */ + printk(KERN_WARNING "%s: No receive buffers \n",dev->name); + if (rx_status->status_buffercnt & (1<<25)) /* Receive frame error detect */ + printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name); + if (rx_status->status_buffercnt & (1<<24)) /* Received Error Detect */ + printk(KERN_WARNING "%s: Received Error Detect \n",dev->name); + } + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; + olympic_priv->olympic_stats.rx_errors++; + } else { + + if (buffer_cnt == 1) { + skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; + } else { + skb = dev_alloc_skb(length) ; + } + + if (skb == NULL) { + printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ; + olympic_priv->olympic_stats.rx_dropped++ ; + /* Update counters even though we don't transfer the frame */ + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; + } else { + skb->dev = dev ; + + /* Optimise based upon number of buffers used. + If only one buffer is used we can simply swap the buffers around. + If more than one then we must use the new buffer and copy the information + first. Ideally all frames would be in a single buffer, this can be tuned by + altering the buffer size. */ + + if (buffer_cnt==1) { + olympic_priv->rx_ring_last_received++ ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); + rx_ring_last_received = olympic_priv->rx_ring_last_received ; + skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; + skb_put(skb2,length); + skb2->protocol = tr_type_trans(skb2,dev); + olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = olympic_priv->pkt_buf_sz ; + olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; + netif_rx(skb2) ; + } else { + do { /* Walk the buffers */ + olympic_priv->rx_ring_last_received++ ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); + rx_ring_last_received = olympic_priv->rx_ring_last_received ; + rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); + cpy_length = (i == 1 ? frag_len : rx_desc->res_length); + memcpy(skb_put(skb, cpy_length), bus_to_virt(rx_desc->buffer), cpy_length) ; + } while (--i) ; + + skb->protocol = tr_type_trans(skb,dev); + netif_rx(skb) ; + } + olympic_priv->olympic_stats.rx_packets++ ; + olympic_priv->olympic_stats.rx_bytes += length ; + } /* if skb == null */ + } /* If status & 0x3b */ + + } else { /*if buffercnt & 0xC */ + olympic_priv->rx_ring_last_received += i ; + olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; + } + + rx_status->fragmentcnt_framelen = 0 ; + rx_status->status_buffercnt = 0 ; + rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]); + + writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | buffer_cnt , olympic_mmio+RXENQ); + } /* while */ + +} + +static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev= (struct device *)dev_id; + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + __u32 sisr; + __u8 *adapter_check_area ; + + sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ + + if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ + return ; + + if (dev->interrupt) + printk(KERN_WARNING "%s: Re-entering interrupt \n",dev->name) ; + + dev->interrupt = 1 ; + + if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | + SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) { + + if(sisr & SISR_SRB_REPLY) { + if(olympic_priv->srb_queued==1) { + wake_up_interruptible(&olympic_priv->srb_wait); + } else if (olympic_priv->srb_queued==2) { + olympic_srb_bh(dev) ; + } + olympic_priv->srb_queued=0; + } /* SISR_SRB_REPLY */ + + if (sisr & SISR_TX1_EOF) { + olympic_priv->tx_ring_last_status++; + olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1); + olympic_priv->free_tx_ring_entries++; + olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; + olympic_priv->olympic_stats.tx_packets++ ; + dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; + olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; + + if(dev->tbusy) { + dev->tbusy=0; + mark_bh(NET_BH); + } + } /* SISR_TX1_EOF */ + + if (sisr & SISR_RX_STATUS) { + olympic_rx(dev); + } /* SISR_RX_STATUS */ + + if (sisr & SISR_ADAPTER_CHECK) { + printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); + writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); + adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; + printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; + dev->interrupt = 0 ; + free_irq(dev->irq, dev) ; + + } /* SISR_ADAPTER_CHECK */ + + if (sisr & SISR_ASB_FREE) { + /* Wake up anything that is waiting for the asb response */ + if (olympic_priv->asb_queued) { + olympic_asb_bh(dev) ; + } + } /* SISR_ASB_FREE */ + + if (sisr & SISR_ARB_CMD) { + olympic_arb_cmd(dev) ; + } /* SISR_ARB_CMD */ + + if (sisr & SISR_TRB_REPLY) { + /* Wake up anything that is waiting for the trb response */ + if (olympic_priv->trb_queued) { + wake_up_interruptible(&olympic_priv->trb_wait); + } + olympic_priv->trb_queued = 0 ; + } /* SISR_TRB_REPLY */ + + if (sisr & SISR_RX_NOBUF) { + /* According to the documentation, we don't have to do anything, but trapping it keeps it out of + /var/log/messages. */ + } /* SISR_RX_NOBUF */ + } else { + printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr); + printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ; + } /* One if the interrupts we want */ + + dev->interrupt = 0 ; + + writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); + +} + +static int olympic_xmit(struct sk_buff *skb, struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + return 1; + } + + if(olympic_priv->free_tx_ring_entries) { + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer=virt_to_bus(skb->data); + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length=skb->len | (0x80000000); + olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb; + olympic_priv->free_tx_ring_entries--; + + olympic_priv->tx_ring_free++; + olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1); + + + writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); + + dev->tbusy=0; + + return 0; + } else + return 1; + +} + + +static int olympic_close(struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; + unsigned long flags; + int i; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + + writeb(SRB_CLOSE_ADAPTER,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + + save_flags(flags); + cli(); + + olympic_priv->srb_queued=1; + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + while(olympic_priv->srb_queued) { + interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ); + if(signal_pending(current)) { + printk(KERN_WARNING "%s: SRB timed out.\n", + dev->name); + printk(KERN_WARNING "SISR=%x MISR=%x\n", + readl(olympic_mmio+SISR), + readl(olympic_mmio+LISR)); + olympic_priv->srb_queued=0; + break; + } + } + + restore_flags(flags) ; + olympic_priv->rx_status_last_received++; + olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; + + for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received]); + olympic_priv->rx_status_last_received++; + olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; + } + + /* reset tx/rx fifo's and busmaster logic */ + + writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); + udelay(1); + writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); + +#if OLYMPIC_DEBUG + printk("srb(%p): ",srb); + for(i=0;i<4;i++) + printk("%x ",readb(srb+i)); + printk("\n"); +#endif + dev->start = 0; + free_irq(dev->irq,dev); + + MOD_DEC_USE_COUNT ; + return 0; + +} + +static void olympic_set_rx_mode(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *olympic_mmio = olympic_priv->olympic_mmio ; + __u8 options = 0, set_mc_list = 0 ; + __u8 *srb, *ata ; + struct dev_mc_list *dmi ; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + options = olympic_priv->olympic_copy_all_options; + + if (dev->flags&IFF_PROMISC) + options |= (3<<5) ; /* All LLC and MAC frames, all through the main rx channel */ + else + options &= ~(3<<5) ; + + if (dev->mc_count) { + set_mc_list = 1 ; + } + + /* Only issue the srb if there is a change in options */ + + if ((options ^ olympic_priv->olympic_copy_all_options)) { + + /* Now to issue the srb command to alter the copy.all.options */ + + writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(olympic_priv->olympic_receive_options,srb+4); + writeb(options,srb+5); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_copy_all_options = options ; + + return ; + } + + if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */ + + dmi = dev->mc_list ; + + if (set_mc_list) { /* Turn multicast on */ + + /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00 + * We do this with a set functional address mask. + */ + + ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ; + if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */ + writeb(SRB_SET_FUNC_ADDRESS,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + writeb(readb(ata+10),srb+6); + writeb(readb(ata+11)|4,srb+7); + writeb(readb(ata+12),srb+8); + writeb(readb(ata+13),srb+9); + + olympic_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_multicast_set = 1 ; + } + + + } else { /* Turn multicast off */ + + ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ; + if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */ + writeb(SRB_SET_FUNC_ADDRESS,srb+0); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + writeb(readb(ata+10),srb+6); + writeb(readb(ata+11) & ~4,srb+7); + writeb(readb(ata+12),srb+8); + writeb(readb(ata+13),srb+9); + + olympic_priv->srb_queued = 2 ; + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + olympic_priv->olympic_multicast_set = 0 ; + } + } + + } + + +} + +static void olympic_srb_bh(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *olympic_mmio = olympic_priv->olympic_mmio ; + __u8 *srb; + + writel(olympic_priv->srb,olympic_mmio+LAPA); + srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); + + switch (readb(srb)) { + + /* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) + * At some point we should do something if we get an error, such as + * resetting the IFF_PROMISC flag in dev + */ + + case SRB_MODIFY_RECEIVE_OPTIONS: + switch (readb(srb+2)) { + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); + break ; + default: + if (olympic_priv->olympic_message_level) + printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; + break ; + } /* switch srb[2] */ + break ; + + /* SRB_SET_GROUP_ADDRESS - Multicast group setting + */ + + case SRB_SET_GROUP_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + olympic_priv->olympic_multicast_set = 1 ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); + break ; + case 0x3c: + printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; + break ; + case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */ + printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; + break ; + case 0x55: + printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list + */ + + case SRB_RESET_GROUP_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + olympic_priv->olympic_multicast_set = 0 ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + case 0x39: /* Must deal with this if individual multicast addresses used */ + printk(KERN_INFO "%s: Group address not found \n",dev->name); + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + + /* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode + */ + + case SRB_SET_FUNC_ADDRESS: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + /* SRB_READ_LOG - Read and reset the adapter error counters + */ + + case SRB_READ_LOG: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + + } /* switch srb[2] */ + break ; + + /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ + + case SRB_READ_SR_COUNTERS: + switch (readb(srb+2)) { + case 0x00: + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; + break ; + case 0x01: + printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; + break ; + case 0x04: + printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; + break ; + default: + break ; + } /* switch srb[2] */ + break ; + + default: + printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name); + break ; + } /* switch srb[0] */ + +} + +static struct net_device_stats * olympic_get_stats(struct device *dev) +{ + struct olympic_private *olympic_priv ; + olympic_priv=(struct olympic_private *) dev->priv; + return (struct net_device_stats *) &olympic_priv->olympic_stats; +} + +static int olympic_set_mac_address (struct device *dev, void *addr) +{ + struct sockaddr *saddr = addr ; + struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; + + if (dev->start) { + printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; + return -EIO ; + } + + memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; + + if (olympic_priv->olympic_message_level) { + printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0], + olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2], + olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4], + olympic_priv->olympic_laa[5]); + } + + return 0 ; +} + +static void olympic_arb_cmd(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + __u8 *olympic_mmio=olympic_priv->olympic_mmio; + __u8 *arb_block, *asb_block, *srb ; + __u8 header_len ; + __u16 frame_len, buffer_len ; + struct sk_buff *mac_frame ; + __u8 *buf_ptr ; + __u8 *frame_data ; + __u16 buff_off ; + __u16 lan_status = 0, lan_status_diff ; /* Initialize to stop compiler warning */ + __u8 fdx_prot_error ; + __u16 next_ptr; + +#if OLYMPIC_NETWORK_MONITOR + struct trh_hdr *mac_hdr ; +#endif + + arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + srb = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; + writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO); + + if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ + + header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */ + frame_len = ntohs(readw(arb_block + 10)) ; + + buff_off = ntohs(readw(arb_block + 6)) ; + + buf_ptr = olympic_priv->olympic_lap + buff_off ; + +#if OLYMPIC_DEBUG +{ + int i; + frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; + + for (i=0 ; i < 14 ; i++) { + printk("Loc %d = %02x\n",i,readb(frame_data + i)); + } + + printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); +} +#endif + mac_frame = dev_alloc_skb(frame_len) ; + + /* Walk the buffer chain, creating the frame */ + + do { + frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; + buffer_len = ntohs(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); + memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ; + next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); + + } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr))); + +#if OLYMPIC_NETWORK_MONITOR + printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ; + mac_hdr = (struct trh_hdr *)mac_frame->data ; + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; +#endif + mac_frame->dev = dev ; + mac_frame->protocol = tr_type_trans(mac_frame,dev); + netif_rx(mac_frame) ; + + /* Now tell the card we have dealt with the received frame */ + + /* Set LISR Bit 1 */ + writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM); + + /* Is the ASB free ? */ + + if (!(readl(olympic_priv->olympic_mmio + SISR) & SISR_ASB_FREE)) { + olympic_priv->asb_queued = 1 ; + writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + return ; + /* Drop out and wait for the bottom half to be run */ + } + + writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ + writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ + writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ + writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ + + writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + + olympic_priv->asb_queued = 2 ; + + return ; + + } else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ + lan_status = readw(arb_block+6); + fdx_prot_error = readb(arb_block+8) ; + + /* Issue ARB Free */ + writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM); + + lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; + + if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { + if (lan_status_diff & LSC_LWF) + printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); + if (lan_status_diff & LSC_ARW) + printk(KERN_WARNING "%s: Auto removal error\n",dev->name); + if (lan_status_diff & LSC_FPE) + printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); + if (lan_status_diff & LSC_RR) + printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); + + /* Adapter has been closed by the hardware */ + + /* reset tx/rx fifo's and busmaster logic */ + + writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); + udelay(1); + writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); + dev->tbusy = 1 ; + dev->interrupt = 1 ; + dev->start = 0 ; + olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; + free_irq(dev->irq,dev); + + printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; + + } /* If serious error */ + + if (olympic_priv->olympic_message_level) { + if (lan_status_diff & LSC_SIG_LOSS) + printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; + if (lan_status_diff & LSC_HARD_ERR) + printk(KERN_INFO "%s: Beaconing \n",dev->name); + if (lan_status_diff & LSC_SOFT_ERR) + printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name); + if (lan_status_diff & LSC_TRAN_BCN) + printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + if (lan_status_diff & LSC_SS) + printk(KERN_INFO "%s: Single Station on the ring \n", dev->name); + if (lan_status_diff & LSC_RING_REC) + printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); + if (lan_status_diff & LSC_FDX_MODE) + printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); + } + + if (lan_status_diff & LSC_CO) { + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Counter Overflow \n", dev->name); + + /* Issue READ.LOG command */ + + writeb(SRB_READ_LOG, srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + writeb(0,srb+4); + writeb(0,srb+5); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + } + + if (lan_status_diff & LSC_SR_CO) { + + if (olympic_priv->olympic_message_level) + printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); + + /* Issue a READ.SR.COUNTERS */ + + writeb(SRB_READ_SR_COUNTERS,srb); + writeb(0,srb+1); + writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); + writeb(0,srb+3); + + olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ + + writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); + + } + + olympic_priv->olympic_lan_status = lan_status ; + + } /* Lan.change.status */ + else + printk(KERN_WARNING "%s: Unknown arb command \n", dev->name); +} + +static void olympic_asb_bh(struct device *dev) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; + __u8 *arb_block, *asb_block ; + + arb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; + asb_block = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; + + if (olympic_priv->asb_queued == 1) { /* Dropped through the first time */ + + writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ + writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ + writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ + writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ + + writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); + olympic_priv->asb_queued = 2 ; + + return ; + } + + if (olympic_priv->asb_queued == 2) { + switch (readb(asb_block+2)) { + case 0x01: + printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name); + break ; + case 0x26: + printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name); + break ; + case 0xFF: + /* Valid response, everything should be ok again */ + break ; + default: + printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name); + break ; + } + } + olympic_priv->asb_queued = 0 ; +} + +static int olympic_change_mtu(struct device *dev, int mtu) +{ + struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv; + __u16 max_mtu ; + + if (olympic_priv->olympic_ring_speed == 4) + max_mtu = 4500 ; + else + max_mtu = 18000 ; + + if (mtu > max_mtu) + return -EINVAL ; + if (mtu < 100) + return -EINVAL ; + + dev->mtu = mtu ; + olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; + + return 0 ; +} + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS +static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + struct pci_dev *pci_device = NULL ; + int len=0; + off_t begin=0; + off_t pos=0; + int size; + + struct device *dev; + + + size = sprintf(buffer, + "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapters\n"); + + pos+=size; + len+=size; + + + while((pci_device=pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, pci_device))) { + + for (dev = dev_base; dev != NULL; dev = dev->next) + { + if (dev->base_addr == (pci_device->base_address[0] & (~3)) ) { /* Yep, an Olympic device */ + size = sprintf_info(buffer+len, dev); + len+=size; + pos=begin+len; + + if(posoffset+length) + break; + } /* if */ + } /* for */ + } /* While */ + + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Start slop */ + if(len>length) + len=length; /* Ending slop */ + return len; +} + +static int sprintf_info(char *buffer, struct device *dev) +{ + struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; + __u8 *oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; + __u8 *opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; + int size = 0 ; + + size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", + dev->name); + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n", + dev->name, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), + readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), + readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); + + size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name); + + size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n", + dev->name, + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); + + size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, + readb(opt+offsetof(struct olympic_parameters_table, source_addr)), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4), + readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, local_ring))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); + + size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", + dev->name) ; + + size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n", + dev->name, + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), + ntohs(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4), + readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), + readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3)); + + + return size; +} +#endif +#endif + +#ifdef MODULE + +static struct device* dev_olympic[OLYMPIC_MAX_ADAPTERS]; + +int init_module(void) +{ + int i; + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *ent ; + + ent = create_proc_entry("net/olympic_tr",0,0); + ent->read_proc = &olympic_proc_info ; +#endif +#endif + for (i = 0; (iinit = &olympic_probe; + + if (register_trdev(dev_olympic[i]) != 0) { + kfree_s(dev_olympic[i], sizeof(struct device)); + dev_olympic[i] = NULL; + if (i == 0) { + printk("Olympic: No IBM PCI Token Ring cards found in system.\n"); + return -EIO; + } else { + printk("Olympic: %d IBM PCI Token Ring card(s) found in system.\n",i) ; + return 0; + } + } + } + + return 0; +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < OLYMPIC_MAX_ADAPTERS; i++) + if (dev_olympic[i]) { + unregister_trdev(dev_olympic[i]); + release_region(dev_olympic[i]->base_addr, OLYMPIC_IO_SPACE); + kfree_s(dev_olympic[i]->priv, sizeof(struct olympic_private)); + kfree_s(dev_olympic[i], sizeof(struct device)); + dev_olympic[i] = NULL; + } + +#if OLYMPIC_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + remove_proc_entry("net/olympic_tr", NULL) ; +#endif +#endif +} +#endif /* MODULE */ + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/olympic.h linux.ac/drivers/net/olympic.h --- linux.vanilla/drivers/net/olympic.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/olympic.h Wed Jun 9 20:08:19 1999 @@ -0,0 +1,303 @@ +/* + * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved + * 1999 Mike Phillips (phillim@amtrak.com) + * + * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. + * + * Base Driver Skeleton: + * Written 1993-94 by Donald Becker. + * + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +#define CID 0x4e + +#define BCTL 0x70 +#define BCTL_SOFTRESET (1<<15) +#define BCTL_MIMREB (1<<6) + +#define GPR 0x4a +#define GPR_OPTI_BF (1<<6) +#define GPR_NEPTUNE_BF (1<<4) +#define GPR_AUTOSENSE (1<<2) +#define GPR_16MBPS (1<<3) + +#define PAG 0x85 +#define LBC 0x8e + +#define LISR 0x10 +#define LISR_SUM 0x14 +#define LISR_RWM 0x18 + +#define LISR_LIE (1<<15) +#define LISR_SLIM (1<<13) +#define LISR_SLI (1<<12) +#define LISR_PCMSRMASK (1<<11) +#define LISR_PCMSRINT (1<<10) +#define LISR_WOLMASK (1<<9) +#define LISR_WOL (1<<8) +#define LISR_SRB_CMD (1<<5) +#define LISR_ASB_REPLY (1<<4) +#define LISR_ASB_FREE_REQ (1<<2) +#define LISR_ARB_FREE (1<<1) +#define LISR_TRB_FRAME (1<<0) + +#define SISR 0x20 +#define SISR_SUM 0x24 +#define SISR_RWM 0x28 +#define SISR_RR 0x2C +#define SISR_RESMASK 0x30 +#define SISR_MASK 0x54 +#define SISR_MASK_SUM 0x58 +#define SISR_MASK_RWM 0x5C + +#define SISR_TX2_IDLE (1<<31) +#define SISR_TX2_HALT (1<<29) +#define SISR_TX2_EOF (1<<28) +#define SISR_TX1_IDLE (1<<27) +#define SISR_TX1_HALT (1<<25) +#define SISR_TX1_EOF (1<<24) +#define SISR_TIMEOUT (1<<23) +#define SISR_RX_NOBUF (1<<22) +#define SISR_RX_STATUS (1<<21) +#define SISR_RX_HALT (1<<18) +#define SISR_RX_EOF_EARLY (1<<16) +#define SISR_MI (1<<15) +#define SISR_PI (1<<13) +#define SISR_ERR (1<<9) +#define SISR_ADAPTER_CHECK (1<<6) +#define SISR_SRB_REPLY (1<<5) +#define SISR_ASB_FREE (1<<4) +#define SISR_ARB_CMD (1<<3) +#define SISR_TRB_REPLY (1<<2) + +#define EISR 0x34 +#define EISR_RWM 0x38 +#define EISR_MASK 0x3c + +#define LAPA 0x60 +#define LAPWWO 0x64 +#define LAPWWC 0x68 +#define LAPCTL 0x6C +#define LAIPD 0x78 +#define LAIPDDINC 0x7C + +#define TIMER 0x50 + +#define CLKCTL 0x74 + +#define PM_CON 0x4 + +#define BMCTL_SUM 0x40 +#define BMCTL_RWM 0x44 +#define BMCTL_TX2_DIS (1<<30) +#define BMCTL_TX1_DIS (1<<26) +#define BMCTL_RX_DIS (1<<22) + +#define BMASR 0xcc + +#define RXDESCQ 0x90 +#define RXDESCQCNT 0x94 +#define RXCDA 0x98 +#define RXENQ 0x9C +#define RXSTATQ 0xA0 +#define RXSTATQCNT 0xA4 +#define RXCSA 0xA8 +#define RXCLEN 0xAC +#define RXHLEN 0xAE + +#define TXDESCQ_1 0xb0 +#define TXDESCQ_2 0xd0 +#define TXDESCQCNT_1 0xb4 +#define TXDESCQCNT_2 0xd4 +#define TXCDA_1 0xb8 +#define TXCDA_2 0xd8 +#define TXENQ_1 0xbc +#define TXENQ_2 0xdc +#define TXSTATQ_1 0xc0 +#define TXSTATQ_2 0xe0 +#define TXSTATQCNT_1 0xc4 +#define TXSTATQCNT_2 0xe4 +#define TXCSA_1 0xc8 +#define TXCSA_2 0xe8 + +#define OLYMPIC_IO_SPACE 256 + +#define SRB_COMMAND_SIZE 50 + +#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ + +/* Defines for LAN STATUS CHANGE reports */ +#define LSC_SIG_LOSS 0x8000 +#define LSC_HARD_ERR 0x4000 +#define LSC_SOFT_ERR 0x2000 +#define LSC_TRAN_BCN 0x1000 +#define LSC_LWF 0x0800 +#define LSC_ARW 0x0400 +#define LSC_FPE 0x0200 +#define LSC_RR 0x0100 +#define LSC_CO 0x0080 +#define LSC_SS 0x0040 +#define LSC_RING_REC 0x0020 +#define LSC_SR_CO 0x0010 +#define LSC_FDX_MODE 0x0004 + +/* Defines for OPEN ADAPTER command */ + +#define OPEN_ADAPTER_EXT_WRAP (1<<15) +#define OPEN_ADAPTER_DIS_HARDEE (1<<14) +#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) +#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) +#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) +#define OPEN_ADAPTER_ENABLE_EC (1<<10) +#define OPEN_ADAPTER_CONTENDER (1<<8) +#define OPEN_ADAPTER_PASS_BEACON (1<<7) +#define OPEN_ADAPTER_ENABLE_FDX (1<<6) +#define OPEN_ADAPTER_ENABLE_RPL (1<<5) +#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) +#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) +#define OPEN_ADAPTER_USE_OPTS2 (1<<0) + +#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15) + +/* Defines for SRB Commands */ + +#define SRB_ACCESS_REGISTER 0x1f +#define SRB_CLOSE_ADAPTER 0x04 +#define SRB_CONFIGURE_BRIDGE 0x0c +#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a +#define SRB_MODIFY_BRIDGE_PARMS 0x15 +#define SRB_MODIFY_OPEN_OPTIONS 0x01 +#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 +#define SRB_NO_OPERATION 0x00 +#define SRB_OPEN_ADAPTER 0x03 +#define SRB_READ_LOG 0x08 +#define SRB_READ_SR_COUNTERS 0x16 +#define SRB_RESET_GROUP_ADDRESS 0x02 +#define SRB_SAVE_CONFIGURATION 0x1b +#define SRB_SET_BRIDGE_PARMS 0x09 +#define SRB_SET_BRIDGE_TARGETS 0x10 +#define SRB_SET_FUNC_ADDRESS 0x07 +#define SRB_SET_GROUP_ADDRESS 0x06 +#define SRB_SET_GROUP_ADDR_OPTIONS 0x11 +#define SRB_UPDATE_WAKEUP_PATTERN 0x19 + +/* Clear return code */ + +#define OLYMPIC_CLEAR_RET_CODE 0xfe + +/* ARB Commands */ +#define ARB_RECEIVE_DATA 0x81 +#define ARB_LAN_CHANGE_STATUS 0x84 +/* ASB Response commands */ + +#define ASB_RECEIVE_DATA 0x81 + + +/* Olympic defaults for buffers */ + +#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */ +#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */ + +#define PKT_BUF_SZ 4096 /* Default packet size */ + +/* Olympic data structures */ + +struct olympic_tx_desc { + __u32 buffer; + __u32 status_length; +}; + +struct olympic_tx_status { + __u32 status; +}; + +struct olympic_rx_desc { + __u32 buffer; + __u32 res_length ; +}; + +struct olympic_rx_status { + __u32 fragmentcnt_framelen; + __u32 status_buffercnt; +}; + +struct mac_receive_buffer { + __u16 next ; + __u8 padding ; + __u8 frame_status ; + __u16 buffer_length ; + __u8 frame_data ; +}; + +struct olympic_private { + + __u16 srb; + __u16 trb; + __u16 arb; + __u16 asb; + + __u8 *olympic_mmio; + __u8 *olympic_lap; + + volatile int srb_queued; /* True if an SRB is still posted */ + struct wait_queue *srb_wait; + + volatile int asb_queued; /* True if an ASB is posted */ + + volatile int trb_queued; /* True if a TRB is posted */ + struct wait_queue *trb_wait ; + + struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE]; + struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE]; + struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE]; + struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE]; + int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries; + + struct net_device_stats olympic_stats ; + __u16 olympic_lan_status ; + __u8 olympic_ring_speed ; + __u16 pkt_buf_sz ; + __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level; + __u8 olympic_multicast_set ; + __u16 olympic_addr_table_addr, olympic_parms_addr ; + __u8 olympic_laa[6] ; +}; + +struct olympic_adapter_addr_table { + + __u8 node_addr[6] ; + __u8 reserved[4] ; + __u8 func_addr[4] ; +} ; + +struct olympic_parameters_table { + + __u8 phys_addr[4] ; + __u8 up_node_addr[6] ; + __u8 up_phys_addr[6] ; + __u8 poll_addr[6] ; + __u16 reserved ; + __u16 acc_priority ; + __u16 auth_source_class ; + __u16 att_code ; + __u8 source_addr[6] ; + __u16 beacon_type ; + __u16 major_vector ; + __u16 lan_status ; + __u16 soft_error_time ; + __u16 reserved1 ; + __u16 local_ring ; + __u16 mon_error ; + __u16 beacon_transmit ; + __u16 beacon_receive ; + __u16 frame_correl ; + __u8 beacon_naun[6] ; + __u32 reserved2 ; + __u8 beacon_phys[4] ; +}; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/ppp.c linux.ac/drivers/net/ppp.c --- linux.vanilla/drivers/net/ppp.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/net/ppp.c Mon Jul 19 19:48:19 1999 @@ -60,7 +60,6 @@ #include #include #include -#include /* to get the struct task_struct */ #include /* used in new tty drivers */ #include /* used in new tty drivers */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/rtl8139.c linux.ac/drivers/net/rtl8139.c --- linux.vanilla/drivers/net/rtl8139.c Thu Dec 3 13:48:36 1998 +++ linux.ac/drivers/net/rtl8139.c Mon Jul 19 03:54:43 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sealevel.c linux.ac/drivers/net/sealevel.c --- linux.vanilla/drivers/net/sealevel.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/net/sealevel.c Fri Jun 4 23:52:39 1999 @@ -0,0 +1,471 @@ +#define LINUX_21 + +/* + * Sealevel Systems 4021 driver. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * (c) Copyright 1999 Building Number Three Ltd + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "syncppp.h" +#include "z85230.h" + + +struct slvl_device +{ + struct z8530_channel *chan; + struct ppp_device netdev; + char name[16]; + int channel; +}; + + +struct slvl_board +{ + struct slvl_device dev[2]; + struct z8530_dev board; + int iobase; +}; + +/* + * Network driver support routines + */ + +/* + * Frame receive. Simple for our card as we do sync ppp and there + * is no funny garbage involved + */ + +static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) +{ + /* Drop the CRC - its not a good idea to try and negotiate it ;) */ + skb_trim(skb, skb->len-2); + skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; + skb->dev=c->netdevice; + /* + * Send it to the PPP layer. We dont have time to process + * it right now. + */ + netif_rx(skb); +} + +/* + * We've been placed in the UP state + */ + +static int sealevel_open(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int err = -1; + int unit = slvl->channel; + + /* + * Link layer up. + */ + + switch(unit) + { + case 0: + err=z8530_sync_dma_open(d, slvl->chan); + break; + case 1: + err=z8530_sync_open(d, slvl->chan); + break; + } + + if(err) + return err; + /* + * Begin PPP + */ + err=sppp_open(d); + if(err) + { + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + return err; + } + + slvl->chan->rx_function=sealevel_input; + + /* + * Go go go + */ + d->tbusy=0; + MOD_INC_USE_COUNT; + return 0; +} + +static int sealevel_close(struct device *d) +{ + struct slvl_device *slvl=d->priv; + int unit = slvl->channel; + + /* + * Discard new frames + */ + + slvl->chan->rx_function=z8530_null_rx; + + /* + * PPP off + */ + sppp_close(d); + /* + * Link layer down + */ + d->tbusy=1; + + switch(unit) + { + case 0: + z8530_sync_dma_close(d, slvl->chan); + break; + case 1: + z8530_sync_close(d, slvl->chan); + break; + } + MOD_DEC_USE_COUNT; + return 0; +} + +static int sealevel_ioctl(struct device *d, struct ifreq *ifr, int cmd) +{ + /* struct slvl_device *slvl=d->priv; + z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ + return sppp_do_ioctl(d, ifr,cmd); +} + +static struct enet_statistics *sealevel_get_stats(struct device *d) +{ + struct slvl_device *slvl=d->priv; + if(slvl) + return z8530_get_stats(slvl->chan); + else + return NULL; +} + +/* + * Passed PPP frames, fire them downwind. + */ + +static int sealevel_queue_xmit(struct sk_buff *skb, struct device *d) +{ + struct slvl_device *slvl=d->priv; + return z8530_queue_xmit(slvl->chan, skb); +} + +#ifdef LINUX_21 +static int sealevel_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int sealevel_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = sealevel_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} + +#else + +static int return_0(struct device *d) +{ + return 0; +} + +#endif + +/* + * Description block for a Comtrol Hostess SV11 card + */ + +static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, int slow) +{ + struct z8530_dev *dev; + struct slvl_device *sv; + struct slvl_board *b; + + int i; + unsigned long flags; + int u; + + /* + * Get the needed I/O space + */ + + if(check_region(iobase, 8)) + { + printk(KERN_WARNING "sealevel: I/O 0x%X already in use.\n", iobase); + return NULL; + } + request_region(iobase, 8, "Sealevel 4021"); + + b=(struct slvl_board *)kmalloc(sizeof(struct slvl_board), GFP_KERNEL); + if(!b) + goto fail3; + + memset(b, 0, sizeof(*sv)); + + b->dev[0].chan = &b->board.chanA; + b->dev[1].chan = &b->board.chanB; + + dev=&b->board; + + /* + * Stuff in the I/O addressing + */ + + dev->active = 0; + + b->iobase = iobase; + + /* + * Select 8530 delays for the old board + */ + + if(slow) + iobase |= Z8530_PORT_SLEEP; + + dev->chanA.ctrlio=iobase+1; + dev->chanA.dataio=iobase; + dev->chanB.ctrlio=iobase+3; + dev->chanB.dataio=iobase+2; + + dev->chanA.irqs=&z8530_nop; + dev->chanB.irqs=&z8530_nop; + + /* + * Assert DTR enable DMA + */ + + outb(3|(1<<7), b->iobase+4); + + + /* We want a fast IRQ for this device. Actually we'd like an even faster + IRQ ;) - This is one driver RtLinux is made for */ + + if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0) + { + printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); + goto fail2; + } + + dev->irq=irq; + dev->chanA.private=&b->dev[0]; + dev->chanB.private=&b->dev[1]; + dev->chanA.netdevice=&b->dev[0].netdev.dev; + dev->chanB.netdevice=&b->dev[1].netdev.dev; + dev->chanA.dev=dev; + dev->chanB.dev=dev; + dev->name=b->dev[0].name; + + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + if(request_dma(dev->chanA.txdma, "SeaLevel (TX)")!=0) + goto fail; + + if(request_dma(dev->chanA.rxdma, "SeaLevel (RX)")!=0) + goto dmafail; + + save_flags(flags); + cli(); + + /* + * Begin normal initialise + */ + + if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); + goto dmafail2; + } + if(dev->type==Z85C30) + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); + } + else + { + z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); + z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); + } + + /* + * Now we can take the IRQ + */ + + restore_flags(flags); + + for(u=0; u<2; u++) + { + sv=&b->dev[u]; + sv->channel = u; + + for(i=0;i<999;i++) + { + sprintf(sv->name,"hdlc%d", i); + if(dev_get(sv->name)==NULL) + { + struct device *d=sv->chan->netdevice; + + /* + * Initialise the PPP components + */ + sppp_attach(&sv->netdev); + + /* + * Local fields + */ + sprintf(sv->name,"hdlc%d", i); + + d->name = sv->name; + d->base_addr = iobase; + d->irq = irq; + d->priv = sv; + d->init = NULL; + + d->open = sealevel_open; + d->stop = sealevel_close; + d->hard_start_xmit = sealevel_queue_xmit; + d->get_stats = sealevel_get_stats; + d->set_multicast_list = NULL; + d->do_ioctl = sealevel_ioctl; +#ifdef LINUX_21 + d->neigh_setup = sealevel_neigh_setup_dev; + dev_init_buffers(d); +#else + d->init = return_0; +#endif + d->set_mac_address = NULL; + + if(register_netdev(d)==-1) + { + printk(KERN_ERR "%s: unable to register device.\n", + sv->name); + goto fail_unit; + } + + break; + } + } + } + z8530_describe(dev, "I/O", iobase); + dev->active=1; + return b; + +fail_unit: + if(u==1) + unregister_netdev(b->dev[0].chan->netdevice); + +dmafail2: + free_dma(dev->chanA.rxdma); +dmafail: + free_dma(dev->chanA.txdma); +fail: + free_irq(irq, dev); +fail2: + kfree(b); +fail3: + release_region(iobase,8); + return NULL; +} + +static void slvl_shutdown(struct slvl_board *b) +{ + int u; + + z8530_shutdown(&b->board); + + for(u=0; u<2; u++) + { + sppp_detach(&b->dev[u].netdev.dev); + unregister_netdev(&b->dev[u].netdev.dev); + } + + free_irq(b->board.irq, &b->board); + free_dma(b->board.chanA.rxdma); + free_dma(b->board.chanA.txdma); + /* DMA off on the card, drop DTR */ + outb(0, b->iobase); + release_region(b->iobase, 8); +} + +#ifdef MODULE + +static int io=0x238; +static int txdma=1; +static int rxdma=3; +static int irq=5; +static int slow=0; + +#ifdef LINUX_21 +MODULE_PARM(io,"i"); +MODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); +MODULE_PARM(txdma,"i"); +MODULE_PARM_DESC(txdma, "Transmit DMA channel"); +MODULE_PARM(rxdma,"i"); +MODULE_PARM_DESC(rxdma, "Receive DMA channel"); +MODULE_PARM(irq,"i"); +MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); +MODULE_PARM(slow,"i"); +MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); + +MODULE_AUTHOR("Bulding Number Three Ltd"); +MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); +#endif + +static struct slvl_board *slvl_unit; + +int init_module(void) +{ + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); + if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) + return -ENODEV; + return 0; +} + +void cleanup_module(void) +{ + if(slvl_unit) + slvl_shutdown(slvl_unit); +} + +#endif + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/seeq8005.c linux.ac/drivers/net/seeq8005.c --- linux.vanilla/drivers/net/seeq8005.c Thu Dec 31 18:10:43 1998 +++ linux.ac/drivers/net/seeq8005.c Sat Jun 12 14:00:10 1999 @@ -736,6 +736,54 @@ outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); } +#ifdef MODULE + +static char devicename[9] = { 0, }; + +static struct device dev_seeq = +{ + devicename, /* device name is inserted by linux/drivers/net/net_init.c */ + 0, 0, 0, 0, + 0x300, 5, + 0, 0, 0, NULL, seeq8005_probe +}; + +static int io=0x320; +static int irq=10; +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); + +int init_module(void) +{ + dev_seeq.irq=irq; + dev_seeq.base_addr=io; + if (register_netdev(&dev_seeq) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + /* + * No need to check MOD_IN_USE, as sys_delete_module() checks. + */ + + unregister_netdev(&dev_seeq); + + /* + * Free up the private structure, or leak memory :-) + */ + + kfree(dev_seeq.priv); + dev_seeq.priv = NULL; /* gets re-allocated by el1_probe1 */ + + /* + * If we don't do this, we can't re-insmod it later. + */ + release_region(dev_seeq.base_addr, EL1_IO_EXTENT); +} + +#endif /* MODULE */ /* * Local variables: diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sgiseeq.c linux.ac/drivers/net/sgiseeq.c --- linux.vanilla/drivers/net/sgiseeq.c Thu Nov 19 18:38:38 1998 +++ linux.ac/drivers/net/sgiseeq.c Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sgiseeq.h linux.ac/drivers/net/sgiseeq.h --- linux.vanilla/drivers/net/sgiseeq.h Sun Nov 8 15:07:30 1998 +++ linux.ac/drivers/net/sgiseeq.h Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/shaper.c linux.ac/drivers/net/shaper.c --- linux.vanilla/drivers/net/shaper.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/net/shaper.c Mon Jun 21 13:20:06 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/slhc.c linux.ac/drivers/net/slhc.c --- linux.vanilla/drivers/net/slhc.c Tue Dec 22 23:19:47 1998 +++ linux.ac/drivers/net/slhc.c Mon Jul 19 19:48:19 1999 @@ -77,7 +77,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sonic.c linux.ac/drivers/net/sonic.c --- linux.vanilla/drivers/net/sonic.c Sat Jan 9 21:50:42 1999 +++ linux.ac/drivers/net/sonic.c Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sonic.h linux.ac/drivers/net/sonic.h --- linux.vanilla/drivers/net/sonic.h Sun Nov 8 15:07:30 1998 +++ linux.ac/drivers/net/sonic.h Tue Jun 22 01:34:49 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunbmac.c linux.ac/drivers/net/sunbmac.c --- linux.vanilla/drivers/net/sunbmac.c Wed Mar 24 10:55:19 1999 +++ linux.ac/drivers/net/sunbmac.c Mon Jul 19 19:48:19 1999 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunhme.c linux.ac/drivers/net/sunhme.c --- linux.vanilla/drivers/net/sunhme.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/net/sunhme.c Fri Jul 2 19:14:38 1999 @@ -3406,7 +3406,7 @@ /* Set the latency timer and cache line size as well, * PROM leaves it at zero. */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); #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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/sunlance.c linux.ac/drivers/net/sunlance.c --- linux.vanilla/drivers/net/sunlance.c Wed Mar 24 10:55:19 1999 +++ linux.ac/drivers/net/sunlance.c Mon Jul 19 19:48:19 1999 @@ -108,7 +108,6 @@ #include #include -#include #include /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/syncppp.c linux.ac/drivers/net/syncppp.c --- linux.vanilla/drivers/net/syncppp.c Fri Apr 16 22:10:53 1999 +++ linux.ac/drivers/net/syncppp.c Mon Jul 19 05:25:52 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/tulip.c linux.ac/drivers/net/tulip.c --- linux.vanilla/drivers/net/tulip.c Sun Jan 24 19:55:35 1999 +++ linux.ac/drivers/net/tulip.c Mon Jul 5 17:04:54 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/via-rhine.c linux.ac/drivers/net/via-rhine.c --- linux.vanilla/drivers/net/via-rhine.c Thu May 27 22:11:54 1999 +++ linux.ac/drivers/net/via-rhine.c Wed Jun 23 03:15:34 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,11 @@ #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 #ifdef VIA_USE_IO #undef readb #undef readw @@ -105,6 +107,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 +505,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 +514,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 +685,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 +1055,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 +1183,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/wavelan.c linux.ac/drivers/net/wavelan.c --- linux.vanilla/drivers/net/wavelan.c Thu May 27 22:11:55 1999 +++ linux.ac/drivers/net/wavelan.c Mon Jul 5 05:05:21 1999 @@ -2087,12 +2087,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); @@ -2118,8 +2112,8 @@ range.max_qual.noise = MMR_SILENCE_LVL; /* 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 +2130,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 +2157,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 +2200,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 +2209,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 +2266,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 +2284,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 +4240,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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/yellowfin.c linux.ac/drivers/net/yellowfin.c --- linux.vanilla/drivers/net/yellowfin.c Tue Dec 22 23:19:47 1998 +++ linux.ac/drivers/net/yellowfin.c Wed Jun 30 00:36:53 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/z85230.c linux.ac/drivers/net/z85230.c --- linux.vanilla/drivers/net/z85230.c Wed Apr 28 19:14:27 1999 +++ linux.ac/drivers/net/z85230.c Wed Jul 7 06:10:40 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/net/zlib.c linux.ac/drivers/net/zlib.c --- linux.vanilla/drivers/net/zlib.c Sun Nov 8 15:07:31 1998 +++ linux.ac/drivers/net/zlib.c Mon Jul 19 19:48:19 1999 @@ -5113,10 +5113,6 @@ /* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */ -#ifdef DEBUG_ZLIB -#include -#endif - /* #include "zutil.h" */ #ifndef NO_DUMMY_DECL diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/oldproc.c linux.ac/drivers/pci/oldproc.c --- linux.vanilla/drivers/pci/oldproc.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/pci/oldproc.c Mon Jul 19 20:31:54 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/pci/pci.c linux.ac/drivers/pci/pci.c --- linux.vanilla/drivers/pci/pci.c Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/pci/pci.c Mon Jul 5 05:48:10 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/char/bpp.c linux.ac/drivers/sbus/char/bpp.c --- linux.vanilla/drivers/sbus/char/bpp.c Wed Mar 24 10:55:20 1999 +++ linux.ac/drivers/sbus/char/bpp.c Mon Jul 19 19:48:19 1999 @@ -20,10 +20,10 @@ #include #include -#include +#include +#include #if defined(__i386__) -# include # include # include #endif @@ -34,7 +34,6 @@ # include /* OpenProm Library */ # include /* struct linux_sbus *SBus_chain */ -# include /* sparc_alloc_io() */ #endif #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sbus/sbus.c linux.ac/drivers/sbus/sbus.c --- linux.vanilla/drivers/sbus/sbus.c Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/sbus/sbus.c Mon Jun 7 22:24:51 1999 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7,8xx.c linux.ac/drivers/scsi/53c7,8xx.c --- linux.vanilla/drivers/scsi/53c7,8xx.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/53c7,8xx.c Fri Jun 4 23:52:42 1999 @@ -1901,7 +1901,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies,timeout)) barrier(); failed = 1; @@ -1986,7 +1987,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/53c7xx.c linux.ac/drivers/scsi/53c7xx.c --- linux.vanilla/drivers/scsi/53c7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/53c7xx.c Mon Jul 19 19:48:19 1999 @@ -254,9 +254,9 @@ #include #include #include +#include #ifdef CONFIG_AMIGA -#include #include #include #include @@ -266,7 +266,6 @@ #endif #ifdef CONFIG_MVME16x -#include #include #define BIG_ENDIAN @@ -275,7 +274,6 @@ #endif #ifdef CONFIG_BVME6000 -#include #include #define BIG_ENDIAN @@ -298,6 +296,10 @@ */ #undef inb #undef outb +#undef inw +#undef outw +#undef inl +#undef outl #define inb(x) 1 #define inw(x) 1 #define inl(x) 1 @@ -1612,7 +1614,8 @@ */ timeout = jiffies + 5 * HZ / 10; - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); failed = 1; @@ -1698,7 +1701,8 @@ restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ - while ((hostdata->test_completed == -1) && jiffies < timeout) + while ((hostdata->test_completed == -1) && + time_before(jiffies, timeout)) barrier(); NCR53c7x0_write32 (DSA_REG, 0); @@ -1899,7 +1903,7 @@ if (left < 0) printk("scsi%d: loop detected in ncr reconncect list\n", host->host_no); - else if (ncr_search) + else if (ncr_search) { if (found) printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n", host->host_no, c->pid); @@ -1910,6 +1914,7 @@ /* If we're at the tail end of the issue queue, update that pointer too. */ found = 1; } + } /* * Traverse the host running list until we find this command or discover @@ -2960,14 +2965,14 @@ NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM); else NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl); -#if 0 - /* Following disables snooping - run with caches disabled at first */ + /* Following disables snooping - snooping is not required, as non- + * cached pages are used for shared data, and appropriate use is + * made of cache_push/cache_clear. Indeed, for 68060 + * enabling snooping causes disk corruption of ext2fs free block + * bitmaps and the like. If you have a 68060 with snooping hardwared + * on, then you need to enable CONFIG_060_WRITETHROUGH. + */ NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD); -#else - /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating - * cache lines. */ - NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0); -#endif /* Actually burst of eight, according to my 53c710 databook */ NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2); NCR53c7x0_write8(SCID_REG, 1 << host->this_id); @@ -5947,11 +5952,12 @@ } } } - if (!(istat & (ISTAT_SIP|ISTAT_DIP))) + if (!(istat & (ISTAT_SIP|ISTAT_DIP))) { if (stage == 0) ++stage; else if (stage == 3) break; + } } hostdata->state = STATE_HALTED; restore_flags(flags); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/NCR53C9x.c linux.ac/drivers/scsi/NCR53C9x.c --- linux.vanilla/drivers/scsi/NCR53C9x.c Tue Dec 22 23:19:48 1998 +++ linux.ac/drivers/scsi/NCR53C9x.c Thu Jun 17 16:14:05 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 --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aha152x.c linux.ac/drivers/scsi/aha152x.c --- linux.vanilla/drivers/scsi/aha152x.c Fri May 28 00:32:59 1999 +++ linux.ac/drivers/scsi/aha152x.c Wed Jun 16 20:19:43 1999 @@ -183,7 +183,7 @@ ************************************************************************** - + DESCRIPTION: This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI @@ -192,30 +192,30 @@ CONFIGURATION ARGUMENTS: - IOPORT base io address (0x340/0x140) - IRQ interrupt level (9-12; default 11) - SCSI_ID scsi id of controller (0-7; default 7) - RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) - PARITY enable parity checking (0/1; default 1 [on]) - SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) - (NOT WORKING YET) - DELAY: bus reset delay (default 100) - EXT_TRANS: enable extended translation (0/1: default 0 [off]) - (see NOTES below) + IOPORT base io address (0x340/0x140) + IRQ interrupt level (9-12; default 11) + SCSI_ID scsi id of controller (0-7; default 7) + RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) + PARITY enable parity checking (0/1; default 1 [on]) + SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) + (NOT WORKING YET) + DELAY: bus reset delay (default 100) + EXT_TRANS: enable extended translation (0/1: default 0 [off]) + (see NOTES below) COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile): -DAUTOCONF - use configuration the controller reports (AHA-152x only) + use configuration the controller reports (AHA-152x only) -DSKIP_BIOSTEST - Don't test for BIOS signature (AHA-1510 or disabled BIOS) + Don't test for BIOS signature (AHA-1510 or disabled BIOS) -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the first controller - + override for the first controller + -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" - override for the second controller + override for the second controller LILO COMMAND LINE OPTIONS: @@ -230,13 +230,13 @@ SYMBOLS FOR MODULE CONFIGURATION: - - aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of first controller - - - aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS - configuration override of second controller + + aha152x=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS + configuration override of first controller + + + aha152x1=IOPORT,IRQ,SCSI_ID,RECONNECT,PARITY,SYNCHRONOUS,DELAY,EXT_TRANS + configuration override of second controller NOTES ON EXT_TRANS: @@ -287,14 +287,14 @@ - for disks<1GB: use default translation (C/32/64) - for disks>1GB: - - take current geometry from the partition table - (using scsicam_bios_param and accept only `valid' geometries, - ie. either (C/32/64) or (C/63/255)). This can be extended - translation even if it's not enabled in the driver. - - if that fails, take extended translation if enabled by override, - kernel or module parameter, otherwise take default translation and - ask the user for verification. This might on not yet partitioned - disks or + - take current geometry from the partition table + (using scsicam_bios_param and accept only `valid' geometries, + ie. either (C/32/64) or (C/63/255)). This can be extended + translation even if it's not enabled in the driver. + - if that fails, take extended translation if enabled by override, + kernel or module parameter, otherwise take default translation and + ask the user for verification. This might on not yet partitioned + disks or REFERENCES USED: @@ -308,7 +308,7 @@ "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu) "Adaptec 1520/1522 User's Guide", Adaptec Corporation. - + Michael K. Johnson (johnsonm@sunsite.unc.edu) Drew Eckhardt (drew@cs.colorado.edu) @@ -350,9 +350,10 @@ #include -struct proc_dir_entry proc_scsi_aha152x = { - PROC_SCSI_AHA152X, 7, "aha152x", - S_IFDIR | S_IRUGO | S_IXUGO, 2 +struct proc_dir_entry proc_scsi_aha152x = +{ + PROC_SCSI_AHA152X, 7, "aha152x", + S_IFDIR | S_IRUGO | S_IXUGO, 2 }; /* DEFINES */ @@ -370,25 +371,25 @@ #if defined(DEBUG_AHA152X) -#undef SKIP_PORTS /* don't display ports */ +#undef SKIP_PORTS /* don't display ports */ -#undef DEBUG_QUEUE /* debug queue() */ -#undef DEBUG_RESET /* debug reset() */ -#undef DEBUG_INTR /* debug intr() */ -#undef DEBUG_SELECTION /* debug selection part in intr() */ -#undef DEBUG_MSGO /* debug message out phase in intr() */ -#undef DEBUG_MSGI /* debug message in phase in intr() */ -#undef DEBUG_STATUS /* debug status phase in intr() */ -#undef DEBUG_CMD /* debug command phase in intr() */ -#undef DEBUG_DATAI /* debug data in phase in intr() */ -#undef DEBUG_DATAO /* debug data out phase in intr() */ -#undef DEBUG_ABORT /* debug abort() */ -#undef DEBUG_DONE /* debug done() */ -#undef DEBUG_BIOSPARAM /* debug biosparam() */ - -#undef DEBUG_RACE /* debug race conditions */ -#undef DEBUG_PHASES /* debug phases (useful to trace) */ -#undef DEBUG_QUEUES /* debug reselection */ +#undef DEBUG_QUEUE /* debug queue() */ +#undef DEBUG_RESET /* debug reset() */ +#undef DEBUG_INTR /* debug intr() */ +#undef DEBUG_SELECTION /* debug selection part in intr() */ +#undef DEBUG_MSGO /* debug message out phase in intr() */ +#undef DEBUG_MSGI /* debug message in phase in intr() */ +#undef DEBUG_STATUS /* debug status phase in intr() */ +#undef DEBUG_CMD /* debug command phase in intr() */ +#undef DEBUG_DATAI /* debug data in phase in intr() */ +#undef DEBUG_DATAO /* debug data out phase in intr() */ +#undef DEBUG_ABORT /* debug abort() */ +#undef DEBUG_DONE /* debug done() */ +#undef DEBUG_BIOSPARAM /* debug biosparam() */ + +#undef DEBUG_RACE /* debug race conditions */ +#undef DEBUG_PHASES /* debug phases (useful to trace) */ +#undef DEBUG_QUEUES /* debug reselection */ /* recently used for debugging */ #if 0 @@ -424,46 +425,50 @@ #define IRQS IRQ_MAX-IRQ_MIN+1 enum { - not_issued = 0x0001, - in_selection = 0x0002, - disconnected = 0x0004, - aborted = 0x0008, - sent_ident = 0x0010, - in_other = 0x0020, - in_sync = 0x0040, - sync_ok = 0x0080, + not_issued = 0x0001, + in_selection = 0x0002, + disconnected = 0x0004, + aborted = 0x0008, + sent_ident = 0x0010, + in_other = 0x0020, + in_sync = 0x0040, + sync_ok = 0x0080, }; #if defined(MODULE) #if defined(DEBUG_AHA152X) -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; +int aha152x[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; +int aha152x1[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; MODULE_PARM(aha152x, "1-9i"); MODULE_PARM(aha152x1, "1-9i"); #else -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; +int aha152x[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; +int aha152x1[] = +{0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; MODULE_PARM(aha152x, "1-8i"); MODULE_PARM(aha152x1, "1-8i"); #endif #endif /* set by aha152x_setup according to the command line */ -static int setup_count=0; -static int registered_count=0; +static int setup_count = 0; +static int registered_count = 0; static struct aha152x_setup { - int io_port; - int irq; - int scsiid; - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; + int io_port; + int irq; + int scsiid; + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; #ifdef DEBUG_AHA152X - int debug; + int debug; #endif - char *conf; + char *conf; } setup[2]; static struct Scsi_Host *aha152x_host[IRQS]; @@ -480,30 +485,30 @@ #define ADDMSG(x) (MSG(MSGLEN++)=x) struct aha152x_hostdata { - Scsi_Cmnd *issue_SC; - Scsi_Cmnd *current_SC; - Scsi_Cmnd *disconnected_SC; - int aborting; - int abortion_complete; - int abort_result; - int commands; - - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; - - int swint; - int service; - - unsigned char syncrate[8]; - - unsigned char message[256]; - int message_len; + Scsi_Cmnd *issue_SC; + Scsi_Cmnd *current_SC; + Scsi_Cmnd *disconnected_SC; + int aborting; + int abortion_complete; + int abort_result; + int commands; + + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; + + int swint; + int service; + + unsigned char syncrate[8]; + + unsigned char message[256]; + int message_len; #ifdef DEBUG_AHA152X - int debug; + int debug; #endif }; @@ -516,7 +521,7 @@ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg); static void disp_ports(struct Scsi_Host *shpnt); -static void show_command(Scsi_Cmnd *ptr); +static void show_command(Scsi_Cmnd * ptr); static void show_queues(struct Scsi_Host *shpnt); static void disp_enintr(struct Scsi_Host *shpnt); @@ -528,8 +533,8 @@ /* possible i/o addresses for the AIC-6260 */ static unsigned short ports[] = { - 0x340, /* default first */ - 0x140 + 0x340, /* default first */ + 0x140 }; #define PORT_COUNT (sizeof(ports) / sizeof(unsigned short)) @@ -537,15 +542,15 @@ /* possible locations for the Adaptec BIOS */ static unsigned int addresses[] = { - 0xdc000, /* default first */ - 0xc8000, - 0xcc000, - 0xd0000, - 0xd4000, - 0xd8000, - 0xe0000, - 0xeb800, /* VTech Platinum SMP */ - 0xf0000, + 0xdc000, /* default first */ + 0xc8000, + 0xcc000, + 0xd0000, + 0xd4000, + 0xd8000, + 0xe0000, + 0xeb800, /* VTech Platinum SMP */ + 0xf0000, }; #define ADDRESS_COUNT (sizeof(addresses) / sizeof(unsigned int)) @@ -557,80 +562,103 @@ needed anyway. May be an information whether or not the BIOS supports extended translation could be also useful here. */ static struct signature { - unsigned char *signature; - int sig_offset; - int sig_length; + unsigned char *signature; + int sig_offset; + int sig_length; } signatures[] = + { - { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, /* Adaptec 152x */ - { "Adaptec AHA-1520B", 0x0b, 19 }, /* Adaptec 152x rev B */ - { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, /* on-board controller */ - { "Adaptec BIOS: ASW-B626", 0x0f, 22 }, /* on-board controller */ - { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, /* on-board controller */ - { "Adaptec BIOS:AIC-6360", 0xc, 21 }, /* on-board controller */ - { "ScsiPro SP-360 BIOS", 0x2873, 19 }, /* ScsiPro-Controller */ - { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, /* Gigabyte Local-Bus-SCSI */ - { "Adaptec BIOS:AVA-282X", 0xc, 21 }, /* Adaptec 282x */ - { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, /* IBM Thinkpad Dock II */ - { "Adaptec BIOS:AHA-1532P", 0x1c, 22 }, /* IBM Thinkpad Dock II SCSI */ - { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, /* DTC 3520A ISA SCSI */ + { + "Adaptec AHA-1520 BIOS", 0x102e, 21 + }, /* Adaptec 152x */ + { + "Adaptec AHA-1520B", 0x0b, 19 + }, /* Adaptec 152x rev B */ + { + "Adaptec ASW-B626 BIOS", 0x1029, 21 + }, /* on-board controller */ + { + "Adaptec BIOS: ASW-B626", 0x0f, 22 + }, /* on-board controller */ + { + "Adaptec ASW-B626 S2", 0x2e6c, 19 + }, /* on-board controller */ + { + "Adaptec BIOS:AIC-6360", 0xc, 21 + }, /* on-board controller */ + { + "ScsiPro SP-360 BIOS", 0x2873, 19 + }, /* ScsiPro-Controller */ + { + "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 + }, /* Gigabyte Local-Bus-SCSI */ + { + "Adaptec BIOS:AVA-282X", 0xc, 21 + }, /* Adaptec 282x */ + { + "Adaptec IBM Dock II SCSI", 0x2edd, 24 + }, /* IBM Thinkpad Dock II */ + { + "Adaptec BIOS:AHA-1532P", 0x1c, 22 + }, /* IBM Thinkpad Dock II SCSI */ + { + "DTC3520A Host Adapter BIOS", 0x318a, 26 + }, /* DTC 3520A ISA SCSI */ }; + #define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature)) #endif -static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ -{ - unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ +static void do_pause(unsigned amount) +{ /* Pause for amount*10 milliseconds */ + unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ - while (time_before(jiffies, the_time)) - barrier(); + while (time_before(jiffies, the_time)) + barrier(); } /* * queue services: */ -static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +static inline void append_SC(Scsi_Cmnd ** SC, Scsi_Cmnd * new_SC) { - Scsi_Cmnd *end; + Scsi_Cmnd *end; - new_SC->host_scribble = (unsigned char *) NULL; - if(!*SC) - *SC=new_SC; - else { - for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble) - ; - end->host_scribble = (unsigned char *) new_SC; - } + new_SC->host_scribble = (unsigned char *) NULL; + if (!*SC) + *SC = new_SC; + else { + for (end = *SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble); + end->host_scribble = (unsigned char *) new_SC; + } } -static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC) { - Scsi_Cmnd *ptr; + Scsi_Cmnd *ptr; - ptr=*SC; - if(ptr) - *SC= (Scsi_Cmnd *) (*SC)->host_scribble; - return ptr; + ptr = *SC; + if (ptr) + *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + return ptr; } -static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd ** SC, int target, int lun) { - Scsi_Cmnd *ptr, *prev; - - for(ptr=*SC, prev=NULL; - ptr && ((ptr->target!=target) || (ptr->lun!=lun)); - prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) - ; + Scsi_Cmnd *ptr, *prev; - if(ptr){ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - *SC= (Scsi_Cmnd *) ptr->host_scribble; - } + for (ptr = *SC, prev = NULL; + ptr && ((ptr->target != target) || (ptr->lun != lun)); + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); - return ptr; + if (ptr) { + if (prev) + prev->host_scribble = ptr->host_scribble; + else + *SC = (Scsi_Cmnd *) ptr->host_scribble; + } + return ptr; } /* @@ -638,12 +666,12 @@ */ static void make_acklow(struct Scsi_Host *shpnt) { - SETPORT(SXFRCTL0, CH1|SPIOEN); - GETPORT(SCSIDAT); - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1 | SPIOEN); + GETPORT(SCSIDAT); + SETPORT(SXFRCTL0, CH1); - while(TESTHI(SCSISIG, ACKI)) - barrier(); + while (TESTHI(SCSISIG, ACKI)) + barrier(); } /* @@ -658,61 +686,61 @@ */ static int getphase(struct Scsi_Host *shpnt) { - int phase, sstat1; - - while(1) { - do { - while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT))) - barrier(); - if(sstat1 & BUSFREE) - return P_BUSFREE; - if(sstat1 & SCSIRSTI) { - printk("aha152x: RESET IN\n"); - SETPORT(SSTAT1, SCSIRSTI); - } - } while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); - - SETPORT(SSTAT1, CLRSCSIPERR); - - phase = GETPORT(SCSISIG) & P_MASK ; - - if(TESTHI(SSTAT1, SCSIPERR)) { - if((phase & (CDO|MSGO))==0) /* DATA phase */ - return P_PARITY; - - make_acklow(shpnt); - } else - return phase; - } + int phase, sstat1; + + while (1) { + do { + while (!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE | SCSIRSTI | REQINIT))) + barrier(); + if (sstat1 & BUSFREE) + return P_BUSFREE; + if (sstat1 & SCSIRSTI) { + printk("aha152x: RESET IN\n"); + SETPORT(SSTAT1, SCSIRSTI); + } + } while (TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); + + SETPORT(SSTAT1, CLRSCSIPERR); + + phase = GETPORT(SCSISIG) & P_MASK; + + if (TESTHI(SSTAT1, SCSIPERR)) { + if ((phase & (CDO | MSGO)) == 0) /* DATA phase */ + return P_PARITY; + + make_acklow(shpnt); + } else + return phase; + } } /* called from init/main.c */ void aha152x_setup(char *str, int *ints) { - if(setup_count>2) - panic("aha152x: you can only configure up to two controllers\n"); + if (setup_count > 2) + panic("aha152x: you can only configure up to two controllers\n"); - setup[setup_count].conf = str; - setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; - setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; - setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; - setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; - setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; - setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */; - setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; - setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; + setup[setup_count].conf = str; + setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; + setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; + setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; + setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; + setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; + setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */ ; + setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; #ifdef DEBUG_AHA152X - setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; - if(ints[0]>9) { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,[,[,]]]]]]]]\n"); + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if (ints[0] > 9) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,[,]]]]]]]]\n"); #else - if(ints[0]>8) { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,[,]]]]]]]\n"); + if (ints[0] > 8) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,]]]]]]]\n"); #endif - } else - setup_count++; + } else + setup_count++; } /* @@ -720,598 +748,589 @@ */ static int aha152x_porttest(int io_port) { - int i; + int i; - if(check_region(io_port, IO_RANGE)) - return 0; + if (check_region(io_port, IO_RANGE)) + return 0; - SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ - for(i=0; i<16; i++) - SETPORT(io_port+O_STACK, i); + SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16; i++) + SETPORT(io_port + O_STACK, i); - SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */ - for(i=0; i<16 && GETPORT(io_port+O_STACK)==i; i++) - ; + SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ + for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++); - return(i==16); + return (i == 16); } int aha152x_checksetup(struct aha152x_setup *setup) { - int i; - + int i; + #ifndef PCMCIA - for(i=0; iio_port != ports[i]); i++) - ; - - if(i==PORT_COUNT) - return 0; -#endif - - if(!aha152x_porttest(setup->io_port)) - return 0; - - if((setup->irqirq>IRQ_MAX)) - return 0; - - if((setup->scsiid < 0) || (setup->scsiid > 7)) - return 0; - - if((setup->reconnect < 0) || (setup->reconnect > 1)) - return 0; - - if((setup->parity < 0) || (setup->parity > 1)) - return 0; - - if((setup->synchronous < 0) || (setup->synchronous > 1)) - return 0; - - if((setup->ext_trans < 0) || (setup->ext_trans > 1)) - return 0; - - - return 1; + for (i = 0; i < PORT_COUNT && (setup->io_port != ports[i]); i++); + + if (i == PORT_COUNT) + return 0; +#endif + + if (!aha152x_porttest(setup->io_port)) + return 0; + + if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) + return 0; + + if ((setup->scsiid < 0) || (setup->scsiid > 7)) + return 0; + + if ((setup->reconnect < 0) || (setup->reconnect > 1)) + return 0; + + if ((setup->parity < 0) || (setup->parity > 1)) + return 0; + + if ((setup->synchronous < 0) || (setup->synchronous > 1)) + return 0; + + if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) + return 0; + + + return 1; } -void aha152x_swintr(int irqno, void *dev_id, struct pt_regs * regs) +void aha152x_swintr(int irqno, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; + struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; - if(!shpnt) - panic("aha152x: catched software interrupt for unknown controller.\n"); + if (!shpnt) + panic("aha152x: catched software interrupt for unknown controller.\n"); - HOSTDATA(shpnt)->swint++; + HOSTDATA(shpnt)->swint++; } int aha152x_detect(Scsi_Host_Template * tpnt) { - int i, j, ok; + int i, j, ok; #if defined(AUTOCONF) - aha152x_config conf; + aha152x_config conf; #endif - - tpnt->proc_dir = &proc_scsi_aha152x; - for(i=0; iproc_dir = &proc_scsi_aha152x; + + for (i = 0; i < IRQS; i++) + aha152x_host[i] = (struct Scsi_Host *) NULL; + + if (setup_count) { + printk("aha152x: processing commandline: "); + + for (i = 0; i < setup_count; i++) + if (!aha152x_checksetup(&setup[i])) { + printk("\naha152x: %s\n", setup[i].conf); + printk("aha152x: invalid line (controller=%d)\n", i + 1); + } + printk("ok\n"); + } #ifdef SETUP0 - if(setup_count<2) { - struct aha152x_setup override = SETUP0; + if (setup_count < 2) { + struct aha152x_setup override = SETUP0; - if(setup_count==0 || (override.io_port != setup[0].io_port)) - if(!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", - override.io_port, - override.irq, - override.scsiid, - override.reconnect, - override.parity, - override.synchronous, - override.delay, - override.ext_trans); - } else - setup[setup_count++] = override; - } + if (setup_count == 0 || (override.io_port != setup[0].io_port)) + if (!aha152x_checksetup(&override)) { + printk("\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif #ifdef SETUP1 - if(setup_count<2) { - struct aha152x_setup override = SETUP1; + if (setup_count < 2) { + struct aha152x_setup override = SETUP1; - if(setup_count==0 || (override.io_port != setup[0].io_port)) - if(!aha152x_checksetup(&override)) { - printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", - override.io_port, - override.irq, - override.scsiid, - override.reconnect, - override.parity, - override.synchronous, - override.delay, - override.ext_trans); - } else - setup[setup_count++] = override; - } + if (setup_count == 0 || (override.io_port != setup[0].io_port)) + if (!aha152x_checksetup(&override)) { + printk("\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } #endif #if defined(MODULE) - if(setup_count<2 && aha152x[0]!=0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x[0]; - setup[setup_count].irq = aha152x[1]; - setup[setup_count].scsiid = aha152x[2]; - setup[setup_count].reconnect = aha152x[3]; - setup[setup_count].parity = aha152x[4]; - setup[setup_count].synchronous = aha152x[5]; - setup[setup_count].delay = aha152x[6]; - setup[setup_count].ext_trans = aha152x[7]; + if (setup_count < 2 && aha152x[0] != 0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x[0]; + setup[setup_count].irq = aha152x[1]; + setup[setup_count].scsiid = aha152x[2]; + setup[setup_count].reconnect = aha152x[3]; + setup[setup_count].parity = aha152x[4]; + setup[setup_count].synchronous = aha152x[5]; + setup[setup_count].delay = aha152x[6]; + setup[setup_count].ext_trans = aha152x[7]; #ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x[8]; + setup[setup_count].debug = aha152x[8]; #endif - if(aha152x_checksetup(&setup[setup_count])) - setup_count++; - else - printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", - setup[setup_count].io_port, - setup[setup_count].irq, - setup[setup_count].scsiid, - setup[setup_count].reconnect, - setup[setup_count].parity, - setup[setup_count].synchronous, - setup[setup_count].delay, - setup[setup_count].ext_trans); - } - - if(setup_count<2 && aha152x1[0]!=0) { - setup[setup_count].conf = ""; - setup[setup_count].io_port = aha152x1[0]; - setup[setup_count].irq = aha152x1[1]; - setup[setup_count].scsiid = aha152x1[2]; - setup[setup_count].reconnect = aha152x1[3]; - setup[setup_count].parity = aha152x1[4]; - setup[setup_count].synchronous = aha152x1[5]; - setup[setup_count].delay = aha152x1[6]; - setup[setup_count].ext_trans = aha152x1[7]; + if (aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } + if (setup_count < 2 && aha152x1[0] != 0) { + setup[setup_count].conf = ""; + setup[setup_count].io_port = aha152x1[0]; + setup[setup_count].irq = aha152x1[1]; + setup[setup_count].scsiid = aha152x1[2]; + setup[setup_count].reconnect = aha152x1[3]; + setup[setup_count].parity = aha152x1[4]; + setup[setup_count].synchronous = aha152x1[5]; + setup[setup_count].delay = aha152x1[6]; + setup[setup_count].ext_trans = aha152x1[7]; #ifdef DEBUG_AHA152X - setup[setup_count].debug = aha152x1[8]; + setup[setup_count].debug = aha152x1[8]; #endif - if(aha152x_checksetup(&setup[setup_count])) - setup_count++; - else - printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", - setup[setup_count].io_port, - setup[setup_count].irq, - setup[setup_count].scsiid, - setup[setup_count].reconnect, - setup[setup_count].parity, - setup[setup_count].synchronous, - setup[setup_count].delay, - setup[setup_count].ext_trans); - } + if (aha152x_checksetup(&setup[setup_count])) + setup_count++; + else + printk("\naha152x: invalid module argument aha152x1=0x%x,%d,%d,%d,%d,%d,%d,%d\n", + setup[setup_count].io_port, + setup[setup_count].irq, + setup[setup_count].scsiid, + setup[setup_count].reconnect, + setup[setup_count].parity, + setup[setup_count].synchronous, + setup[setup_count].delay, + setup[setup_count].ext_trans); + } #endif - + #if defined(AUTOCONF) - if(setup_count<2) { + if (setup_count < 2) { #if !defined(SKIP_BIOSTEST) - ok=0; - for(i=0; i < ADDRESS_COUNT && !ok; i++) - for(j=0; (j < SIGNATURE_COUNT) && !ok; j++) - ok = check_signature(addresses[i]+signatures[j].sig_offset, - signatures[j].signature, signatures[j].sig_length); + ok = 0; + for (i = 0; i < ADDRESS_COUNT && !ok; i++) + for (j = 0; (j < SIGNATURE_COUNT) && !ok; j++) + ok = check_signature(addresses[i] + signatures[j].sig_offset, + signatures[j].signature, signatures[j].sig_length); - if(!ok && setup_count==0) - return 0; + if (!ok && setup_count == 0) + return 0; - printk("aha152x: BIOS test: passed, "); + printk("aha152x: BIOS test: passed, "); #else - printk("aha152x: "); -#endif /* !SKIP_BIOSTEST */ - - ok=0; - for(i=0; iio_port = setup[i].io_port; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = setup[i].irq; + + ISSUE_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC = (Scsi_Cmnd *) NULL; + DISCONNECTED_SC = (Scsi_Cmnd *) NULL; + + HOSTDATA(shpnt)->reconnect = setup[i].reconnect; + HOSTDATA(shpnt)->parity = setup[i].parity; + HOSTDATA(shpnt)->synchronous = setup[i].synchronous; + HOSTDATA(shpnt)->delay = setup[i].delay; + HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; +#ifdef DEBUG_AHA152X + HOSTDATA(shpnt)->debug = setup[i].debug; +#endif - shpnt = aha152x_host[setup[i].irq-IRQ_MIN] = - scsi_register(tpnt, sizeof(struct aha152x_hostdata)); - registered_count++; + HOSTDATA(shpnt)->aborting = 0; + HOSTDATA(shpnt)->abortion_complete = 0; + HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->commands = 0; + + HOSTDATA(shpnt)->message_len = 0; + + for (j = 0; j < 8; j++) + HOSTDATA(shpnt)->syncrate[j] = 0; + + SETPORT(SCSIID, setup[i].scsiid << 4); + shpnt->this_id = setup[i].scsiid; + + if (setup[i].reconnect) + shpnt->can_queue = AHA152X_MAXQUEUE; + + /* RESET OUT */ + SETBITS(SCSISEQ, SCSIRSTO); + do_pause(30); + CLRBITS(SCSISEQ, SCSIRSTO); + do_pause(setup[i].delay); + + aha152x_reset_ports(shpnt); + + printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," + " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", + i, + shpnt->io_port, + shpnt->irq, + shpnt->this_id, + HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled", + HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", + HOSTDATA(shpnt)->delay, + HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); + + request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + SETBITS(DMACNTRL0, INTEN); + + ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); + if (ok < 0) { + if (ok == -EINVAL) + printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); + else if (ok == -EBUSY) + printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); + else + printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); + printk("aha152x: driver needs an IRQ.\n"); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + continue; + } + HOSTDATA(shpnt)->swint = 0; - shpnt->io_port = setup[i].io_port; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; + printk("aha152x: trying software interrupt, "); + SETBITS(DMACNTRL0, SWINT); - ISSUE_SC = (Scsi_Cmnd *) NULL; - CURRENT_SC = (Scsi_Cmnd *) NULL; - DISCONNECTED_SC = (Scsi_Cmnd *) NULL; + the_time = jiffies + 100; + while (!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) + barrier(); + + free_irq(shpnt->irq, shpnt); + + if (!HOSTDATA(shpnt)->swint) { + if (TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + shpnt = aha152x_host[shpnt->irq - IRQ_MIN] = 0; + continue; + } + printk("ok.\n"); - HOSTDATA(shpnt)->reconnect = setup[i].reconnect; - HOSTDATA(shpnt)->parity = setup[i].parity; - HOSTDATA(shpnt)->synchronous = setup[i].synchronous; - HOSTDATA(shpnt)->delay = setup[i].delay; - HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; -#ifdef DEBUG_AHA152X - HOSTDATA(shpnt)->debug = setup[i].debug; -#endif + CLRBITS(DMACNTRL0, SWINT); - HOSTDATA(shpnt)->aborting = 0; - HOSTDATA(shpnt)->abortion_complete = 0; - HOSTDATA(shpnt)->abort_result = 0; - HOSTDATA(shpnt)->commands = 0; - - HOSTDATA(shpnt)->message_len = 0; - - for(j=0; j<8; j++) - HOSTDATA(shpnt)->syncrate[j] = 0; - - SETPORT(SCSIID, setup[i].scsiid << 4); - shpnt->this_id=setup[i].scsiid; - - if(setup[i].reconnect) - shpnt->can_queue=AHA152X_MAXQUEUE; - - /* RESET OUT */ - SETBITS(SCSISEQ, SCSIRSTO); - do_pause(30); - CLRBITS(SCSISEQ, SCSIRSTO); - do_pause(setup[i].delay); - - aha152x_reset_ports(shpnt); - - printk("aha152x%d: vital data: PORTBASE=0x%03lx, IRQ=%d, SCSI ID=%d," - " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", - i, - shpnt->io_port, - shpnt->irq, - shpnt->this_id, - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", - HOSTDATA(shpnt)->delay, - HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); - - request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); - - SETBITS(DMACNTRL0, INTEN); - - ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); - if(ok<0) { - if(ok == -EINVAL) - printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); - else if(ok == -EBUSY) - printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); - else - printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); - printk("aha152x: driver needs an IRQ.\n"); - - scsi_unregister(shpnt); - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; - continue; - } - - HOSTDATA(shpnt)->swint=0; - - printk("aha152x: trying software interrupt, "); - SETBITS(DMACNTRL0, SWINT); - - the_time=jiffies+100; - while(!HOSTDATA(shpnt)->swint && time_before(jiffies, the_time)) - barrier(); - - free_irq(shpnt->irq,shpnt); - - if(!HOSTDATA(shpnt)->swint) { - if(TESTHI(DMASTAT, INTSTAT)) { - printk("lost.\n"); - } else { - printk("failed.\n"); - } - - printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); - - scsi_unregister(shpnt); - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; - continue; - } - - printk("ok.\n"); - - CLRBITS(DMACNTRL0, SWINT); - - /* clear interrupts */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); - - if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",shpnt)<0) { - printk("aha152x: failed to reassign interrupt.\n"); - } - } - - return (registered_count>0); + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if (request_irq(shpnt->irq, aha152x_intr, SA_INTERRUPT, "aha152x", shpnt) < 0) { + printk("aha152x: failed to reassign interrupt.\n"); + } + } + + return (registered_count > 0); } int aha152x_release(struct Scsi_Host *shpnt) { - if (shpnt->irq) - free_irq(shpnt->irq, shpnt); - if (shpnt->io_port) - release_region(shpnt->io_port, IO_RANGE); + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + if (shpnt->io_port) + release_region(shpnt->io_port, IO_RANGE); - return 0; + return 0; } /* * Queue a command and setup interrupts for a free bus. */ -int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; #if defined(DEBUG_RACE) - enter_driver("queue"); + enter_driver("queue"); #else #if defined(DEBUG_QUEUE) - if(HOSTDATA(shpnt)->debug & debug_queue) - printk("aha152x: queue(), "); + if (HOSTDATA(shpnt)->debug & debug_queue) + printk("aha152x: queue(), "); #endif #endif #if defined(DEBUG_QUEUE) - if(HOSTDATA(shpnt)->debug & debug_queue) { - printk("SCpnt (target = %d lun = %d cmnd = ", - SCpnt->target, SCpnt->lun); - print_command(SCpnt->cmnd); - printk(", cmd_len=%d, pieces = %d size = %u), ", - SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); - disp_ports(shpnt); - } -#endif - - SCpnt->scsi_done = done; - - /* setup scratch area - SCp.ptr : buffer pointer - SCp.this_residual : buffer length - SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list - SCp.phase : current state of the command */ - SCpnt->SCp.phase = not_issued; - if (SCpnt->use_sg) { - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; - } else { - SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - } - - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0; - SCpnt->SCp.have_data_in = 0; - SCpnt->SCp.sent_command = 0; - - /* Turn led on, when this is the first command. */ - save_flags(flags); - cli(); - HOSTDATA(shpnt)->commands++; - if(HOSTDATA(shpnt)->commands==1) - SETPORT(PORTA, 1); + if (HOSTDATA(shpnt)->debug & debug_queue) { + printk("SCpnt (target = %d lun = %d cmnd = ", + SCpnt->target, SCpnt->lun); + print_command(SCpnt->cmnd); + printk(", cmd_len=%d, pieces = %d size = %u), ", + SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); + disp_ports(shpnt); + } +#endif + + SCpnt->scsi_done = done; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + SCpnt->SCp.phase = not_issued; + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + + /* Turn led on, when this is the first command. */ + save_flags(flags); + cli(); + HOSTDATA(shpnt)->commands++; + if (HOSTDATA(shpnt)->commands == 1) + SETPORT(PORTA, 1); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i+ (%d), ", HOSTDATA(shpnt)->commands); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i+ (%d), ", HOSTDATA(shpnt)->commands); #endif - append_SC(&ISSUE_SC, SCpnt); - - /* Enable bus free interrupt, when we aren't currently on the bus */ - if(!CURRENT_SC) { - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - } - restore_flags(flags); + append_SC(&ISSUE_SC, SCpnt); + + /* Enable bus free interrupt, when we aren't currently on the bus */ + if (!CURRENT_SC) { + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + } + restore_flags(flags); #if defined(DEBUG_RACE) - leave_driver("queue"); + leave_driver("queue"); #endif - return 0; + return 0; } /* * We only support commands in interrupt-driven fashion */ -int aha152x_command(Scsi_Cmnd *SCpnt) +int aha152x_command(Scsi_Cmnd * SCpnt) { - printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); - return -1; + printk("aha152x: interrupt driven driver; use aha152x_queue()\n"); + return -1; } /* * Abort a queued command * (commands that are on the bus can't be aborted easily) */ -int aha152x_abort(Scsi_Cmnd *SCpnt) +int aha152x_abort(Scsi_Cmnd * SCpnt) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; - Scsi_Cmnd *ptr, *prev; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + Scsi_Cmnd *ptr, *prev; - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) { - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); - show_queues(shpnt); - } -#endif - - /* look for command in issue queue */ - for(ptr=ISSUE_SC, prev=NULL; - ptr && ptr!=SCpnt; - prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) - ; - - if(ptr) { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; - - HOSTDATA(shpnt)->commands--; - - restore_flags(flags); - - ptr->host_scribble = NULL; - ptr->result = DID_ABORT << 16; - ptr->scsi_done(ptr); - - return SCSI_ABORT_SUCCESS; - } - - /* if the bus is busy or a command is currently processed, - we can't do anything more */ - if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) { - /* fail abortion, if bus is busy */ - - if(!CURRENT_SC) - printk("bus busy w/o current command, "); - - restore_flags(flags); - - return SCSI_ABORT_BUSY; - } - - /* bus is free */ - - if(CURRENT_SC) { - HOSTDATA(shpnt)->commands--; - - /* target entered bus free before COMMAND COMPLETE, nothing to abort */ - restore_flags(flags); - CURRENT_SC->result = DID_ERROR << 16; - CURRENT_SC->scsi_done(CURRENT_SC); - CURRENT_SC = (Scsi_Cmnd *) NULL; - - return SCSI_ABORT_SUCCESS; - } - - /* look for command in disconnected queue */ - for(ptr=DISCONNECTED_SC, prev=NULL; - ptr && ptr!=SCpnt; - prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) - ; - - if(!ptr) { - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); - - return SCSI_ABORT_NOT_RUNNING; - } - - if(!HOSTDATA(shpnt)->aborting) { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - HOSTDATA(shpnt)->commands--; - - /* set command current and initiate selection, - let the interrupt routine take care of the abortion */ - CURRENT_SC = ptr; - ptr->SCp.phase = in_selection|aborted; - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - - ADDMSG(ABORT); - - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - SETBITS(DMACNTRL0, INTEN); - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->aborting++; - HOSTDATA(shpnt)->abortion_complete=0; - - restore_flags(flags); - - /* sleep until the abortion is complete */ - while(!HOSTDATA(shpnt)->abortion_complete) - barrier(); - HOSTDATA(shpnt)->aborting=0; - - return HOSTDATA(shpnt)->abort_result; - } else { - /* we're already aborting a command */ - restore_flags(flags); + if (HOSTDATA(shpnt)->debug & debug_abort) { + printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); + show_queues(shpnt); + } +#endif + + /* look for command in issue queue */ + for (ptr = ISSUE_SC, prev = NULL; + ptr && ptr != SCpnt; + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + + if (ptr) { + /* dequeue */ + if (prev) + prev->host_scribble = ptr->host_scribble; + else + ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; + + HOSTDATA(shpnt)->commands--; + + restore_flags(flags); + + ptr->host_scribble = NULL; + ptr->result = DID_ABORT << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(ptr); + spin_unlock_irqrestore(&io_request_lock, flags); + + return SCSI_ABORT_SUCCESS; + } + /* if the bus is busy or a command is currently processed, + we can't do anything more */ + if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC != SCpnt)) { + /* fail abortion, if bus is busy */ + + if (!CURRENT_SC) + printk("bus busy w/o current command, "); + + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } + /* bus is free */ + + if (CURRENT_SC) { + HOSTDATA(shpnt)->commands--; + + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ + restore_flags(flags); + spin_lock_irqsave(&io_request_lock, flags); + CURRENT_SC->result = DID_ERROR << 16; + CURRENT_SC->scsi_done(CURRENT_SC); + CURRENT_SC = (Scsi_Cmnd *) NULL; + spin_unlock_irqrestore(&io_request_lock, flags); + + return SCSI_ABORT_SUCCESS; + } + /* look for command in disconnected queue */ + for (ptr = DISCONNECTED_SC, prev = NULL; + ptr && ptr != SCpnt; + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble); + + if (!ptr) { + /* command wasn't found */ + printk("command not found\n"); + restore_flags(flags); + + return SCSI_ABORT_NOT_RUNNING; + } + if (!HOSTDATA(shpnt)->aborting) { + /* dequeue */ + if (prev) + prev->host_scribble = ptr->host_scribble; + else + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; + + HOSTDATA(shpnt)->commands--; + + /* set command current and initiate selection, + let the interrupt routine take care of the abortion */ + CURRENT_SC = ptr; + ptr->SCp.phase = in_selection | aborted; + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + + ADDMSG(ABORT); + + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + SETBITS(DMACNTRL0, INTEN); + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->aborting++; + HOSTDATA(shpnt)->abortion_complete = 0; + + restore_flags(flags); + + /* sleep until the abortion is complete */ + while (!HOSTDATA(shpnt)->abortion_complete) + barrier(); + HOSTDATA(shpnt)->aborting = 0; + + return HOSTDATA(shpnt)->abort_result; + } else { + /* we're already aborting a command */ + restore_flags(flags); - return SCSI_ABORT_BUSY; - } + return SCSI_ABORT_BUSY; + } } /* @@ -1319,110 +1338,113 @@ */ static void aha152x_reset_ports(struct Scsi_Host *shpnt) { - /* disable interrupts */ - SETPORT(DMACNTRL0, RSTFIFO); + /* disable interrupts */ + SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(SCSISEQ, 0); + SETPORT(SCSISEQ, 0); - SETPORT(SXFRCTL1, 0); - SETPORT(SCSISIG, 0); - SETPORT(SCSIRATE, 0); + SETPORT(SXFRCTL1, 0); + SETPORT(SCSISIG, 0); + SETPORT(SCSIRATE, 0); - /* clear all interrupt conditions */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); + /* clear all interrupt conditions */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); - SETPORT(SSTAT4, SYNCERR|FWERR|FRERR); + SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); - SETPORT(DMACNTRL0, 0); - SETPORT(DMACNTRL1, 0); + SETPORT(DMACNTRL0, 0); + SETPORT(DMACNTRL1, 0); - SETPORT(BRSTCNTRL, 0xf1); + SETPORT(BRSTCNTRL, 0xf1); - /* clear SCSI fifo and transfer count */ - SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1); + /* clear SCSI fifo and transfer count */ + SETPORT(SXFRCTL0, CH1 | CLRCH1 | CLRSTCNT); + SETPORT(SXFRCTL0, CH1); - /* enable interrupts */ - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + /* enable interrupts */ + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); } /* * Reset registers, reset a hanging bus and * kill active and disconnected commands for target w/o soft reset */ -int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused) +int aha152x_reset(Scsi_Cmnd * SCpnt, unsigned int unused) { - struct Scsi_Host *shpnt = SCpnt->host; - unsigned long flags; - Scsi_Cmnd *ptr, *prev, *next; + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + Scsi_Cmnd *ptr, *prev, *next; - aha152x_reset_ports(shpnt); + aha152x_reset_ports(shpnt); - /* Reset, if bus hangs */ - if(TESTLO(SSTAT1, BUSFREE)) { - CLRBITS(DMACNTRL0, INTEN); + /* Reset, if bus hangs */ + if (TESTLO(SSTAT1, BUSFREE)) { + CLRBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(shpnt); - } -#endif - - ptr=CURRENT_SC; - if(ptr && !ptr->device->soft_reset) { - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(CURRENT_SC); - CURRENT_SC=NULL; - } - - save_flags(flags); - cli(); - prev=NULL; ptr=DISCONNECTED_SC; - while(ptr) { - if(!ptr->device->soft_reset) { - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - next = (Scsi_Cmnd *) ptr->host_scribble; - - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(ptr); - - ptr = next; - } else { - prev=ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble; - } - } - restore_flags(flags); + if (HOSTDATA(shpnt)->debug & debug_reset) { + printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); + show_queues(shpnt); + } +#endif + + ptr = CURRENT_SC; + if (ptr && !ptr->device->soft_reset) { + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(CURRENT_SC); + spin_unlock_irqrestore(&io_request_lock, flags); + CURRENT_SC = NULL; + } + save_flags(flags); + cli(); + prev = NULL; + ptr = DISCONNECTED_SC; + while (ptr) { + if (!ptr->device->soft_reset) { + if (prev) + prev->host_scribble = ptr->host_scribble; + else + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; + + next = (Scsi_Cmnd *) ptr->host_scribble; + + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); + ptr->scsi_done(ptr); + spin_unlock_irqrestore(&io_request_lock, flags); + + ptr = next; + } else { + prev = ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble; + } + } + restore_flags(flags); #if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) { - printk("commands on targets w/ soft-resets:\n"); - show_queues(shpnt); - } + if (HOSTDATA(shpnt)->debug & debug_reset) { + printk("commands on targets w/ soft-resets:\n"); + show_queues(shpnt); + } #endif - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(DELAY); - - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + /* RESET OUT */ + SETPORT(SCSISEQ, SCSIRSTO); + do_pause(30); + SETPORT(SCSISEQ, 0); + do_pause(DELAY); - SETPORT(DMACNTRL0, INTEN); - } + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - return SCSI_RESET_SUCCESS; + SETPORT(DMACNTRL0, INTEN); + } + return SCSI_RESET_SUCCESS; } /* @@ -1430,59 +1452,58 @@ */ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) { - struct Scsi_Host *shpnt=disk->device->host; + struct Scsi_Host *shpnt = disk->device->host; #if defined(DEBUG_BIOSPARAM) - if(HOSTDATA(shpnt)->debug & debug_biosparam) - printk("aha152x_biosparam: dev=%s, size=%d, ", - kdevname(dev), disk->capacity); -#endif - - /* try default translation */ - info_array[0]=64; - info_array[1]=32; - info_array[2]=disk->capacity / (64 * 32); - - /* for disks >1GB do some guessing */ - if(info_array[2]>=1024) { - int info[3]; - - /* try to figure out the geometry from the partition table */ - if(scsicam_bios_param(disk, dev, info)<0 || - !((info[0]==64 && info[1]==32) || (info[0]==255 && info[1]==63))) { - if(EXT_TRANS) { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" - " using extended translation.\n"); - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = disk->capacity / (255 * 63); - } else { - printk("aha152x: unable to verify geometry for disk with >1GB.\n" - " Using default translation. Please verify yourself.\n" - " Perhaps you need to enable extended translation in the driver.\n" - " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); - } - } else { - info_array[0]=info[0]; - info_array[1]=info[1]; - info_array[2]=info[2]; - - if(info[0]==255 && !EXT_TRANS) { - printk("aha152x: current partition table is using extended translation.\n" - " using it also, although it's not explicty enabled.\n"); - } - } - } - + if (HOSTDATA(shpnt)->debug & debug_biosparam) + printk("aha152x_biosparam: dev=%s, size=%d, ", + kdevname(dev), disk->capacity); +#endif + + /* try default translation */ + info_array[0] = 64; + info_array[1] = 32; + info_array[2] = disk->capacity / (64 * 32); + + /* for disks >1GB do some guessing */ + if (info_array[2] >= 1024) { + int info[3]; + + /* try to figure out the geometry from the partition table */ + if (scsicam_bios_param(disk, dev, info) < 0 || + !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { + if (EXT_TRANS) { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = disk->capacity / (255 * 63); + } else { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " Using default translation. Please verify yourself.\n" + " Perhaps you need to enable extended translation in the driver.\n" + " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); + } + } else { + info_array[0] = info[0]; + info_array[1] = info[1]; + info_array[2] = info[2]; + + if (info[0] == 255 && !EXT_TRANS) { + printk("aha152x: current partition table is using extended translation.\n" + " using it also, although it's not explicty enabled.\n"); + } + } + } #if defined(DEBUG_BIOSPARAM) - if(HOSTDATA(shpnt)->debug & debug_biosparam) { - printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); - printk("WARNING: check, if the bios geometry is correct.\n"); - } + if (HOSTDATA(shpnt)->debug & debug_biosparam) { + printk("bios geometry: head=%d, sec=%d, cyl=%d\n", + info_array[0], info_array[1], info_array[2]); + printk("WARNING: check, if the bios geometry is correct.\n"); + } #endif - return 0; + return 0; } /* @@ -1490,71 +1511,73 @@ */ void aha152x_done(struct Scsi_Host *shpnt, int error) { - unsigned long flags; - Scsi_Cmnd *done_SC; + unsigned long flags; + Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) { - printk("\naha152x: done(), "); - disp_ports(shpnt); - } + if (HOSTDATA(shpnt)->debug & debug_done) { + printk("\naha152x: done(), "); + disp_ports(shpnt); + } #endif - if(CURRENT_SC) { + if (CURRENT_SC) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done(%x), ", error); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("done(%x), ", error); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - done_SC = CURRENT_SC; - CURRENT_SC = NULL; + done_SC = CURRENT_SC; + CURRENT_SC = NULL; - /* turn led off, when no commands are in the driver */ - HOSTDATA(shpnt)->commands--; - if(!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ + /* turn led off, when no commands are in the driver */ + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("ok (%d), ", HOSTDATA(shpnt)->commands); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("ok (%d), ", HOSTDATA(shpnt)->commands); #endif - restore_flags(flags); + restore_flags(flags); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); #if 0 /* Why poll for the BUS FREE phase, when we have setup the interrupt!? */ #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE loop, "); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE loop, "); #endif - while(TESTLO(SSTAT1, BUSFREE)) - barrier(); + while (TESTLO(SSTAT1, BUSFREE)) + barrier(); #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE\n"); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE\n"); #endif #endif - done_SC->result = error; - if(done_SC->scsi_done) { + done_SC->result = error; + if (done_SC->scsi_done) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("calling scsi_done, "); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("calling scsi_done, "); #endif - done_SC->scsi_done(done_SC); + spin_lock_irqsave(&io_request_lock, flags); + done_SC->scsi_done(done_SC); + spin_unlock_irqrestore(&io_request_lock, flags); #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done returned, "); + if (HOSTDATA(shpnt)->debug & debug_done) + printk("done returned, "); #endif - } else - panic("aha152x: current_SC->scsi_done() == NULL"); - } else - aha152x_panic(shpnt, "done() called outside of command"); + } else + panic("aha152x: current_SC->scsi_done() == NULL"); + } else + aha152x_panic(shpnt, "done() called outside of command"); } @@ -1563,41 +1586,39 @@ static struct tq_struct aha152x_tq; /* - * Run service completions on the card with interrupts enabled. + * Run service completions on the card with interrupts enabled. */ - + static void aha152x_run(void) { int i; - for(i=0;iservice) - { - HOSTDATA(shpnt)->service=0; + for (i = 0; i < IRQS; i++) { + struct Scsi_Host *shpnt = aha152x_host[i]; + if (shpnt && HOSTDATA(shpnt)->service) { + HOSTDATA(shpnt)->service = 0; aha152x_complete(shpnt); } } } /* - * Interrupts handler (main routine of the driver) + * Interrupts handler (main routine of the driver) */ -static void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) +static void aha152x_intr(int irqno, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; + struct Scsi_Host *shpnt = aha152x_host[irqno - IRQ_MIN]; #if defined(DEBUG_RACE) enter_driver("intr"); #else #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) + if (HOSTDATA(shpnt)->debug & debug_intr) printk("\naha152x: intr(), "); #endif #endif - if(!shpnt) + if (!shpnt) panic("aha152x: catched interrupt for unknown controller.\n"); /* no more interrupts from the controller, while we're busy. @@ -1606,9 +1627,9 @@ CLRBITS(DMACNTRL0, INTEN); /* Poke the BH handler */ - - HOSTDATA(shpnt)->service=1; - aha152x_tq.routine = (void *)aha152x_run; + + HOSTDATA(shpnt)->service = 1; + aha152x_tq.routine = (void *) aha152x_run; queue_task(&aha152x_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } @@ -1616,1020 +1637,1001 @@ static void aha152x_complete(struct Scsi_Host *shpnt) { unsigned int flags; - int done=0, phase; + int done = 0, phase; /* disconnected target is trying to reconnect. Only possible, if we have disconnected nexuses and nothing is occupying the bus. */ - - if(TESTHI(SSTAT0, SELDI) && - DISCONNECTED_SC && - (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) { - int identify_msg, target, i; - - /* Avoid conflicts when a target reconnects - while we are trying to connect to another. */ - if(CURRENT_SC) { + + if (TESTHI(SSTAT0, SELDI) && + DISCONNECTED_SC && + (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))) { + int identify_msg, target, i; + + /* Avoid conflicts when a target reconnects + while we are trying to connect to another. */ + if (CURRENT_SC) { #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i+, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i+, "); #endif - save_flags(flags); - cli(); - append_SC(&ISSUE_SC, CURRENT_SC); - CURRENT_SC=NULL; - restore_flags(flags); - } - - /* disable sequences */ - SETPORT(SCSISEQ, 0); - SETPORT(SSTAT0, CLRSELDI); - SETPORT(SSTAT1, CLRBUSFREE); + save_flags(flags); + cli(); + append_SC(&ISSUE_SC, CURRENT_SC); + CURRENT_SC = NULL; + restore_flags(flags); + } + /* disable sequences */ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases)) - printk("reselected, "); + if (HOSTDATA(shpnt)->debug & (debug_queues | debug_phases)) + printk("reselected, "); #endif - i = GETPORT(SELID) & ~(1 << shpnt->this_id); - target=0; + i = GETPORT(SELID) & ~(1 << shpnt->this_id); + target = 0; - if(i==0) - aha152x_panic(shpnt, "reconnecting target unknown"); + if (i == 0) + aha152x_panic(shpnt, "reconnecting target unknown"); - for(; (i & 1)==0; target++, i>>=1) - ; + for (; (i & 1) == 0; target++, i >>= 1); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, ENRESELI); - - if(TESTLO(SSTAT0, SELDI)) - aha152x_panic(shpnt, "RESELI failed"); - - SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f); + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, ENRESELI); - SETPORT(SCSISIG, P_MSGI); + if (TESTLO(SSTAT0, SELDI)) + aha152x_panic(shpnt, "RESELI failed"); - /* Get identify message */ - if((i=getphase(shpnt))!=P_MSGI) { - printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); - aha152x_panic(shpnt, "unknown lun"); - } - SETPORT(SCSISEQ, 0); + SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target] & 0x7f); - SETPORT(SXFRCTL0, CH1); + SETPORT(SCSISIG, P_MSGI); - identify_msg = GETPORT(SCSIBUS); + /* Get identify message */ + if ((i = getphase(shpnt)) != P_MSGI) { + printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); + aha152x_panic(shpnt, "unknown lun"); + } + SETPORT(SCSISEQ, 0); - if(!(identify_msg & IDENTIFY_BASE)) { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic(shpnt, "unknown lun"); - } + SETPORT(SXFRCTL0, CH1); + identify_msg = GETPORT(SCSIBUS); + if (!(identify_msg & IDENTIFY_BASE)) { + printk("target=%d, inbound message (%02x) != IDENTIFY\n", + target, identify_msg); + aha152x_panic(shpnt, "unknown lun"); + } #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d-, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("d-, "); #endif - CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); + CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); + + if (!CURRENT_SC) { + printk("lun=%d, ", identify_msg & 0x3f); + aha152x_panic(shpnt, "no disconnected command for that lun"); + } + CURRENT_SC->SCp.phase &= ~disconnected; + restore_flags(flags); - if(!CURRENT_SC) { - printk("lun=%d, ", identify_msg & 0x3f); - aha152x_panic(shpnt, "no disconnected command for that lun"); - } - - CURRENT_SC->SCp.phase &= ~disconnected; - restore_flags(flags); - - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) { - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + make_acklow(shpnt); + if (getphase(shpnt) != P_MSGI) { + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); #if defined(DEBUG_RACE) - leave_driver("(reselected) intr"); + leave_driver("(reselected) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; - } - } - - /* Check, if we aren't busy with a command */ - if(!CURRENT_SC) { - /* bus is free to issue a queued command */ - if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { - save_flags(flags); - cli(); + SETBITS(DMACNTRL0, INTEN); + return; + } + } + /* Check, if we aren't busy with a command */ + if (!CURRENT_SC) { + /* bus is free to issue a queued command */ + if (TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i-, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("i-, "); #endif - CURRENT_SC = remove_first_SC(&ISSUE_SC); - restore_flags(flags); + CURRENT_SC = remove_first_SC(&ISSUE_SC); + restore_flags(flags); #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("issuing command, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) + printk("issuing command, "); #endif - CURRENT_SC->SCp.phase = in_selection; + CURRENT_SC->SCp.phase = in_selection; #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("selecting %d, ", CURRENT_SC->target); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_selection | debug_phases)) + printk("selecting %d, ", CURRENT_SC->target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER); + /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ + SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK | ENSTIMER) : ENSTIMER); - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - } else { - /* No command we are busy with and no new to issue */ - printk("aha152x: ignoring spurious interrupt, nothing to do\n"); - if(TESTHI(DMACNTRL0, SWINT)) { - printk("aha152x: SWINT is set! Why?\n"); - CLRBITS(DMACNTRL0, SWINT); - } - show_queues(shpnt); - } + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + } else { + /* No command we are busy with and no new to issue */ + printk("aha152x: ignoring spurious interrupt, nothing to do\n"); + if (TESTHI(DMACNTRL0, SWINT)) { + printk("aha152x: SWINT is set! Why?\n"); + CLRBITS(DMACNTRL0, SWINT); + } + show_queues(shpnt); + } #if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); + leave_driver("(selecting) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; - } - - /* the bus is busy with something */ + SETBITS(DMACNTRL0, INTEN); + return; + } + /* the bus is busy with something */ #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - disp_ports(shpnt); + if (HOSTDATA(shpnt)->debug & debug_intr) + disp_ports(shpnt); #endif - /* we are waiting for the result of a selection attempt */ - if(CURRENT_SC->SCp.phase & in_selection) { - if(TESTLO(SSTAT1, SELTO)) { - /* no timeout */ - if(TESTHI(SSTAT0, SELDO)) { - /* clear BUS FREE interrupt */ - SETPORT(SSTAT1, CLRBUSFREE); - - /* Disable SELECTION OUT sequence */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); + /* we are waiting for the result of a selection attempt */ + if (CURRENT_SC->SCp.phase & in_selection) { + if (TESTLO(SSTAT1, SELTO)) { + /* no timeout */ + if (TESTHI(SSTAT0, SELDO)) { + /* clear BUS FREE interrupt */ + SETPORT(SSTAT1, CLRBUSFREE); + + /* Disable SELECTION OUT sequence */ + CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + /* Disable SELECTION OUT DONE interrupt */ + CLRBITS(SIMODE0, ENSELDO); + CLRBITS(SIMODE1, ENSELTIMO); - if(TESTLO(SSTAT0, SELDO)) { - printk("aha152x: passing bus free condition\n"); + if (TESTLO(SSTAT0, SELDO)) { + printk("aha152x: passing bus free condition\n"); #if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); + leave_driver("(passing bus free) intr"); #endif - SETBITS(DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); - if(CURRENT_SC->SCp.phase & aborted) { - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } + if (CURRENT_SC->SCp.phase & aborted) { + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } + aha152x_done(shpnt, DID_NO_CONNECT << 16); - aha152x_done(shpnt, DID_NO_CONNECT << 16); - - return; - } + return; + } #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); + if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) + printk("SELDO (SELID=%x), ", GETPORT(SELID)); #endif - /* selection was done */ - SETPORT(SSTAT0, CLRSELDO); + /* selection was done */ + SETPORT(SSTAT0, CLRSELDO); #if defined(DEBUG_ABORT) - if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); + if ((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) + printk("(ABORT) target selected, "); #endif - CURRENT_SC->SCp.phase &= ~in_selection; - CURRENT_SC->SCp.phase |= in_other; - - ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)); + CURRENT_SC->SCp.phase &= ~in_selection; + CURRENT_SC->SCp.phase |= in_other; - if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) { - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - ADDMSG(50); - ADDMSG(8); + ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)); - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); + if (!(SYNCRATE & 0x80) && HOSTDATA(shpnt)->synchronous) { + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + ADDMSG(50); + ADDMSG(8); - SYNCRATE=0x80; - CURRENT_SC->SCp.phase |= in_sync; - } + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN - 5)); + SYNCRATE = 0x80; + CURRENT_SC->SCp.phase |= in_sync; + } #if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); + leave_driver("(SELDO) intr"); #endif - SETPORT(SCSIRATE, SYNCRATE&0x7f); + SETPORT(SCSIRATE, SYNCRATE & 0x7f); - SETPORT(SCSISIG, P_MSGO); + SETPORT(SCSISIG, P_MSGO); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); + SETBITS(DMACNTRL0, INTEN); - return; - } else - aha152x_panic(shpnt, "neither timeout nor selection\007"); - } else { + return; + } else + aha152x_panic(shpnt, "neither timeout nor selection\007"); + } else { #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELTO, "); + if (HOSTDATA(shpnt)->debug & (debug_selection | debug_phases)) + printk("SELTO, "); #endif - /* end selection attempt */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); + /* end selection attempt */ + CLRBITS(SCSISEQ, ENSELO | ENAUTOATNO); - /* timeout */ - SETPORT(SSTAT1, CLRSELTIMO); + /* timeout */ + SETPORT(SSTAT1, CLRSELTIMO); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); + leave_driver("(SELTO) intr"); #endif - if(CURRENT_SC->SCp.phase & aborted) { + if (CURRENT_SC->SCp.phase & aborted) { #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) - printk("(ABORT) selection timeout, "); + if (HOSTDATA(shpnt)->debug & debug_abort) + printk("(ABORT) selection timeout, "); #endif - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - - if(TESTLO(SSTAT0, SELINGO)) - /* ARBITRATION not won */ - aha152x_done(shpnt, DID_BUS_BUSY << 16); - else - /* ARBITRATION won, but SELECTION failed */ - aha152x_done(shpnt, DID_NO_CONNECT << 16); - - return; - } - } - - /* enable interrupt, when target leaves current phase */ - phase = getphase(shpnt); - if(!(phase & ~P_MASK)) /* "real" phase */ - SETPORT(SCSISIG, phase); - SETPORT(SSTAT1, CLRPHASECHG); - CURRENT_SC->SCp.phase = - (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16); - - /* information transfer phase */ - switch(phase) { - case P_MSGO: /* MESSAGE OUT */ - { - int i, identify=0, abort=0; + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } + if (TESTLO(SSTAT0, SELINGO)) + /* ARBITRATION not won */ + aha152x_done(shpnt, DID_BUS_BUSY << 16); + else + /* ARBITRATION won, but SELECTION failed */ + aha152x_done(shpnt, DID_NO_CONNECT << 16); + + return; + } + } + /* enable interrupt, when target leaves current phase */ + phase = getphase(shpnt); + if (!(phase & ~P_MASK)) /* "real" phase */ + SETPORT(SCSISIG, phase); + SETPORT(SSTAT1, CLRPHASECHG); + CURRENT_SC->SCp.phase = + (CURRENT_SC->SCp.phase & ~((P_MASK | 1) << 16)) | (phase << 16); + + /* information transfer phase */ + switch (phase) { + case P_MSGO: /* MESSAGE OUT */ + { + int i, identify = 0, abort = 0; #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases)) - printk("MESSAGE OUT, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgo | debug_phases)) + printk("MESSAGE OUT, "); #endif - if(MSGLEN==0) { - ADDMSG(MESSAGE_REJECT); + if (MSGLEN == 0) { + ADDMSG(MESSAGE_REJECT); #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) - printk("unexpected MESSAGE OUT phase; rejecting, "); + if (HOSTDATA(shpnt)->debug & debug_msgo) + printk("unexpected MESSAGE OUT phase; rejecting, "); #endif - } - - CLRBITS(SXFRCTL0, ENDMA); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); - + } + CLRBITS(SXFRCTL0, ENDMA); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while (TESTLO(DMASTAT, INTSTAT)) + barrier(); + #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) { - int i; - - printk("messages ("); - for(i=0; idebug & debug_msgo) { + int i; + + printk("messages ("); + for (i = 0; i < MSGLEN; i += print_msg(&MSG(i)), printk(" ")); + printk("), "); + } #endif - - for(i=0; idebug & debug_msgo) - printk("%x ", MSG(i)); + if (HOSTDATA(shpnt)->debug & debug_msgo) + printk("%x ", MSG(i)); #endif - if(i==MSGLEN-1) { - /* Leave MESSAGE OUT after transfer */ - SETPORT(SSTAT1, CLRATNO); - } - - SETPORT(SCSIDAT, MSG(i)); + if (i == MSGLEN - 1) { + /* Leave MESSAGE OUT after transfer */ + SETPORT(SSTAT1, CLRATNO); + } + SETPORT(SCSIDAT, MSG(i)); - make_acklow(shpnt); - getphase(shpnt); + make_acklow(shpnt); + getphase(shpnt); - if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)) - identify++; + if (MSG(i) == IDENTIFY(HOSTDATA(shpnt)->reconnect, CURRENT_SC->lun)) + identify++; - if(MSG(i)==ABORT) - abort++; + if (MSG(i) == ABORT) + abort++; - } + } - MSGLEN=0; + MSGLEN = 0; - if(identify) - CURRENT_SC->SCp.phase |= sent_ident; + if (identify) + CURRENT_SC->SCp.phase |= sent_ident; - if(abort) { - /* revive abort(); abort() enables interrupts */ - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->abortion_complete++; + if (abort) { + /* revive abort(); abort() enables interrupts */ + HOSTDATA(shpnt)->abort_result = SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->abortion_complete++; - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - /* exit */ - SETBITS(DMACNTRL0, INTEN); + /* exit */ + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(ABORT) intr"); + leave_driver("(ABORT) intr"); #endif - aha152x_done(shpnt, DID_ABORT<<16); + aha152x_done(shpnt, DID_ABORT << 16); - return; - } - } - break; + return; + } + } + break; - case P_CMD: /* COMMAND phase */ + case P_CMD: /* COMMAND phase */ #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases)) - printk("COMMAND, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_cmd | debug_phases)) + printk("COMMAND, "); #endif - if(!(CURRENT_SC->SCp.sent_command)) { - int i; + if (!(CURRENT_SC->SCp.sent_command)) { + int i; + + CLRBITS(SXFRCTL0, ENDMA); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENREQINIT | ENBUSFREE); + + /* wait for data latch to become ready or a phase change */ + while (TESTLO(DMASTAT, INTSTAT)) + barrier(); - CLRBITS(SXFRCTL0, ENDMA); + for (i = 0; i < CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { + SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); + + make_acklow(shpnt); + getphase(shpnt); + } + + if (i < CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS)) + aha152x_panic(shpnt, "target left COMMAND"); + + CURRENT_SC->SCp.sent_command++; + } else + aha152x_panic(shpnt, "Nothing to send while in COMMAND"); + break; + + case P_MSGI: /* MESSAGE IN phase */ + { + int start_sync = 0; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); - - for(i=0; icmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { - SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); - - make_acklow(shpnt); - getphase(shpnt); - } - - if(icmd_len && TESTHI(SSTAT1, PHASEMIS)) - aha152x_panic(shpnt, "target left COMMAND"); - - CURRENT_SC->SCp.sent_command++; - } else - aha152x_panic(shpnt, "Nothing to send while in COMMAND"); - break; - - case P_MSGI: /* MESSAGE IN phase */ - { - int start_sync=0; - #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases)) - printk("MESSAGE IN, "); + if (HOSTDATA(shpnt)->debug & (debug_intr | debug_msgi | debug_phases)) + printk("MESSAGE IN, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENBUSFREE); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENBUSFREE); - - while(phase == P_MSGI) { - CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); - switch(CURRENT_SC->SCp.Message) { - case DISCONNECT: + while (phase == P_MSGI) { + CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); + switch (CURRENT_SC->SCp.Message) { + case DISCONNECT: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("target disconnected, "); + if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) + printk("target disconnected, "); #endif - CURRENT_SC->SCp.Message = 0; - CURRENT_SC->SCp.phase |= disconnected; - if(!HOSTDATA(shpnt)->reconnect) - aha152x_panic(shpnt, "target was not allowed to disconnect"); - - break; - - case COMMAND_COMPLETE: + CURRENT_SC->SCp.Message = 0; + CURRENT_SC->SCp.phase |= disconnected; + if (!HOSTDATA(shpnt)->reconnect) + aha152x_panic(shpnt, "target was not allowed to disconnect"); + + break; + + case COMMAND_COMPLETE: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("inbound message (COMMAND COMPLETE), "); + if (HOSTDATA(shpnt)->debug & (debug_msgi | debug_phases)) + printk("inbound message (COMMAND COMPLETE), "); #endif - done++; - break; + done++; + break; - case MESSAGE_REJECT: - if(CURRENT_SC->SCp.phase & in_sync) { - CURRENT_SC->SCp.phase &= ~in_sync; - SYNCRATE=0x80; - printk("synchronous rejected, "); - } else - printk("inbound message (MESSAGE REJECT), "); + case MESSAGE_REJECT: + if (CURRENT_SC->SCp.phase & in_sync) { + CURRENT_SC->SCp.phase &= ~in_sync; + SYNCRATE = 0x80; + printk("synchronous rejected, "); + } else + printk("inbound message (MESSAGE REJECT), "); #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (MESSAGE REJECT), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (MESSAGE REJECT), "); #endif - break; + break; - case SAVE_POINTERS: + case SAVE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (SAVE DATA POINTERS), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (SAVE DATA POINTERS), "); #endif - break; + break; - case RESTORE_POINTERS: + case RESTORE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (RESTORE DATA POINTERS), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (RESTORE DATA POINTERS), "); #endif - break; + break; - case EXTENDED_MESSAGE: - { - char buffer[16]; - int i; + case EXTENDED_MESSAGE: + { + char buffer[16]; + int i; #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (EXTENDED MESSAGE), "); + if (HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (EXTENDED MESSAGE), "); #endif - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) - break; - - buffer[0]=EXTENDED_MESSAGE; - buffer[1]=GETPORT(SCSIDAT); - - for(i=0; idebug & debug_msgi) - print_msg(buffer); + if (HOSTDATA(shpnt)->debug & debug_msgi) + print_msg(buffer); #endif - switch(buffer [2]) { - case EXTENDED_SDTR: - { - long ticks; - - if(buffer[1]!=3) - aha152x_panic(shpnt, "SDTR message length != 3"); - - if(!HOSTDATA(shpnt)->synchronous) - break; - - printk("inbound SDTR: "); print_msg(buffer); - - ticks=(buffer[3]*4+49)/50; - - if(CURRENT_SC->SCp.phase & in_sync) { - /* we initiated SDTR */ - if(ticks>9 || buffer[4]<1 || buffer[4]>8) - aha152x_panic(shpnt, "received SDTR invalid"); - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - } else if(ticks<=9 && buffer[4]>=1) { - if(buffer[4]>8) - buffer[4]=8; - - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - if(ticks<4) { - ticks=4; - ADDMSG(50); - } else - ADDMSG(buffer[3]); - - ADDMSG(buffer[4]); - - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); - - CURRENT_SC->SCp.phase |= in_sync; - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - - start_sync++; - } else { - /* requested SDTR is too slow, do it asynchronously */ - ADDMSG(MESSAGE_REJECT); - SYNCRATE = 0; - } - - SETPORT(SCSIRATE, SYNCRATE&0x7f); - } - break; - - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSG(MESSAGE_REJECT); - break; - } - } - break; - - default: - printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); - break; - - } - - make_acklow(shpnt); - phase=getphase(shpnt); - } - - if(start_sync) - CURRENT_SC->SCp.phase |= in_sync; - else - CURRENT_SC->SCp.phase &= ~in_sync; - - if(MSGLEN>0) - SETPORT(SCSISIG, P_MSGI|ATNO); - - /* clear SCSI fifo on BUSFREE */ - if(phase==P_BUSFREE) - SETPORT(SXFRCTL0, CH1|CLRCH1); - - if(CURRENT_SC->SCp.phase & disconnected) { - save_flags(flags); - cli(); + switch (buffer[2]) { + case EXTENDED_SDTR: + { + long ticks; + + if (buffer[1] != 3) + aha152x_panic(shpnt, "SDTR message length != 3"); + + if (!HOSTDATA(shpnt)->synchronous) + break; + + printk("inbound SDTR: "); + print_msg(buffer); + + ticks = (buffer[3] * 4 + 49) / 50; + + if (CURRENT_SC->SCp.phase & in_sync) { + /* we initiated SDTR */ + if (ticks > 9 || buffer[4] < 1 || buffer[4] > 8) + aha152x_panic(shpnt, "received SDTR invalid"); + + SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; + } else if (ticks <= 9 && buffer[4] >= 1) { + if (buffer[4] > 8) + buffer[4] = 8; + + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + if (ticks < 4) { + ticks = 4; + ADDMSG(50); + } else + ADDMSG(buffer[3]); + + ADDMSG(buffer[4]); + + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN - 5)); + + CURRENT_SC->SCp.phase |= in_sync; + + SYNCRATE |= ((ticks - 2) << 4) + buffer[4]; + + start_sync++; + } else { + /* requested SDTR is too slow, do it asynchronously */ + ADDMSG(MESSAGE_REJECT); + SYNCRATE = 0; + } + + SETPORT(SCSIRATE, SYNCRATE & 0x7f); + } + break; + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSG(MESSAGE_REJECT); + break; + } + } + break; + + default: + printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); + break; + + } + + make_acklow(shpnt); + phase = getphase(shpnt); + } + + if (start_sync) + CURRENT_SC->SCp.phase |= in_sync; + else + CURRENT_SC->SCp.phase &= ~in_sync; + + if (MSGLEN > 0) + SETPORT(SCSISIG, P_MSGI | ATNO); + + /* clear SCSI fifo on BUSFREE */ + if (phase == P_BUSFREE) + SETPORT(SXFRCTL0, CH1 | CLRCH1); + + if (CURRENT_SC->SCp.phase & disconnected) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d+, "); + if (HOSTDATA(shpnt)->debug & debug_queues) + printk("d+, "); #endif - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1<<16; - CURRENT_SC = NULL; - restore_flags(flags); + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1 << 16; + CURRENT_SC = NULL; + restore_flags(flags); - SETBITS(SCSISEQ, ENRESELI); + SETBITS(SCSISEQ, ENRESELI); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); - return; - } - } - break; + return; + } + } + break; - case P_STATUS: /* STATUS IN phase */ + case P_STATUS: /* STATUS IN phase */ #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases)) - printk("STATUS, "); + if (HOSTDATA(shpnt)->debug & (debug_status | debug_intr | debug_phases)) + printk("STATUS, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT | ENBUSFREE); - if(TESTHI(SSTAT1, PHASEMIS)) - printk("aha152x: passing STATUS phase"); - - CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); - make_acklow(shpnt); - getphase(shpnt); + if (TESTHI(SSTAT1, PHASEMIS)) + printk("aha152x: passing STATUS phase"); + + CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); + make_acklow(shpnt); + getphase(shpnt); #if defined(DEBUG_STATUS) - if(HOSTDATA(shpnt)->debug & debug_status) { - printk("inbound status "); - print_status(CURRENT_SC->SCp.Status); - printk(", "); - } -#endif - break; - - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; + if (HOSTDATA(shpnt)->debug & debug_status) { + printk("inbound status "); + print_status(CURRENT_SC->SCp.Status); + printk(", "); + } +#endif + break; + + case P_DATAI: /* DATA IN phase */ + { + int fifodata, data_count, done; #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases)) - printk("DATA IN, "); + if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr | debug_phases)) + printk("DATA IN, "); #endif #if 0 - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) - printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) + printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); #endif - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + /* reset host fifo */ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO | ENDMA); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); + SETPORT(SXFRCTL0, CH1 | SCSIEN | DMAEN); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); - /* done is set when the FIFO is empty after the target left DATA IN */ - done=0; - - /* while the target stays in DATA to transfer data */ - while (!done) { + /* done is set when the FIFO is empty after the target left DATA IN */ + done = 0; + + /* while the target stays in DATA to transfer data */ + while (!done) { #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("expecting data, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("expecting data, "); #endif - /* wait for PHASEMIS or full FIFO */ - while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) - barrier(); + /* wait for PHASEMIS or full FIFO */ + while (TESTLO(DMASTAT, DFIFOFULL | INTSTAT)) + barrier(); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("ok, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("ok, "); #endif - - if(TESTHI(DMASTAT, DFIFOFULL)) - fifodata=GETPORT(FIFOSTAT); - else { - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); - /* rest of data in FIFO */ - fifodata=GETPORT(FIFOSTAT); + if (TESTHI(DMASTAT, DFIFOFULL)) + fifodata = GETPORT(FIFOSTAT); + else { + /* wait for SCSI fifo to get empty */ + while (TESTLO(SSTAT2, SEMPTY)) + barrier(); + + /* rest of data in FIFO */ + fifodata = GETPORT(FIFOSTAT); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("last transfer, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("last transfer, "); #endif - done=1; - } - + done = 1; + } + #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("fifodata=%d, ", fifodata); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("fifodata=%d, ", fifodata); #endif - while(fifodata && CURRENT_SC->SCp.this_residual) { - data_count=fifodata; - - /* limit data transfer to size of first sg buffer */ - if(data_count > CURRENT_SC->SCp.this_residual) - data_count = CURRENT_SC->SCp.this_residual; - - fifodata -= data_count; + while (fifodata && CURRENT_SC->SCp.this_residual) { + data_count = fifodata; + + /* limit data transfer to size of first sg buffer */ + if (data_count > CURRENT_SC->SCp.this_residual) + data_count = CURRENT_SC->SCp.this_residual; + + fifodata -= data_count; #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("data_count=%d, ", data_count); + if (HOSTDATA(shpnt)->debug & debug_datai) + printk("data_count=%d, ", data_count); #endif - - if(data_count&1) { - /* get a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); - CURRENT_SC->SCp.this_residual--; - } - - if(data_count>1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* Number of words */ - insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + + if (data_count & 1) { + /* get a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); + CURRENT_SC->SCp.this_residual--; + } + if (data_count > 1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* Number of words */ + insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - /* show what comes with the last transfer */ - if(done) { + if (HOSTDATA(shpnt)->debug & debug_datai) + /* show what comes with the last transfer */ + if (done) { #if 0 - int i; - unsigned char *data; + int i; + unsigned char *data; #endif - - printk("data on last transfer (%d bytes) ", - 2*data_count); -#if 0 - printk("data on last transfer (%d bytes: ", - 2*data_count); - data = (unsigned char *) CURRENT_SC->SCp.ptr; - for(i=0; i<2*data_count; i++) - printk("%2x ", *data++); - printk("), "); -#endif - } -#endif - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* if this buffer is full and there are more buffers left */ - if(!CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } - - /* - * FIFO should be empty - */ - if(fifodata>0) { - printk("aha152x: more data than expected (%d bytes)\n", - GETPORT(FIFOSTAT)); - SETBITS(DMACNTRL0, _8BIT); - printk("aha152x: data ("); - while(fifodata--) - printk("%2x ", GETPORT(DATAPORT)); - printk(")\n"); - } + printk("data on last transfer (%d bytes) ", + 2 * data_count); +#if 0 + printk("data on last transfer (%d bytes: ", + 2 * data_count); + data = (unsigned char *) CURRENT_SC->SCp.ptr; + for (i = 0; i < 2 * data_count; i++) + printk("%2x ", *data++); + printk("), "); +#endif + } +#endif + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + /* if this buffer is full and there are more buffers left */ + if (!CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + /* + * FIFO should be empty + */ + if (fifodata > 0) { + printk("aha152x: more data than expected (%d bytes)\n", + GETPORT(FIFOSTAT)); + SETBITS(DMACNTRL0, _8BIT); + printk("aha152x: data ("); + while (fifodata--) + printk("%2x ", GETPORT(DATAPORT)); + printk(")\n"); + } #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - if(!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); + if (HOSTDATA(shpnt)->debug & debug_datai) + if (!fifodata) + printk("fifo empty, "); + else + printk("something left in fifo, "); #endif - } + } #if defined(DEBUG_DATAI) - if((HOSTDATA(shpnt)->debug & debug_datai) && - (CURRENT_SC->SCp.buffers_residual || - CURRENT_SC->SCp.this_residual)) - printk("left buffers (buffers=%d, bytes=%d), ", - CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); -#endif - /* transfer can be considered ended, when SCSIEN reads back zero */ - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); - CLRBITS(DMACNTRL0, ENDMA); + if ((HOSTDATA(shpnt)->debug & debug_datai) && + (CURRENT_SC->SCp.buffers_residual || + CURRENT_SC->SCp.this_residual)) + printk("left buffers (buffers=%d, bytes=%d), ", + CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); +#endif + /* transfer can be considered ended, when SCSIEN reads back zero */ + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + while (TESTHI(SXFRCTL0, SCSIEN)) + barrier(); + CLRBITS(DMACNTRL0, ENDMA); #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr)) - printk("got %d bytes, ", GETSTCNT()); + if (HOSTDATA(shpnt)->debug & (debug_datai | debug_intr)) + printk("got %d bytes, ", GETSTCNT()); #endif - CURRENT_SC->SCp.have_data_in++; - } - break; + CURRENT_SC->SCp.have_data_in++; + } + break; - case P_DATAO: /* DATA OUT phase */ - { - int data_count; + case P_DATAO: /* DATA OUT phase */ + { + int data_count; #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases)) - printk("DATA OUT, "); + if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr | debug_phases)) + printk("DATA OUT, "); #endif #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("got data to send (bytes=%d, buffers=%d), ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) { - printk("%d(%d) left in FIFO, ", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); - aha152x_panic(shpnt, "FIFO should be empty"); - } - - SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1); - SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); - - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - SETPORT(DMACNTRL0, ENDMA|WRITE_READ); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); - - /* while current buffer is not empty or - there are more buffers to transfer */ - while(TESTLO(SSTAT1, PHASEMIS) && - (CURRENT_SC->SCp.this_residual || - CURRENT_SC->SCp.buffers_residual)) { + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("got data to send (bytes=%d, buffers=%d), ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + + if (GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL | SFCNT)) { + printk("%d(%d) left in FIFO, ", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL | SFCNT)); + aha152x_panic(shpnt, "FIFO should be empty"); + } + SETPORT(SXFRCTL0, CH1 | CLRSTCNT | CLRCH1); + SETPORT(SXFRCTL0, SCSIEN | DMAEN | CH1); + + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + SETPORT(DMACNTRL0, ENDMA | WRITE_READ); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); + + /* while current buffer is not empty or + there are more buffers to transfer */ + while (TESTLO(SSTAT1, PHASEMIS) && + (CURRENT_SC->SCp.this_residual || + CURRENT_SC->SCp.buffers_residual)) { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - /* transfer rest of buffer, but max. 128 byte */ - data_count = - CURRENT_SC->SCp.this_residual > 128 ? - 128 : CURRENT_SC->SCp.this_residual ; + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("sending data (left: bytes=%d, buffers=%d), waiting, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + /* transfer rest of buffer, but max. 128 byte */ + data_count = + CURRENT_SC->SCp.this_residual > 128 ? + 128 : CURRENT_SC->SCp.this_residual; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("data_count=%d, ", data_count); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("data_count=%d, ", data_count); #endif - - if(data_count&1) { - /* put a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); - CURRENT_SC->SCp.this_residual--; - } - if(data_count>1) { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* number of words */ - outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* wait for FIFO to get empty */ - while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) - barrier(); + + if (data_count & 1) { + /* put a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); + CURRENT_SC->SCp.this_residual--; + } + if (data_count > 1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* number of words */ + outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + /* wait for FIFO to get empty */ + while (TESTLO(DMASTAT, DFIFOEMP | INTSTAT)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("fifo (%d bytes), transfered (%d bytes), ", - GETPORT(FIFOSTAT), GETSTCNT()); -#endif - - /* if this buffer is empty and there are more buffers left */ - if(TESTLO(SSTAT1, PHASEMIS) && - !CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } - - if(CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { - /* target leaves DATA OUT for an other phase (perhaps disconnect) */ - - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); - - data_count += GETPORT(FIFOSTAT) ; - CURRENT_SC->SCp.ptr -= data_count; - CURRENT_SC->SCp.this_residual += data_count; + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("fifo (%d bytes), transfered (%d bytes), ", + GETPORT(FIFOSTAT), GETSTCNT()); +#endif + + /* if this buffer is empty and there are more buffers left */ + if (TESTLO(SSTAT1, PHASEMIS) && + !CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { + /* target leaves DATA OUT for an other phase (perhaps disconnect) */ + + /* data in fifos has to be resend */ + data_count = GETPORT(SSTAT2) & (SFULL | SFCNT); + + data_count += GETPORT(FIFOSTAT); + CURRENT_SC->SCp.ptr -= data_count; + CURRENT_SC->SCp.this_residual += data_count; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " - "transfer incomplete, resetting fifo, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual, - data_count); -#endif - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - CLRBITS(DMACNTRL0, ENDMA); - } else { + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " + "transfer incomplete, resetting fifo, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual, + data_count); +#endif + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + CLRBITS(DMACNTRL0, ENDMA); + } else { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("waiting for SCSI fifo to get empty, "); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("waiting for SCSI fifo to get empty, "); #endif - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); + /* wait for SCSI fifo to get empty */ + while (TESTLO(SSTAT2, SEMPTY)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("ok, left data (bytes=%d, buffers=%d) ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - - /* transfer can be considered ended, when SCSIEN reads back zero */ - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); + if (HOSTDATA(shpnt)->debug & debug_datao) + printk("ok, left data (bytes=%d, buffers=%d) ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + CLRBITS(SXFRCTL0, SCSIEN | DMAEN); + + /* transfer can be considered ended, when SCSIEN reads back zero */ + while (TESTHI(SXFRCTL0, SCSIEN)) + barrier(); - CLRBITS(DMACNTRL0, ENDMA); - } + CLRBITS(DMACNTRL0, ENDMA); + } #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr)) - printk("sent %d data bytes, ", GETSTCNT()); + if (HOSTDATA(shpnt)->debug & (debug_datao | debug_intr)) + printk("sent %d data bytes, ", GETSTCNT()); #endif - } - break; + } + break; - case P_BUSFREE: /* BUSFREE */ + case P_BUSFREE: /* BUSFREE */ #if defined(DEBUG_RACE) - leave_driver("(BUSFREE) intr"); + leave_driver("(BUSFREE) intr"); #endif #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("unexpected BUS FREE, "); + if (HOSTDATA(shpnt)->debug & debug_phases) + printk("unexpected BUS FREE, "); #endif - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ - return; - break; + aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ + return; + break; - case P_PARITY: /* parity error in DATA phase */ + case P_PARITY: /* parity error in DATA phase */ #if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); + leave_driver("(DID_PARITY) intr"); #endif - printk("PARITY error in DATA phase, "); + printk("PARITY error in DATA phase, "); - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK << 16); - SETBITS(DMACNTRL0, INTEN); - aha152x_done(shpnt, DID_PARITY << 16); - return; - break; + SETBITS(DMACNTRL0, INTEN); + aha152x_done(shpnt, DID_PARITY << 16); + return; + break; - default: - printk("aha152x: unexpected phase\n"); - break; - } + default: + printk("aha152x: unexpected phase\n"); + break; + } - if(done) { + if (done) { #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - printk("command done.\n"); + if (HOSTDATA(shpnt)->debug & debug_intr) + printk("command done.\n"); #endif #if defined(DEBUG_RACE) - leave_driver("(done) intr"); + leave_driver("(done) intr"); #endif - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); - - SETBITS(DMACNTRL0, INTEN); - - aha152x_done(shpnt, - (CURRENT_SC->SCp.Status & 0xff) - | ((CURRENT_SC->SCp.Message & 0xff) << 8) - | (DID_OK << 16)); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + + SETBITS(DMACNTRL0, INTEN); + + aha152x_done(shpnt, + (CURRENT_SC->SCp.Status & 0xff) + | ((CURRENT_SC->SCp.Message & 0xff) << 8) + | (DID_OK << 16)); #if defined(DEBUG_RACE) - printk("done returned (DID_OK: Status=%x; Message=%x).\n", - CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); + printk("done returned (DID_OK: Status=%x; Message=%x).\n", + CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); #endif - return; - } - - if(CURRENT_SC) - CURRENT_SC->SCp.phase |= 1<<16; + return; + } + if (CURRENT_SC) + CURRENT_SC->SCp.phase |= 1 << 16; - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENBUSFREE); #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - disp_enintr(shpnt); + if (HOSTDATA(shpnt)->debug & debug_intr) + disp_enintr(shpnt); #endif #if defined(DEBUG_RACE) - leave_driver("(PHASEEND) intr"); + leave_driver("(PHASEEND) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; + SETBITS(DMACNTRL0, INTEN); + return; } /* @@ -2637,9 +2639,9 @@ */ static void aha152x_panic(struct Scsi_Host *shpnt, char *msg) { - printk("\naha152x: %s\n", msg); - show_queues(shpnt); - panic("aha152x panic"); + printk("\naha152x: %s\n", msg); + show_queues(shpnt); + panic("aha152x panic"); } /* @@ -2648,166 +2650,231 @@ static void disp_ports(struct Scsi_Host *shpnt) { #ifdef DEBUG_AHA152X - int s; + int s; #ifdef SKIP_PORTS - if(HOSTDATA(shpnt)->debug & debug_skipports) - return; + if (HOSTDATA(shpnt)->debug & debug_skipports) + return; #endif - printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); - s=GETPORT(SCSISEQ); - printk("SCSISEQ ("); - if(s & TEMODEO) printk("TARGET MODE "); - if(s & ENSELO) printk("SELO "); - if(s & ENSELI) printk("SELI "); - if(s & ENRESELI) printk("RESELI "); - if(s & ENAUTOATNO) printk("AUTOATNO "); - if(s & ENAUTOATNI) printk("AUTOATNI "); - if(s & ENAUTOATNP) printk("AUTOATNP "); - if(s & SCSIRSTO) printk("SCSIRSTO "); - printk(");"); - - printk(" SCSISIG ("); - s=GETPORT(SCSISIG); - switch(s & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - - printk("); "); - - printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - printk("SSTAT ("); - s=GETPORT(SSTAT0); - if(s & TARGET) printk("TARGET "); - if(s & SELDO) printk("SELDO "); - if(s & SELDI) printk("SELDI "); - if(s & SELINGO) printk("SELINGO "); - if(s & SWRAP) printk("SWRAP "); - if(s & SDONE) printk("SDONE "); - if(s & SPIORDY) printk("SPIORDY "); - if(s & DMADONE) printk("DMADONE "); - - s=GETPORT(SSTAT1); - if(s & SELTO) printk("SELTO "); - if(s & ATNTARG) printk("ATNTARG "); - if(s & SCSIRSTI) printk("SCSIRSTI "); - if(s & PHASEMIS) printk("PHASEMIS "); - if(s & BUSFREE) printk("BUSFREE "); - if(s & SCSIPERR) printk("SCSIPERR "); - if(s & PHASECHG) printk("PHASECHG "); - if(s & REQINIT) printk("REQINIT "); - printk("); "); - - - printk("SSTAT ("); - - s=GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if(s & TARGET) printk("TARGET "); - if(s & SELDO) printk("SELDO "); - if(s & SELDI) printk("SELDI "); - if(s & SELINGO) printk("SELINGO "); - if(s & SWRAP) printk("SWRAP "); - if(s & SDONE) printk("SDONE "); - if(s & SPIORDY) printk("SPIORDY "); - if(s & DMADONE) printk("DMADONE "); - - s=GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if(s & SELTO) printk("SELTO "); - if(s & ATNTARG) printk("ATNTARG "); - if(s & SCSIRSTI) printk("SCSIRSTI "); - if(s & PHASEMIS) printk("PHASEMIS "); - if(s & BUSFREE) printk("BUSFREE "); - if(s & SCSIPERR) printk("SCSIPERR "); - if(s & PHASECHG) printk("PHASECHG "); - if(s & REQINIT) printk("REQINIT "); - printk("); "); - - printk("SXFRCTL0 ("); - - s=GETPORT(SXFRCTL0); - if(s & SCSIEN) printk("SCSIEN "); - if(s & DMAEN) printk("DMAEN "); - if(s & CH1) printk("CH1 "); - if(s & CLRSTCNT) printk("CLRSTCNT "); - if(s & SPIOEN) printk("SPIOEN "); - if(s & CLRCH1) printk("CLRCH1 "); - printk("); "); - - printk("SIGNAL ("); - - s=GETPORT(SCSISIG); - if(s & ATNI) printk("ATNI "); - if(s & SELI) printk("SELI "); - if(s & BSYI) printk("BSYI "); - if(s & REQI) printk("REQI "); - if(s & ACKI) printk("ACKI "); - printk("); "); - - printk("SELID (%02x), ", GETPORT(SELID)); - - printk("SSTAT2 ("); - - s=GETPORT(SSTAT2); - if(s & SOFFSET) printk("SOFFSET "); - if(s & SEMPTY) printk("SEMPTY "); - if(s & SFULL) printk("SFULL "); - printk("); SFCNT (%d); ", s & (SFULL|SFCNT)); - - s=GETPORT(SSTAT3); - printk("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); - - printk("SSTAT4 ("); - s=GETPORT(SSTAT4); - if(s & SYNCERR) printk("SYNCERR "); - if(s & FWERR) printk("FWERR "); - if(s & FRERR) printk("FRERR "); - printk("); "); - - printk("DMACNTRL0 ("); - s=GETPORT(DMACNTRL0); - printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); - printk("%s ", s & DMA ? "DMA" : "PIO" ); - printk("%s ", s & WRITE_READ ? "WRITE" : "READ" ); - if(s & ENDMA) printk("ENDMA "); - if(s & INTEN) printk("INTEN "); - if(s & RSTFIFO) printk("RSTFIFO "); - if(s & SWINT) printk("SWINT "); - printk("); "); - - printk("DMASTAT ("); - s=GETPORT(DMASTAT); - if(s & ATDONE) printk("ATDONE "); - if(s & WORDRDY) printk("WORDRDY "); - if(s & DFIFOFULL) printk("DFIFOFULL "); - if(s & DFIFOEMP) printk("DFIFOEMP "); - printk(")"); + s = GETPORT(SCSISEQ); + printk("SCSISEQ ("); + if (s & TEMODEO) + printk("TARGET MODE "); + if (s & ENSELO) + printk("SELO "); + if (s & ENSELI) + printk("SELI "); + if (s & ENRESELI) + printk("RESELI "); + if (s & ENAUTOATNO) + printk("AUTOATNO "); + if (s & ENAUTOATNI) + printk("AUTOATNI "); + if (s & ENAUTOATNP) + printk("AUTOATNP "); + if (s & SCSIRSTO) + printk("SCSIRSTO "); + printk(");"); + + printk(" SCSISIG ("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } + + printk("); "); + + printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - printk("\n"); + printk("SSTAT ("); + s = GETPORT(SSTAT0); + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + + printk("SSTAT ("); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + printk("SXFRCTL0 ("); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + printk("SCSIEN "); + if (s & DMAEN) + printk("DMAEN "); + if (s & CH1) + printk("CH1 "); + if (s & CLRSTCNT) + printk("CLRSTCNT "); + if (s & SPIOEN) + printk("SPIOEN "); + if (s & CLRCH1) + printk("CLRCH1 "); + printk("); "); + + printk("SIGNAL ("); + + s = GETPORT(SCSISIG); + if (s & ATNI) + printk("ATNI "); + if (s & SELI) + printk("SELI "); + if (s & BSYI) + printk("BSYI "); + if (s & REQI) + printk("REQI "); + if (s & ACKI) + printk("ACKI "); + printk("); "); + + printk("SELID (%02x), ", GETPORT(SELID)); + + printk("SSTAT2 ("); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + printk("SOFFSET "); + if (s & SEMPTY) + printk("SEMPTY "); + if (s & SFULL) + printk("SFULL "); + printk("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + printk("SSTAT4 ("); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + printk("SYNCERR "); + if (s & FWERR) + printk("FWERR "); + if (s & FRERR) + printk("FRERR "); + printk("); "); + + printk("DMACNTRL0 ("); + s = GETPORT(DMACNTRL0); + printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); + printk("%s ", s & DMA ? "DMA" : "PIO"); + printk("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + printk("ENDMA "); + if (s & INTEN) + printk("INTEN "); + if (s & RSTFIFO) + printk("RSTFIFO "); + if (s & SWINT) + printk("SWINT "); + printk("); "); + + printk("DMASTAT ("); + s = GETPORT(DMASTAT); + if (s & ATDONE) + printk("ATDONE "); + if (s & WORDRDY) + printk("WORDRDY "); + if (s & DFIFOFULL) + printk("DFIFOFULL "); + if (s & DFIFOEMP) + printk("DFIFOEMP "); + printk(")"); + + printk("\n"); #endif } @@ -2816,518 +2883,618 @@ */ static void disp_enintr(struct Scsi_Host *shpnt) { - int s; + int s; + + printk("enabled interrupts ("); - printk("enabled interrupts ("); - - s=GETPORT(SIMODE0); - if(s & ENSELDO) printk("ENSELDO "); - if(s & ENSELDI) printk("ENSELDI "); - if(s & ENSELINGO) printk("ENSELINGO "); - if(s & ENSWRAP) printk("ENSWRAP "); - if(s & ENSDONE) printk("ENSDONE "); - if(s & ENSPIORDY) printk("ENSPIORDY "); - if(s & ENDMADONE) printk("ENDMADONE "); - - s=GETPORT(SIMODE1); - if(s & ENSELTIMO) printk("ENSELTIMO "); - if(s & ENATNTARG) printk("ENATNTARG "); - if(s & ENPHASEMIS) printk("ENPHASEMIS "); - if(s & ENBUSFREE) printk("ENBUSFREE "); - if(s & ENSCSIPERR) printk("ENSCSIPERR "); - if(s & ENPHASECHG) printk("ENPHASECHG "); - if(s & ENREQINIT) printk("ENREQINIT "); - printk(")\n"); + s = GETPORT(SIMODE0); + if (s & ENSELDO) + printk("ENSELDO "); + if (s & ENSELDI) + printk("ENSELDI "); + if (s & ENSELINGO) + printk("ENSELINGO "); + if (s & ENSWRAP) + printk("ENSWRAP "); + if (s & ENSDONE) + printk("ENSDONE "); + if (s & ENSPIORDY) + printk("ENSPIORDY "); + if (s & ENDMADONE) + printk("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + printk("ENSELTIMO "); + if (s & ENATNTARG) + printk("ENATNTARG "); + if (s & ENPHASEMIS) + printk("ENPHASEMIS "); + if (s & ENBUSFREE) + printk("ENBUSFREE "); + if (s & ENSCSIPERR) + printk("ENSCSIPERR "); + if (s & ENPHASECHG) + printk("ENPHASECHG "); + if (s & ENREQINIT) + printk("ENREQINIT "); + printk(")\n"); } #if defined(DEBUG_RACE) static const char *should_leave; -static int in_driver=0; +static int in_driver = 0; /* * Only one routine can be in the driver at once. */ static void enter_driver(const char *func) { - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); - printk("aha152x: entering %s() (%x)\n", func, jiffies); - if(in_driver) { - printk("%s should leave first.\n", should_leave); - panic("aha152x: already in driver\n"); - } - - in_driver++; - should_leave=func; - restore_flags(flags); + save_flags(flags); + cli(); + printk("aha152x: entering %s() (%x)\n", func, jiffies); + if (in_driver) { + printk("%s should leave first.\n", should_leave); + panic("aha152x: already in driver\n"); + } + in_driver++; + should_leave = func; + restore_flags(flags); } static void leave_driver(const char *func) { - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); - printk("\naha152x: leaving %s() (%x)\n", func, jiffies); - if(!in_driver) { - printk("aha152x: %s already left.\n", should_leave); - panic("aha152x: %s already left driver.\n"); - } - - in_driver--; - should_leave=func; - restore_flags(flags); + save_flags(flags); + cli(); + printk("\naha152x: leaving %s() (%x)\n", func, jiffies); + if (!in_driver) { + printk("aha152x: %s already left.\n", should_leave); + panic("aha152x: %s already left driver.\n"); + } + in_driver--; + should_leave = func; + restore_flags(flags); } #endif /* * Show the command data of a command */ -static void show_command(Scsi_Cmnd *ptr) +static void show_command(Scsi_Cmnd * ptr) { - printk("0x%08x: target=%d; lun=%d; cmnd=(", - (unsigned int) ptr, ptr->target, ptr->lun); - - print_command(ptr->cmnd); - - printk("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); - - if(ptr->SCp.phase & not_issued ) printk("not issued|"); - if(ptr->SCp.phase & in_selection) printk("in selection|"); - if(ptr->SCp.phase & disconnected) printk("disconnected|"); - if(ptr->SCp.phase & aborted ) printk("aborted|"); - if(ptr->SCp.phase & sent_ident ) printk("send_ident|"); - if(ptr->SCp.phase & in_other) { - printk("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - printk(")"); - if(ptr->SCp.phase & (1<<16)) - printk("; phaseend"); - } - printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + printk("0x%08x: target=%d; lun=%d; cmnd=(", + (unsigned int) ptr, ptr->target, ptr->lun); + + print_command(ptr->cmnd); + + printk("); residual=%d; buffers=%d; phase |", + ptr->SCp.this_residual, ptr->SCp.buffers_residual); + + if (ptr->SCp.phase & not_issued) + printk("not issued|"); + if (ptr->SCp.phase & in_selection) + printk("in selection|"); + if (ptr->SCp.phase & disconnected) + printk("disconnected|"); + if (ptr->SCp.phase & aborted) + printk("aborted|"); + if (ptr->SCp.phase & sent_ident) + printk("send_ident|"); + if (ptr->SCp.phase & in_other) { + printk("; in other("); + switch ((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } + printk(")"); + if (ptr->SCp.phase & (1 << 16)) + printk("; phaseend"); + } + printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); } - + /* * Dump the queued data */ static void show_queues(struct Scsi_Host *shpnt) { - unsigned long flags; - Scsi_Cmnd *ptr; + unsigned long flags; + Scsi_Cmnd *ptr; - save_flags(flags); - cli(); - printk("QUEUE STATUS:\nissue_SC:\n"); - for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - show_command(ptr); - - printk("current_SC:\n"); - if(CURRENT_SC) - show_command(CURRENT_SC); - else - printk("none\n"); - - printk("disconnected_SC:\n"); - for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - show_command(ptr); - - disp_ports(shpnt); - disp_enintr(shpnt); - restore_flags(flags); + save_flags(flags); + cli(); + printk("QUEUE STATUS:\nissue_SC:\n"); + for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + show_command(ptr); + + printk("current_SC:\n"); + if (CURRENT_SC) + show_command(CURRENT_SC); + else + printk("none\n"); + + printk("disconnected_SC:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + show_command(ptr); + + disp_ports(shpnt); + disp_enintr(shpnt); + restore_flags(flags); } int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) { - return(-ENOSYS); /* Currently this is a no-op */ + return (-ENOSYS); /* Currently this is a no-op */ } #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, ## args) -static int get_command(char *pos, Scsi_Cmnd *ptr) +static int get_command(char *pos, Scsi_Cmnd * ptr) { - char *start = pos; - int i; - - SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", - (unsigned int) ptr, ptr->target, ptr->lun); - - for(i=0; icmnd[0]); i++) - SPRINTF("0x%02x ", ptr->cmnd[i]); - - SPRINTF("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); - - if(ptr->SCp.phase & not_issued ) SPRINTF("not issued|"); - if(ptr->SCp.phase & in_selection) SPRINTF("in selection|"); - if(ptr->SCp.phase & disconnected) SPRINTF("disconnected|"); - if(ptr->SCp.phase & aborted ) SPRINTF("aborted|"); - if(ptr->SCp.phase & sent_ident ) SPRINTF("send_ident|"); - if(ptr->SCp.phase & in_other) { - SPRINTF("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - SPRINTF(")"); - if(ptr->SCp.phase & (1<<16)) - SPRINTF("; phaseend"); - } - SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); - - return(pos-start); + char *start = pos; + int i; + + SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", + (unsigned int) ptr, ptr->target, ptr->lun); + + for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) + SPRINTF("0x%02x ", ptr->cmnd[i]); + + SPRINTF("); residual=%d; buffers=%d; phase |", + ptr->SCp.this_residual, ptr->SCp.buffers_residual); + + if (ptr->SCp.phase & not_issued) + SPRINTF("not issued|"); + if (ptr->SCp.phase & in_selection) + SPRINTF("in selection|"); + if (ptr->SCp.phase & disconnected) + SPRINTF("disconnected|"); + if (ptr->SCp.phase & aborted) + SPRINTF("aborted|"); + if (ptr->SCp.phase & sent_ident) + SPRINTF("send_ident|"); + if (ptr->SCp.phase & in_other) { + SPRINTF("; in other("); + switch ((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + SPRINTF(")"); + if (ptr->SCp.phase & (1 << 16)) + SPRINTF("; phaseend"); + } + SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); + + return (pos - start); } static int get_ports(struct Scsi_Host *shpnt, char *pos) { - char *start = pos; - int s; + char *start = pos; + int s; #ifdef SKIP_PORTS - if(HOSTDATA(shpnt)->debug & debug_skipports) - return; + if (HOSTDATA(shpnt)->debug & debug_skipports) + return; #endif - SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + + s = GETPORT(SCSISEQ); + SPRINTF("SCSISEQ ("); + if (s & TEMODEO) + SPRINTF("TARGET MODE "); + if (s & ENSELO) + SPRINTF("SELO "); + if (s & ENSELI) + SPRINTF("SELI "); + if (s & ENRESELI) + SPRINTF("RESELI "); + if (s & ENAUTOATNO) + SPRINTF("AUTOATNO "); + if (s & ENAUTOATNI) + SPRINTF("AUTOATNI "); + if (s & ENAUTOATNP) + SPRINTF("AUTOATNP "); + if (s & SCSIRSTO) + SPRINTF("SCSIRSTO "); + SPRINTF(");"); + + SPRINTF(" SCSISIG ("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + + SPRINTF("); "); + + SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - s=GETPORT(SCSISEQ); - SPRINTF("SCSISEQ ("); - if(s & TEMODEO) SPRINTF("TARGET MODE "); - if(s & ENSELO) SPRINTF("SELO "); - if(s & ENSELI) SPRINTF("SELI "); - if(s & ENRESELI) SPRINTF("RESELI "); - if(s & ENAUTOATNO) SPRINTF("AUTOATNO "); - if(s & ENAUTOATNI) SPRINTF("AUTOATNI "); - if(s & ENAUTOATNP) SPRINTF("AUTOATNP "); - if(s & SCSIRSTO) SPRINTF("SCSIRSTO "); - SPRINTF(");"); - - SPRINTF(" SCSISIG ("); - s=GETPORT(SCSISIG); - switch(s & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - - SPRINTF("); "); - - SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - SPRINTF("SSTAT ("); - s=GETPORT(SSTAT0); - if(s & TARGET) SPRINTF("TARGET "); - if(s & SELDO) SPRINTF("SELDO "); - if(s & SELDI) SPRINTF("SELDI "); - if(s & SELINGO) SPRINTF("SELINGO "); - if(s & SWRAP) SPRINTF("SWRAP "); - if(s & SDONE) SPRINTF("SDONE "); - if(s & SPIORDY) SPRINTF("SPIORDY "); - if(s & DMADONE) SPRINTF("DMADONE "); - - s=GETPORT(SSTAT1); - if(s & SELTO) SPRINTF("SELTO "); - if(s & ATNTARG) SPRINTF("ATNTARG "); - if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); - if(s & PHASEMIS) SPRINTF("PHASEMIS "); - if(s & BUSFREE) SPRINTF("BUSFREE "); - if(s & SCSIPERR) SPRINTF("SCSIPERR "); - if(s & PHASECHG) SPRINTF("PHASECHG "); - if(s & REQINIT) SPRINTF("REQINIT "); - SPRINTF("); "); - - - SPRINTF("SSTAT ("); - - s=GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if(s & TARGET) SPRINTF("TARGET "); - if(s & SELDO) SPRINTF("SELDO "); - if(s & SELDI) SPRINTF("SELDI "); - if(s & SELINGO) SPRINTF("SELINGO "); - if(s & SWRAP) SPRINTF("SWRAP "); - if(s & SDONE) SPRINTF("SDONE "); - if(s & SPIORDY) SPRINTF("SPIORDY "); - if(s & DMADONE) SPRINTF("DMADONE "); - - s=GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if(s & SELTO) SPRINTF("SELTO "); - if(s & ATNTARG) SPRINTF("ATNTARG "); - if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); - if(s & PHASEMIS) SPRINTF("PHASEMIS "); - if(s & BUSFREE) SPRINTF("BUSFREE "); - if(s & SCSIPERR) SPRINTF("SCSIPERR "); - if(s & PHASECHG) SPRINTF("PHASECHG "); - if(s & REQINIT) SPRINTF("REQINIT "); - SPRINTF("); "); - - SPRINTF("SXFRCTL0 ("); - - s=GETPORT(SXFRCTL0); - if(s & SCSIEN) SPRINTF("SCSIEN "); - if(s & DMAEN) SPRINTF("DMAEN "); - if(s & CH1) SPRINTF("CH1 "); - if(s & CLRSTCNT) SPRINTF("CLRSTCNT "); - if(s & SPIOEN) SPRINTF("SPIOEN "); - if(s & CLRCH1) SPRINTF("CLRCH1 "); - SPRINTF("); "); - - SPRINTF("SIGNAL ("); - - s=GETPORT(SCSISIG); - if(s & ATNI) SPRINTF("ATNI "); - if(s & SELI) SPRINTF("SELI "); - if(s & BSYI) SPRINTF("BSYI "); - if(s & REQI) SPRINTF("REQI "); - if(s & ACKI) SPRINTF("ACKI "); - SPRINTF("); "); - - SPRINTF("SELID (%02x), ", GETPORT(SELID)); - - SPRINTF("SSTAT2 ("); - - s=GETPORT(SSTAT2); - if(s & SOFFSET) SPRINTF("SOFFSET "); - if(s & SEMPTY) SPRINTF("SEMPTY "); - if(s & SFULL) SPRINTF("SFULL "); - SPRINTF("); SFCNT (%d); ", s & (SFULL|SFCNT)); - - s=GETPORT(SSTAT3); - SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); - - SPRINTF("SSTAT4 ("); - s=GETPORT(SSTAT4); - if(s & SYNCERR) SPRINTF("SYNCERR "); - if(s & FWERR) SPRINTF("FWERR "); - if(s & FRERR) SPRINTF("FRERR "); - SPRINTF("); "); - - SPRINTF("DMACNTRL0 ("); - s=GETPORT(DMACNTRL0); - SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); - SPRINTF("%s ", s & DMA ? "DMA" : "PIO" ); - SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ" ); - if(s & ENDMA) SPRINTF("ENDMA "); - if(s & INTEN) SPRINTF("INTEN "); - if(s & RSTFIFO) SPRINTF("RSTFIFO "); - if(s & SWINT) SPRINTF("SWINT "); - SPRINTF("); "); - - SPRINTF("DMASTAT ("); - s=GETPORT(DMASTAT); - if(s & ATDONE) SPRINTF("ATDONE "); - if(s & WORDRDY) SPRINTF("WORDRDY "); - if(s & DFIFOFULL) SPRINTF("DFIFOFULL "); - if(s & DFIFOEMP) SPRINTF("DFIFOEMP "); - SPRINTF(")\n\n"); - - SPRINTF("enabled interrupts ("); - - s=GETPORT(SIMODE0); - if(s & ENSELDO) SPRINTF("ENSELDO "); - if(s & ENSELDI) SPRINTF("ENSELDI "); - if(s & ENSELINGO) SPRINTF("ENSELINGO "); - if(s & ENSWRAP) SPRINTF("ENSWRAP "); - if(s & ENSDONE) SPRINTF("ENSDONE "); - if(s & ENSPIORDY) SPRINTF("ENSPIORDY "); - if(s & ENDMADONE) SPRINTF("ENDMADONE "); - - s=GETPORT(SIMODE1); - if(s & ENSELTIMO) SPRINTF("ENSELTIMO "); - if(s & ENATNTARG) SPRINTF("ENATNTARG "); - if(s & ENPHASEMIS) SPRINTF("ENPHASEMIS "); - if(s & ENBUSFREE) SPRINTF("ENBUSFREE "); - if(s & ENSCSIPERR) SPRINTF("ENSCSIPERR "); - if(s & ENPHASECHG) SPRINTF("ENPHASECHG "); - if(s & ENREQINIT) SPRINTF("ENREQINIT "); - SPRINTF(")\n"); - - return (pos-start); + SPRINTF("SSTAT ("); + s = GETPORT(SSTAT0); + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + + SPRINTF("SSTAT ("); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + SPRINTF("SXFRCTL0 ("); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + SPRINTF("SCSIEN "); + if (s & DMAEN) + SPRINTF("DMAEN "); + if (s & CH1) + SPRINTF("CH1 "); + if (s & CLRSTCNT) + SPRINTF("CLRSTCNT "); + if (s & SPIOEN) + SPRINTF("SPIOEN "); + if (s & CLRCH1) + SPRINTF("CLRCH1 "); + SPRINTF("); "); + + SPRINTF("SIGNAL ("); + + s = GETPORT(SCSISIG); + if (s & ATNI) + SPRINTF("ATNI "); + if (s & SELI) + SPRINTF("SELI "); + if (s & BSYI) + SPRINTF("BSYI "); + if (s & REQI) + SPRINTF("REQI "); + if (s & ACKI) + SPRINTF("ACKI "); + SPRINTF("); "); + + SPRINTF("SELID (%02x), ", GETPORT(SELID)); + + SPRINTF("SSTAT2 ("); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + SPRINTF("SOFFSET "); + if (s & SEMPTY) + SPRINTF("SEMPTY "); + if (s & SFULL) + SPRINTF("SFULL "); + SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + SPRINTF("SSTAT4 ("); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + SPRINTF("SYNCERR "); + if (s & FWERR) + SPRINTF("FWERR "); + if (s & FRERR) + SPRINTF("FRERR "); + SPRINTF("); "); + + SPRINTF("DMACNTRL0 ("); + s = GETPORT(DMACNTRL0); + SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); + SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); + SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + SPRINTF("ENDMA "); + if (s & INTEN) + SPRINTF("INTEN "); + if (s & RSTFIFO) + SPRINTF("RSTFIFO "); + if (s & SWINT) + SPRINTF("SWINT "); + SPRINTF("); "); + + SPRINTF("DMASTAT ("); + s = GETPORT(DMASTAT); + if (s & ATDONE) + SPRINTF("ATDONE "); + if (s & WORDRDY) + SPRINTF("WORDRDY "); + if (s & DFIFOFULL) + SPRINTF("DFIFOFULL "); + if (s & DFIFOEMP) + SPRINTF("DFIFOEMP "); + SPRINTF(")\n\n"); + + SPRINTF("enabled interrupts ("); + + s = GETPORT(SIMODE0); + if (s & ENSELDO) + SPRINTF("ENSELDO "); + if (s & ENSELDI) + SPRINTF("ENSELDI "); + if (s & ENSELINGO) + SPRINTF("ENSELINGO "); + if (s & ENSWRAP) + SPRINTF("ENSWRAP "); + if (s & ENSDONE) + SPRINTF("ENSDONE "); + if (s & ENSPIORDY) + SPRINTF("ENSPIORDY "); + if (s & ENDMADONE) + SPRINTF("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + SPRINTF("ENSELTIMO "); + if (s & ENATNTARG) + SPRINTF("ENATNTARG "); + if (s & ENPHASEMIS) + SPRINTF("ENPHASEMIS "); + if (s & ENBUSFREE) + SPRINTF("ENBUSFREE "); + if (s & ENSCSIPERR) + SPRINTF("ENSCSIPERR "); + if (s & ENPHASECHG) + SPRINTF("ENPHASECHG "); + if (s & ENREQINIT) + SPRINTF("ENREQINIT "); + SPRINTF(")\n"); + + return (pos - start); } #undef SPRINTF #define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) int aha152x_proc_info(char *buffer, char **start, - off_t offset, int length, int hostno, int inout) + off_t offset, int length, int hostno, int inout) { - int i; - char *pos = buffer; - struct Scsi_Host *shpnt; - unsigned long flags; - Scsi_Cmnd *ptr; - - for(i=0, shpnt= (struct Scsi_Host *) NULL; ihost_no == hostno) - shpnt=aha152x_host[i]; - - if(!shpnt) - return(-ESRCH); - - if(inout) /* Has data been written to the file ? */ - return(aha152x_set_info(buffer, length, shpnt)); - - SPRINTF(AHA152X_REVID "\n"); - - save_flags(flags); - cli(); - - SPRINTF("ioports 0x%04lx to 0x%04lx\n", - shpnt->io_port, shpnt->io_port+shpnt->n_io_port-1); - SPRINTF("interrupt 0x%02x\n", shpnt->irq); - SPRINTF("disconnection/reconnection %s\n", - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled"); - SPRINTF("parity checking %s\n", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); - SPRINTF("synchronous transfers %s\n", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); - SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); - - if(HOSTDATA(shpnt)->synchronous) { + int i; + char *pos = buffer; + struct Scsi_Host *shpnt; + unsigned long flags; + Scsi_Cmnd *ptr; + + for (i = 0, shpnt = (struct Scsi_Host *) NULL; i < IRQS; i++) + if (aha152x_host[i] && aha152x_host[i]->host_no == hostno) + shpnt = aha152x_host[i]; + + if (!shpnt) + return (-ESRCH); + + if (inout) /* Has data been written to the file ? */ + return (aha152x_set_info(buffer, length, shpnt)); + + SPRINTF(AHA152X_REVID "\n"); + + save_flags(flags); + cli(); + + SPRINTF("ioports 0x%04lx to 0x%04lx\n", + shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); + SPRINTF("interrupt 0x%02x\n", shpnt->irq); + SPRINTF("disconnection/reconnection %s\n", + HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled"); + SPRINTF("parity checking %s\n", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); + SPRINTF("synchronous transfers %s\n", + HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); + SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); + + if (HOSTDATA(shpnt)->synchronous) { #if 0 - SPRINTF("synchronously operating targets (tick=%ld ns):\n", - 250000000/loops_per_sec); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)* - 250000000/loops_per_sec, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=%ld ns):\n", + 250000000 / loops_per_sec); + for (i = 0; i < 8; i++) + if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) + SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * + 250000000 / loops_per_sec, + HOSTDATA(shpnt)->syncrate[i] & 0x0f); #else - SPRINTF("synchronously operating targets (tick=50 ns):\n"); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=50 ns):\n"); + for (i = 0; i < 8; i++) + if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) + SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, + HOSTDATA(shpnt)->syncrate[i] & 0x0f); #endif - } - + } #ifdef DEBUG_AHA152X #define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); - - SPRINTF("enabled debugging options: "); - - PDEBUG(debug_skipports, "skip ports"); - PDEBUG(debug_queue, "queue"); - PDEBUG(debug_intr, "interrupt"); - PDEBUG(debug_selection, "selection"); - PDEBUG(debug_msgo, "message out"); - PDEBUG(debug_msgi, "message in"); - PDEBUG(debug_status, "status"); - PDEBUG(debug_cmd, "command"); - PDEBUG(debug_datai, "data in"); - PDEBUG(debug_datao, "data out"); - PDEBUG(debug_abort, "abort"); - PDEBUG(debug_done, "done"); - PDEBUG(debug_biosparam, "bios parameters"); - PDEBUG(debug_phases, "phases"); - PDEBUG(debug_queues, "queues"); - PDEBUG(debug_reset, "reset"); - - SPRINTF("\n"); -#endif - - SPRINTF("\nqueue status:\n"); - if(ISSUE_SC) { - SPRINTF("not yet issued commands:\n"); - for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); - } else - SPRINTF("no not yet issued commands\n"); - - if(CURRENT_SC) { - SPRINTF("current command:\n"); - pos += get_command(pos, CURRENT_SC); - } else - SPRINTF("no current command\n"); - - if(DISCONNECTED_SC) { - SPRINTF("disconnected commands:\n"); - for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); - } else - SPRINTF("no disconnected commands\n"); - - restore_flags(flags); - - pos += get_ports(shpnt, pos); - - *start=buffer+offset; - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; + + SPRINTF("enabled debugging options: "); + + PDEBUG(debug_skipports, "skip ports"); + PDEBUG(debug_queue, "queue"); + PDEBUG(debug_intr, "interrupt"); + PDEBUG(debug_selection, "selection"); + PDEBUG(debug_msgo, "message out"); + PDEBUG(debug_msgi, "message in"); + PDEBUG(debug_status, "status"); + PDEBUG(debug_cmd, "command"); + PDEBUG(debug_datai, "data in"); + PDEBUG(debug_datao, "data out"); + PDEBUG(debug_abort, "abort"); + PDEBUG(debug_done, "done"); + PDEBUG(debug_biosparam, "bios parameters"); + PDEBUG(debug_phases, "phases"); + PDEBUG(debug_queues, "queues"); + PDEBUG(debug_reset, "reset"); + + SPRINTF("\n"); +#endif + + SPRINTF("\nqueue status:\n"); + if (ISSUE_SC) { + SPRINTF("not yet issued commands:\n"); + for (ptr = ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no not yet issued commands\n"); + + if (CURRENT_SC) { + SPRINTF("current command:\n"); + pos += get_command(pos, CURRENT_SC); + } else + SPRINTF("no current command\n"); + + if (DISCONNECTED_SC) { + SPRINTF("disconnected commands:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no disconnected commands\n"); + + restore_flags(flags); + + pos += get_ports(shpnt, pos); + + *start = buffer + offset; + if (pos - buffer < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + else + return length; } #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aha1542.c linux.ac/drivers/scsi/aha1542.c --- linux.vanilla/drivers/scsi/aha1542.c Sun Nov 8 15:07:48 1998 +++ linux.ac/drivers/scsi/aha1542.c Mon Jul 19 03:58:53 1999 @@ -18,6 +18,9 @@ * 1-Jan-97 * Modified by Bjorn L. Thordarson and Einar Thor Einarsson * Recognize that DMA0 is valid DMA channel -- 13-Jul-98 + * Modified by Chris Faulhaber + * Added module command-line options + * 18-Jul-99 */ #include @@ -84,7 +87,7 @@ static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL}; /* - * LILO params: aha1542=[,,[,]] + * LILO/Module params: aha1542=[,,[,]] * * Where: is any of the valid AHA addresses: * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 @@ -100,6 +103,11 @@ * Factory default is 5 MB/s. */ +#if defined(MODULE) +int aha1542[] = { 0x330, 11, 4, -1 }; +MODULE_PARM(aha1542, "1-4i"); +#endif + #define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ #define BIOS_TRANSLATION_6432 1 /* Default case these days */ #define BIOS_TRANSLATION_25563 2 /* Big disk case */ @@ -823,7 +831,8 @@ mbenable_cmd[1]=0; mbenable_cmd[2]=mbenable_result[1]; - if(mbenable_result[1] & 0x03) retval = BIOS_TRANSLATION_25563; + if((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) + retval = BIOS_TRANSLATION_25563; aha1542_out(base,mbenable_cmd,3); WAIT(INTRFLAGS(base),INTRMASK,HACC,0); @@ -953,6 +962,14 @@ DEB(printk("aha1542_detect: \n")); tpnt->proc_dir = &proc_scsi_aha1542; + +#ifdef MODULE + bases[0] = 4; + bases[1] = aha1542[0]; + bases[2] = aha1542[1]; + bases[3] = aha1542[2]; + bases[4] = aha1542[3]; +#endif for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++) if(bases[indx] != 0 && !check_region(bases[indx], 4)) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg linux.ac/drivers/scsi/aic7xxx/aic7xxx.reg --- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg Tue Jun 15 16:49:50 1999 +++ linux.ac/drivers/scsi/aic7xxx/aic7xxx.reg Mon Jul 19 20:16:25 1999 @@ -845,7 +845,7 @@ bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ bit CRCREQCHKEN 0x10 bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ - bit TARGCRCCNTEN 0x40 /* Enable CRC transfer when target */ + bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ } /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx.c linux.ac/drivers/scsi/aic7xxx.c --- linux.vanilla/drivers/scsi/aic7xxx.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/aic7xxx.c Mon Jul 19 20:16:25 1999 @@ -270,7 +270,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.17" +#define AIC7XXX_C_VERSION "5.1.19" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -7412,73 +7412,83 @@ /*+F************************************************************************* * Function: - * write_brdctl + * read_brdctl * * Description: - * Writes a value to the BRDCTL register. + * Reads the BRDCTL register. *-F*************************************************************************/ -static void -write_brdctl(struct aic7xxx_host *p, unsigned char value) +static unsigned char +read_brdctl(struct aic7xxx_host *p) { - unsigned char brdctl; + unsigned char brdctl, value; - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) + if (p->features & AHC_ULTRA2) { - brdctl = BRDSTB; - if (p->flags & AHC_CHNLB) - brdctl |= BRDCS; + brdctl = BRDRW_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + return(aic_inb(p, BRDCTL)); + } + brdctl = BRDRW; + if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || + (p->flags & AHC_CHNLB) ) + { + brdctl |= BRDCS; } - else if (p->features & AHC_ULTRA2) - brdctl = 0; - else - brdctl = BRDSTB | BRDCS; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - brdctl |= value; aic_outb(p, brdctl, BRDCTL); udelay(1); - if (p->features & AHC_ULTRA2) - brdctl |= BRDSTB_ULTRA2; - else - brdctl &= ~BRDSTB; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - if (p->features & AHC_ULTRA2) - brdctl = 0; - else - brdctl &= ~BRDCS; - aic_outb(p, brdctl, BRDCTL); + value = aic_inb(p, BRDCTL); + aic_outb(p, 0, BRDCTL); udelay(1); + return (value); } /*+F************************************************************************* * Function: - * read_brdctl + * write_brdctl * * Description: - * Reads the BRDCTL register. + * Writes a value to the BRDCTL register. *-F*************************************************************************/ -static unsigned char -read_brdctl(struct aic7xxx_host *p) +static void +write_brdctl(struct aic7xxx_host *p, unsigned char value) { - unsigned char brdctl, value; + unsigned char brdctl; - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) + if (p->features & AHC_ULTRA2) { - brdctl = BRDRW; - if (p->flags & AHC_CHNLB) - brdctl |= BRDCS; + brdctl = value; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + brdctl |= BRDSTB_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + brdctl &= ~BRDSTB_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + udelay(4); + read_brdctl(p); } - else if (p->features & AHC_ULTRA2) - brdctl = BRDRW_ULTRA2; else - brdctl = BRDRW | BRDCS; - aic_outb(p, brdctl, BRDCTL); - udelay(1); - value = aic_inb(p, BRDCTL); - aic_outb(p, 0, BRDCTL); - udelay(1); - return (value); + { + brdctl = BRDSTB; + if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || + (p->flags & AHC_CHNLB) ) + { + brdctl |= BRDCS; + } + brdctl = BRDSTB | BRDCS; + aic_outb(p, brdctl, BRDCTL); + udelay(1); + brdctl |= value; + aic_outb(p, brdctl, BRDCTL); + udelay(1); + brdctl &= ~BRDSTB; + aic_outb(p, brdctl, BRDCTL); + udelay(1); + brdctl &= ~BRDCS; + aic_outb(p, brdctl, BRDCTL); + udelay(1); + } } /*+F************************************************************************* @@ -7770,9 +7780,9 @@ p->host_no); } } + aic_outb(p, sxfrctl1, SXFRCTL1); write_brdctl(p, brddat); release_seeprom(p); - aic_outb(p, sxfrctl1, SXFRCTL1); } } @@ -8086,7 +8096,11 @@ /* Select channel B */ aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - term = ((p->flags & AHC_TERM_ENB_B) != 0) ? STPWEN : 0; + if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) + term = (aic_inb(p, SXFRCTL1) & STPWEN); + else + term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0); + aic_outb(p, p->scsi_id_b, SCSIID); scsi_conf = aic_inb(p, SCSICONF + 1); aic_outb(p, DFON | SPIOEN, SXFRCTL0); @@ -8100,11 +8114,18 @@ aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); } - term = ((p->flags & AHC_TERM_ENB_SE_LOW) != 0) ? STPWEN : 0; if (p->features & AHC_ULTRA2) + { aic_outb(p, p->scsi_id, SCSIID_ULTRA2); + } else + { aic_outb(p, p->scsi_id, SCSIID); + } + if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) + term = (aic_inb(p, SXFRCTL1) & STPWEN); + else + term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0); scsi_conf = aic_inb(p, SCSICONF); aic_outb(p, DFON | SPIOEN, SXFRCTL0); aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | @@ -8794,27 +8815,33 @@ } if (p->flags & AHC_NEWEEPROM_FMT) { - if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && - !(p->features & AHC_ULTRA2) ) + if ( !(p->features & AHC_ULTRA2) ) { /* * I know of two different Ultra BIOSes that do this differently. * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to - * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s + * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s * while on the IBM Netfinity 5000 they want the same thing * to be something else, while flags[i] & CFXFER == 0x03 and - * SYNCISULTRA false should be 40MByte/s. So, we set both to + * SYNCHISULTRA false should be 40MByte/s. So, we set both to * 40MByte/s and the lower speeds be damned. People will have * to select around the conversely mapped lower speeds in order * to select lower speeds on these boards. */ - if ((sc->device_flags[i] & (CFXFER)) == 0x03) + if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && + ((sc->device_flags[i] & CFXFER) == 0x03) ) { sc->device_flags[i] &= ~CFXFER; sc->device_flags[i] |= CFSYNCHISULTRA; } + if (sc->device_flags[i] & CFSYNCHISULTRA) + { + p->ultraenb |= mask; + } } - if (sc->device_flags[i] & CFSYNCHISULTRA) + else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && + (p->features & AHC_ULTRA2) && + (sc->device_flags[i] & CFSYNCHISULTRA) ) { p->ultraenb |= mask; } @@ -9035,11 +9062,44 @@ #if defined(__i386__) || defined(__alpha__) +#ifdef CONFIG_PCI + /* + * PCI-bus chipset probe. + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) + if (pci_present()) + { + if (pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82450GX, + NULL)) + aic7xxx_no_probe = 1; + if (pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82451NX, + NULL)) + aic7xxx_no_probe = 1; + } +#else +#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca + if (pcibios_present()) + { + unsigned char pci_bus, pci_devfn; + if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82450GX, + 0, &pci_bus, &pci_devfn)) ) + aic7xxx_no_probe = 1; + if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82451NX, + 0, &pci_bus, &pci_devfn)) ) + aic7xxx_no_probe = 1; + } +#endif /* LINUX_VERSION_CODE */ +#endif /* CONFIG_PCI */ /* * EISA/VL-bus card signature probe. */ slot = MINSLOT; - while ( (slot <= MAXSLOT) && !(aic7xxx_no_probe) ) + while ( (slot <= MAXSLOT) && + !(aic7xxx_no_probe) ) { base = SLOTBASE(slot) + MINREG; @@ -9293,6 +9353,10 @@ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7860_FE, 7, 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, AHC_AIC7860_FE, 7, @@ -9471,6 +9535,23 @@ temp_p->pci_device_fn = pdev->devfn; temp_p->base = pdev->base_address[0]; temp_p->mbase = pdev->base_address[1]; + temp_p->base &= PCI_BASE_ADDRESS_IO_MASK; + temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK; + current_p = list_p; + while(current_p) + { + if ( ((current_p->pci_bus == temp_p->pci_bus) && + (current_p->pci_device_fn == temp_p->pci_device_fn)) || + (current_p->base == temp_p->base) ) + { + /* duplicate PCI entry, skip it */ + kfree(temp_p); + temp_p = NULL; + } + current_p = current_p->next; + } + if ( temp_p == NULL ) + continue; if (aic7xxx_verbose & VERBOSE_PROBE2) printk("aic7xxx: <%s> at PCI %d/%d\n", board_names[aic_pdevs[i].board_name_index], @@ -9504,11 +9585,6 @@ #else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */ temp_p->pci_bus = pci_bus; temp_p->pci_device_fn = pci_devfn; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at PCI %d/%d\n", - board_names[aic_pdevs[i].board_name_index], - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE, &pci_irq); temp_p->irq = pci_irq; @@ -9518,6 +9594,28 @@ pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1, &mmapbase); temp_p->mbase = mmapbase; + temp_p->base &= PCI_BASE_ADDRESS_IO_MASK; + temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK; + current_p = list_p; + while(current_p) + { + if ( ((current_p->pci_bus == temp_p->pci_bus) && + (current_p->pci_device_fn == temp_p->pci_device_fn)) || + (current_p->base == temp_p->base) ) + { + /* duplicate PCI entry, skip it */ + kfree(temp_p); + temp_p = NULL; + } + current_p = current_p->next; + } + if ( temp_p == NULL ) + continue; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("aic7xxx: <%s> at PCI %d/%d\n", + board_names[aic_pdevs[i].board_name_index], + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command); if (aic7xxx_verbose & VERBOSE_PROBE2) { @@ -9545,12 +9643,6 @@ #endif /* AIC7XXX_STRICT_PCI_SETUP */ #endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */ - /* - * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so - * we mask it off. - */ - temp_p->base &= PCI_BASE_ADDRESS_IO_MASK; - temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK; temp_p->unpause = INTEN; temp_p->pause = temp_p->unpause | PAUSE; if ( ((temp_p->base == 0) && @@ -9568,6 +9660,9 @@ } #ifdef MMAPIO + if ( !(temp_p->flags & AHC_MULTI_CHANNEL) || + ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && + (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) { unsigned long page_offset, base; @@ -9737,17 +9832,17 @@ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT); /* * Set our options...the last two items set our CRC after x byte - * count in target mode... + * count in target mode... */ aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE); - aic_outb(temp_p, 0x00, 0x0b); - aic_outb(temp_p, 0x10, 0x0a); + aic_outb(temp_p, 0x00, 0x0b); + aic_outb(temp_p, 0x10, 0x0a); /* * switch back to normal mode... */ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT); aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN | - TARGCRCENDEN | TARGCRCCNTEN, + TARGCRCENDEN | TARGCRCCNTEN, CRCCONTROL1); aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 | MPARCKEN | CIOPARCKEN | CACHETHEN) & diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_proc.c linux.ac/drivers/scsi/aic7xxx_proc.c --- linux.vanilla/drivers/scsi/aic7xxx_proc.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/aic7xxx_proc.c Mon Jul 19 03:45:43 1999 @@ -29,6 +29,8 @@ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ *-M*************************************************************************/ +#include + #define BLS (&aic7xxx_buffer[size]) #define HDRB \ " < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/aic7xxx_reg.h linux.ac/drivers/scsi/aic7xxx_reg.h --- linux.vanilla/drivers/scsi/aic7xxx_reg.h Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/aic7xxx_reg.h Mon Jul 19 20:16:25 1999 @@ -459,11 +459,11 @@ #define CRCCONTROL1 0x9d #define CRCONSEEN 0x80 -#define TARGCRCCNTEN 0x40 #define CRCVALCHKEN 0x40 #define CRCENDCHKEN 0x20 #define CRCREQCHKEN 0x10 #define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 #define SCSIPHASE 0x9e #define SP_STATUS 0x20 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/amiga7xx.c linux.ac/drivers/scsi/amiga7xx.c --- linux.vanilla/drivers/scsi/amiga7xx.c Sun Nov 8 15:07:55 1998 +++ linux.ac/drivers/scsi/amiga7xx.c Fri Jun 4 23:52:42 1999 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -33,9 +34,9 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, - u32 base, int io_port, int irq, int dma, - long long options, int clock); +extern int ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, + u32 base, int io_port, int irq, int dma, + long long options, int clock); int amiga7xx_detect(Scsi_Host_Template *tpnt) { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_NCR5380.c linux.ac/drivers/scsi/atari_NCR5380.c --- linux.vanilla/drivers/scsi/atari_NCR5380.c Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/atari_NCR5380.c Fri Jun 4 23:52:42 1999 @@ -1459,9 +1459,9 @@ unsigned long timeout = jiffies + 2*NCR_TIMEOUT; while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout && !hostdata->connected) + && time_before(jiffies, timeout) && !hostdata->connected) ; - if (jiffies >= timeout) + if (time_after_eq(jiffies, timeout)) { printk("scsi : arbitration timeout at %d\n", __LINE__); NCR5380_write(MODE_REG, MR_BASE); @@ -1616,7 +1616,7 @@ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) */ - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == @@ -1629,7 +1629,7 @@ return -1; } #else - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); #endif /* diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atari_scsi.c linux.ac/drivers/scsi/atari_scsi.c --- linux.vanilla/drivers/scsi/atari_scsi.c Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/atari_scsi.c Fri Jun 4 23:52:42 1999 @@ -132,51 +132,51 @@ } while(0) #define SCSI_DMA_READ_P(elt) \ - (((unsigned long)tt_scsi_dma.elt##_hi << 24) | \ - ((unsigned long)tt_scsi_dma.elt##_hmd << 16) | \ - ((unsigned long)tt_scsi_dma.elt##_lmd << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lo) - - -#define SCSI_DMA_SETADR(adr) \ - do { \ - unsigned long __adr = (adr); \ - st_dma.dma_lo = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_md = (unsigned char)__adr; \ - MFPDELAY(); \ - __adr >>= 8; \ - st_dma.dma_hi = (unsigned char)__adr; \ - MFPDELAY(); \ - } while(0) - -#define SCSI_DMA_GETADR() ({ \ - unsigned long __adr; \ - __adr = st_dma.dma_lo; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_md & 0xff) << 8; \ - MFPDELAY(); \ - __adr |= (st_dma.dma_hi & 0xff) << 16; \ - MFPDELAY(); \ - __adr; \ -}) - -#define ENABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_enable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_enable_irq( IRQ_MFP_FSCSI ); \ - } while(0) - -#define DISABLE_IRQ() \ - do { \ - if (IS_A_TT()) \ - atari_disable_irq( IRQ_TT_MFP_SCSI ); \ - else \ - atari_disable_irq( IRQ_MFP_FSCSI ); \ - } while(0) + (((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \ + (unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \ + (unsigned long)tt_scsi_dma.elt##_lo) + + +static inline void SCSI_DMA_SETADR(unsigned long adr) +{ + st_dma.dma_lo = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_md = (unsigned char)adr; + MFPDELAY(); + adr >>= 8; + st_dma.dma_hi = (unsigned char)adr; + MFPDELAY(); +} + +static inline unsigned long SCSI_DMA_GETADR(void) +{ + unsigned long adr; + adr = st_dma.dma_lo; + MFPDELAY(); + adr |= (st_dma.dma_md & 0xff) << 8; + MFPDELAY(); + adr |= (st_dma.dma_hi & 0xff) << 16; + MFPDELAY(); + return adr; +} + +static inline void ENABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_enable_irq(IRQ_TT_MFP_SCSI); + else + atari_enable_irq(IRQ_MFP_FSCSI); +} + +static inline void DISABLE_IRQ(void) +{ + if (IS_A_TT()) + atari_disable_irq(IRQ_TT_MFP_SCSI); + else + atari_disable_irq(IRQ_MFP_FSCSI); +} #define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ @@ -480,16 +480,17 @@ /* fetch rest bytes in the DMA register */ dst = (char *)SCSI_DMA_READ_P( dma_addr ); - if ((nr = ((long)dst & 3))) { + nr = ((long)dst & 3); + if (nr) { /* there are 'nr' bytes left for the last long address before the DMA pointer */ - dst = (char *)( (unsigned long)dst & ~3 ); + dst = (char *)((unsigned long)dst ^ nr); DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", nr, (long)dst); dst = (char *)PTOV(dst); /* The content of the DMA pointer * is a physical address! */ DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst); - for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr ) + for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) *dst++ = *src++; } } @@ -764,7 +765,7 @@ } #endif -__initfunc(void atari_scsi_setup( char *str, int *ints )) +void __init atari_scsi_setup(char *str, int *ints) { /* Format of atascsi parameter is: * atascsi=,,,, @@ -772,23 +773,6 @@ * Negative values mean don't change. */ - /* Grmbl... the standard parameter parsing can't handle negative numbers - * :-( So let's do it ourselves! - */ - - int i = ints[0]+1, fact; - - while( str && (isdigit(*str) || *str == '-') && i <= 10) { - if (*str == '-') - fact = -1, ++str; - else - fact = 1; - ints[i++] = simple_strtoul( str, NULL, 0 ) * fact; - if ((str = strchr( str, ',' )) != NULL) - ++str; - } - ints[0] = i-1; - if (ints[0] < 1) { printk( "atari_scsi_setup: no arguments!\n" ); return; @@ -869,7 +853,7 @@ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -__initfunc(static void atari_scsi_reset_boot( void )) +static void __init atari_scsi_reset_boot(void) { unsigned long end; @@ -892,7 +876,7 @@ NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; ) + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies,end); ) barrier(); printk( " done\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/atp870u.c linux.ac/drivers/scsi/atp870u.c --- linux.vanilla/drivers/scsi/atp870u.c Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/scsi/atp870u.c Tue Jun 29 04:21:59 1999 @@ -3,7 +3,9 @@ * * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski - * + * + * Marcelo Tosatti : SMP fixes + * */ #include @@ -17,6 +19,7 @@ #include #include #include +#include #include #include #include "scsi.h" @@ -60,6 +63,7 @@ static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned short int tmpcip,id; unsigned char i,j,h,tarid,lun; unsigned char *prd; @@ -364,7 +368,10 @@ outb(0x80,tmport); } */ go_42: + spin_lock_irqsave(&io_request_lock, flags); (*workrequ->scsi_done)(workrequ); + spin_unlock_irqrestore(&io_request_lock, flags); + curr_req[h][tarid]=0; workingu[h]--; if (wide_idu[h] != 0) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/constants.c linux.ac/drivers/scsi/constants.c --- linux.vanilla/drivers/scsi/constants.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/constants.c Fri Jun 4 23:52:42 1999 @@ -1,6 +1,8 @@ /* * ASCII values for a number of symbolic constants, printing functions, * etc. + * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) + * */ #define __NO_VERSION__ @@ -37,7 +39,7 @@ /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, @@ -46,37 +48,57 @@ static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ unknown, "Read TOC", unknown, unknown, unknown, unknown, unknown, -/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown, +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, /* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", /* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, /* 5c-5f */ unknown, unknown, unknown, }; +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; @@ -89,9 +111,6 @@ case RESERVED_GROUP: printk("%s(0x%02x) ", reserved, opcode); break; - case NOTEXT_GROUP: - printk("%s(0x%02x) ", unknown, opcode); - break; case VENDOR_GROUP: printk("%s(0x%02x) ", vendor, opcode); break; @@ -119,15 +138,18 @@ #if (CONSTANTS & CONST_STATUS) static const char * statuses[] = { -/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", -/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, -/* a-d */ "Intermediate Good", unknown, "Reservation Conflict", unknown, -/* e-f */ unknown, unknown, +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, }; #endif void print_status (int status) { - status = (status >> 1) & 0xf; + status = (status >> 1) & 0x1f; #if (CONSTANTS & CONST_STATUS) printk("%s ",statuses[status]); #else @@ -405,8 +427,10 @@ s = sizeof(SCpnt->sense_buffer); if (!valid) - printk("extra data not valid "); - + printk("[valid=0] "); + printk("Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); if (sense_buffer[2] & 0x80) printk( "FMK "); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) @@ -427,7 +451,7 @@ error = "Invalid"; } - printk("%s error ", error); + printk("%s ", error); #if (CONSTANTS & CONST_SENSE) printk( "%s%s: sense key %s\n", devclass, @@ -603,7 +627,8 @@ #if (CONSTANTS & CONST_HOST) static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", -"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL}; +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/dec_esp.c linux.ac/drivers/scsi/dec_esp.c --- linux.vanilla/drivers/scsi/dec_esp.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/dec_esp.c Tue Jun 22 01:35:45 1999 @@ -0,0 +1,351 @@ +/* + * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations + * + * TURBOchannel changes by Harald Koerfgen + * + * based on jazz_esp.c: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * + * jazz_esp is based on David S. Miller's ESP driver and cyber_esp + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "NCR53C9x.h" +#include "dec_esp.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); +static void dma_drain(struct NCR_ESP *esp); +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_dump_state(struct NCR_ESP *esp); +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void dma_ints_off(struct NCR_ESP *esp); +static void dma_ints_on(struct NCR_ESP *esp); +static int dma_irq_p(struct NCR_ESP *esp); +static int dma_ports_p(struct NCR_ESP *esp); +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void dma_advance_sg(Scsi_Cmnd * sp); + + +volatile unsigned char cmd_buffer[16]; + /* This is where all commands are put + * before they are trasfered to the ESP chip + * via PIO. + */ + +volatile unsigned long *scsi_dma_ptr; +volatile unsigned long *scsi_next_ptr; +volatile unsigned long *scsi_scr; +volatile unsigned long *ioasic_ssr; +volatile unsigned long *scsi_sdr0; +volatile unsigned long *scsi_sdr1; + +static void scsi_dma_int(int, void *, struct pt_regs *); + +/***************************************************************** Detection */ +int dec_esp_detect(Scsi_Host_Template * tpnt) +{ + struct NCR_ESP *esp; + struct ConfigDev *esp_dev; + + if (IOASIC) { + esp_dev = 0; + esp = esp_allocate(tpnt, (void *) esp_dev); + + scsi_dma_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_P); + scsi_next_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_BP); + scsi_scr = (unsigned long *) (system_base + IOCTL + SCSI_SCR); + ioasic_ssr = (unsigned long *) (system_base + IOCTL + SSR); + scsi_sdr0 = (unsigned long *) (system_base + IOCTL + SCSI_SDR0); + scsi_sdr1 = (unsigned long *) (system_base + IOCTL + SCSI_SDR1); + + /* Do command transfer with programmed I/O */ + esp->do_pio_cmds = 1; + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &dma_init_read; + esp->dma_init_write = &dma_init_write; + esp->dma_ints_off = &dma_ints_off; + esp->dma_ints_on = &dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = &dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + /* virtual DMA functions */ + esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = &dma_advance_sg; + + + /* SCSI chip speed */ + esp->cfreq = 25000000; + + /* + * we don't give the address of DMA channel, but the number + * of DMA channel, so we can use the jazz DMA functions + * + */ + esp->dregs = JAZZ_SCSI_DMA; + + /* ESP register base */ + esp->eregs = (struct ESP_regs *) (system_base + SCSI); + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char *) cmd_buffer; + + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = KSEG1ADDR((volatile unsigned char *) cmd_buffer); + + esp->irq = SCSI_INT; + request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI", + NULL); + request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA", + NULL); + + /* + * FIXME, look if the scsi id is availabe from NVRAM + */ + esp->scsi_id = 7; + + /* Check for differential SCSI-bus */ + /* What is this stuff? */ + esp->diff = 0; + + esp_initialize(esp); + + printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); + esps_running = esps_in_use; + return esps_in_use; + } + return 0; +} + +/************************************************************* DMA Functions */ +static void scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (*isr & SCSI_PTR_LOADED) { + /* next page */ + *scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3; + *isr &= ~SCSI_PTR_LOADED; + } else { + printk("Got unexpected SCSI DMA Interrupt! < "); + if (*isr & SCSI_PAGOVRRUN) + printk("SCSI_PAGOVRRUN "); + if (*isr & SCSI_DMA_MEMRDERR) + printk("SCSI_DMA_MEMRDERR "); + printk(">\n"); +// panic("stop"); + *isr &= ~(SCSI_PAGOVRRUN || SCSI_DMA_MEMRDERR); + } + + /* + * This driver will only work on IOASIC machines + * so we can avoid an indirect function call here + * and flush the writeback buffer the fast way + */ + dummy = *isr; + dummy = *isr; +} + +static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) +{ + return fifo_count; +} + +static void dma_drain(struct NCR_ESP *esp) +{ + unsigned long nw; + unsigned short *p = KSEG1ADDR((unsigned short *) ((*scsi_dma_ptr) >> 3)); + + /* + * Is there something in the dma buffers left? + */ + if (nw = *scsi_scr) { + switch (nw) { + case 1: + *p = (unsigned short) *scsi_sdr0; + break; + case 2: + *p++ = (unsigned short) (*scsi_sdr0); + *p = (unsigned short) ((*scsi_sdr0) >> 16); + break; + case 3: + *p++ = (unsigned short) (*scsi_sdr0); + *p++ = (unsigned short) ((*scsi_sdr0) >> 16); + *p = (unsigned short) (*scsi_sdr1); + break; + default: + printk("Strange: %d words in dma buffer left\n", (int) nw); + break; + } + } +} + +static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + return sp->SCp.this_residual;; +} + +static void dma_dump_state(struct NCR_ESP *esp) +{ +/* + ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", + esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); + */ +} + +static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (vaddress & 3) + panic("dec_efs.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + *ioasic_ssr &= ~SCSI_DMA_EN; + *scsi_scr = 0; + *scsi_dma_ptr = vaddress << 3; + + /* prepare for next page */ + *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + *ioasic_ssr |= (SCSI_DMA_DIR | SCSI_DMA_EN); + + /* + * see above + */ + dummy = *isr; + dummy = *isr; +} + +static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + extern volatile unsigned int *isr; + unsigned int dummy; + + if (vaddress & 3) + panic("dec_efs.c: unable to handle partial word transfers, yet..."); + + dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length); + + *ioasic_ssr &= ~(SCSI_DMA_DIR | SCSI_DMA_EN); + *scsi_scr = 0; + *scsi_dma_ptr = vaddress << 3; + + /* prepare for next page */ + *scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3; + *ioasic_ssr |= SCSI_DMA_EN; + + /* + * see above + */ + dummy = *isr; + dummy = *isr; +} + +static void dma_ints_off(struct NCR_ESP *esp) +{ + disable_irq(SCSI_DMA_INT); +} + +static void dma_ints_on(struct NCR_ESP *esp) +{ + enable_irq(SCSI_DMA_INT); +} + +static int dma_irq_p(struct NCR_ESP *esp) +{ + return (esp->eregs->esp_status & ESP_STAT_INTR); +} + +static int dma_ports_p(struct NCR_ESP *esp) +{ +/* + * FIXME: what's this good for? + */ + return 1; +} + +static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* + * On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) { + dma_init_read(esp, addr, count); + } else { + dma_init_write(esp, addr, count); + } +} + +/* + * These aren't used yet + */ +static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + sp->SCp.have_data_in = PHYSADDR(sp->SCp.buffer); + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.have_data_in); +} + +static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + int sz = sp->SCp.buffers_residual; + struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer; + + while (sz >= 0) { + sg[sz].dvma_addr = PHYSADDR(sg[sz].addr); + sz--; + } + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); +} + +static void dma_advance_sg(Scsi_Cmnd * sp) +{ + sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address); +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/dec_esp.h linux.ac/drivers/scsi/dec_esp.h --- linux.vanilla/drivers/scsi/dec_esp.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/scsi/dec_esp.h Tue Jun 22 01:35:45 1999 @@ -0,0 +1,42 @@ +/* dec_esp.h: Defines and structures for the JAZZ SCSI driver. + * + * DECstation changes Copyright (C) 1998 Harald Koerfgen + * + * based on jazz_esp.h: + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#ifndef DEC_ESP_H +#define DEC_ESP_H + +#define EREGS_PAD(n) unchar n[3]; + +#include "NCR53C9x.h" + + +extern int dec_esp_detect(struct SHT *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_command(Scsi_Cmnd *); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *, unsigned int); +extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout); + +#define SCSI_DEC_ESP { \ + proc_dir: &proc_scsi_esp, \ + proc_info: &esp_proc_info, \ + name: "PMAZ-AA", \ + detect: dec_esp_detect, \ + info: esp_info, \ + command: esp_command, \ + queuecommand: esp_queue, \ + abort: esp_abort, \ + reset: esp_reset, \ + can_queue: 7, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + use_clustering: DISABLE_CLUSTERING, } + +#endif /* DEC_ESP_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/eata_dma.c linux.ac/drivers/scsi/eata_dma.c --- linux.vanilla/drivers/scsi/eata_dma.c Thu Dec 31 18:10:44 1998 +++ linux.ac/drivers/scsi/eata_dma.c Thu Jul 8 23:07:05 1999 @@ -31,6 +31,10 @@ * mike@i-Connect.Net * * neuffer@mail.uni-mainz.de * * * + * + * Changes: + * Marcelo Tosatti, Jul/8/99 : SMP fixes + * * 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 * @@ -777,7 +781,10 @@ x, sp->pid); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); + + spin_lock_irqsave(&io_request_lock, flags); sp->scsi_done(sp); + spin_unlock_irqrestore(&io_request_lock, flags); } HD(cmd)->state = FALSE; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.ac/drivers/scsi/gdth_proc.c --- linux.vanilla/drivers/scsi/gdth_proc.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/gdth_proc.c Fri Jun 4 23:52:42 1999 @@ -3,6 +3,7 @@ */ #include "gdth_ioctl.h" +#include int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ide-scsi.c linux.ac/drivers/scsi/ide-scsi.c --- linux.vanilla/drivers/scsi/ide-scsi.c Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/scsi/ide-scsi.c Mon Jul 5 16:13:00 1999 @@ -1,7 +1,7 @@ /* - * linux/drivers/scsi/ide-scsi.c Version 0.6 Jan 27, 1998 + * linux/drivers/scsi/ide-scsi.c Version 0.9 Jul 4, 1999 * - * Copyright (C) 1996 - 1998 Gadi Oxman + * Copyright (C) 1996 - 1999 Gadi Oxman */ /* @@ -25,10 +25,11 @@ * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. * Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple * detection of devices with CONFIG_SCSI_MULTI_LUN - * Ver 0.8 Feb 05 99 Optical media need translation too. + * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. + * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. */ -#define IDESCSI_VERSION "0.6" +#define IDESCSI_VERSION "0.9" #include #include @@ -606,6 +607,8 @@ host = scsi_register(host_template, 0); for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); host->max_id = id; + host->max_lun = 1; /* We should query the drive for multilun + support ? */ host->can_queue = host->cmd_per_lun * id; return 1; } @@ -632,9 +635,13 @@ { ide_drive_t *drive = idescsi_drives[dev->id]; idescsi_scsi_t *scsi = drive->driver_data; + int enable = (int) arg; if (cmd == SG_SET_TRANSFORM) { - set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + if (enable) + set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + else + clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return 0; } else if (cmd == SG_GET_TRANSFORM) return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int *) arg); @@ -729,6 +736,9 @@ if (!drive) { printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); + goto abort; + } + if (cmd->lun != 0) { /* Only respond to LUN 0. Drop others */ goto abort; } scsi = drive->driver_data; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/in2000.h linux.ac/drivers/scsi/in2000.h --- linux.vanilla/drivers/scsi/in2000.h Sun Nov 8 15:07:50 1998 +++ linux.ac/drivers/scsi/in2000.h Mon Jul 19 20:52:13 1999 @@ -67,7 +67,7 @@ orl %%ecx, %%ecx \n \ jz 1f \n \ rep \n \ - insw %%dx \n \ + insw (%%dx),%%es:(%%edi) \n \ 1: " \ : "=D" (sp) /* output */ \ : "d" (f), "D" (sp), "c" (i) /* input */ \ @@ -79,7 +79,7 @@ orl %%ecx, %%ecx \n \ jz 1f \n \ rep \n \ - outsw %%dx \n \ + outsw %%ds:(%%esi),(%%dx) \n \ 1: " \ : "=S" (sp) /* output */ \ : "d" (f), "S" (sp), "c" (i) /* input */ \ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ini9100u.c linux.ac/drivers/scsi/ini9100u.c --- linux.vanilla/drivers/scsi/ini9100u.c Sun Jan 24 19:55:36 1999 +++ linux.ac/drivers/scsi/ini9100u.c Mon Jul 19 19:48:19 1999 @@ -109,19 +109,13 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include -#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif #include -#include #include -#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) #include #endif @@ -129,39 +123,28 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "ini9100u.h" #include -#include #include #else -#include #include #include +#include +#include "../block/blk.h" +#endif + +#include #include #include - #include #include -#include #include -#include "../block/blk.h" #include "scsi.h" #include "sd.h" #include "hosts.h" #include #include "ini9100u.h" -#endif - -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93) -#ifdef CONFIG_PCI -#include -#endif -#endif #ifdef DEBUG_i91u unsigned int i91u_debug = DEBUG_DEFAULT; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/inia100.c linux.ac/drivers/scsi/inia100.c --- linux.vanilla/drivers/scsi/inia100.c Wed Mar 10 21:13:04 1999 +++ linux.ac/drivers/scsi/inia100.c Mon Jul 19 19:48:19 1999 @@ -73,19 +73,13 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include -#include #include -#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif #include -#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23) #include #endif @@ -93,33 +87,27 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "inia100.h" #include -#include - #else -#include #include #include +#include +#include "../block/blk.h" +#endif + +#include #include #include - #include #include -#include #include -#include "../block/blk.h" #include "scsi.h" #include "sd.h" #include "hosts.h" #include #include "inia100.h" -#endif #ifdef MODULE Scsi_Host_Template driver_template = INIA100; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/jazz_esp.c linux.ac/drivers/scsi/jazz_esp.c --- linux.vanilla/drivers/scsi/jazz_esp.c Sun Nov 8 15:08:00 1998 +++ linux.ac/drivers/scsi/jazz_esp.c Tue Jun 22 01:35:45 1999 @@ -1,7 +1,7 @@ /* * jazz_esp.c: Driver for SCSI chip on Mips Magnum Boards (JAZZ architecture) * - * Copyright (C) 1997 Thomas Boegndoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * jazz_esp is based on David S. Miller's ESP driver and cyber_esp */ @@ -161,7 +161,7 @@ { ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", - esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); + esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_residue((int)esp->dregs))); } static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.c linux.ac/drivers/scsi/megaraid.c --- linux.vanilla/drivers/scsi/megaraid.c Thu May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/megaraid.c Mon Jul 19 19:48:20 1999 @@ -9,14 +9,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version : 1.00 + * Version : 1.01 * * Description: Linux device driver for AMI MegaRAID controller * * Supported controllers: MegaRAID 418, 428, 438, 466, 762 * * Maintainer: Jeff L Jones - * + * Xi Shine Chen * History: * * Version 0.90: @@ -38,10 +38,10 @@ * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: - * Small changes to the comments/formatting. Plus a couple of + * Small changes to the comments/formatting. Plus a couple of * added notes. Returned to the authors. No actual code changes * save printk levels. - * 8 Oct 98 Alan Cox + * 8 Oct 98 Alan Cox * * Merged with 2.1.131 source tree. * 12 Dec 98 K. Baranowski @@ -73,14 +73,15 @@ * * Version 0.96: * 762 fully supported. + * * Version 0.97: * Changed megaraid_command to use wait_queue. * Fixed bug of undesirably detecting HP onboard controllers which - * are disabled. + * are disabled. * * Version 1.00: * Checks to see if an irq ocurred while in isr, and runs through - * routine again. + * routine again. * Copies mailbox to temp area before processing in isr * Added barrier() in busy wait to fix volatility bug * Uses separate list for freed Scbs, keeps track of cmd state @@ -88,6 +89,11 @@ * Full multi-io commands working stablely without previous problems * Added skipXX LILO option for Madrona motherboard support * + * Version 1.01: + * Fixed bug in mega_cmd_done() for megamgr control commands, + * the host_byte in the result code from the scsi request to + * scsi midlayer is set to DID_BAD_TARGET when adapter's + * returned codes are 0xF0 and oxF4. * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that @@ -100,6 +106,7 @@ #define CRLFSTR "\n" +#include #include #ifdef MODULE @@ -132,6 +139,7 @@ #include #include #include /* for kmalloc() */ +#include /* for CONFIG_PCI */ #if LINUX_VERSION_CODE < 0x20100 #include #else @@ -482,6 +490,8 @@ { int islogical; Scsi_Cmnd *SCpnt; + mega_passthru *pthru; + mega_mailbox *mbox; if (pScb == NULL) { TRACE(("NULL pScb in mega_cmd_done!")); @@ -489,7 +499,9 @@ } SCpnt = pScb->SCpnt; - freeSCB(megaCfg, pScb); + /*freeSCB(megaCfg, pScb);*/ /*delay this to the end of this func.*/ + pthru = &pScb->pthru; + mbox = (mega_mailbox *) &pScb->mboxData; if (SCpnt == NULL) { TRACE(("NULL SCpnt in mega_cmd_done!")); @@ -507,23 +519,48 @@ !islogical) { status = 0xF0; } - - SCpnt->result = 0; /* clear result; otherwise, success returns corrupt - value */ +/* clear result; otherwise, success returns corrupt value */ + SCpnt->result = 0; + +if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */{ + /*printk(KERN_WARNING "***megamgr cmnd status= %x h\n ", status); */ + switch (status) { + case 0xF0: + case 0xF4: + SCpnt->result=(DID_BAD_TARGET<<16)|status; + break; + default: + SCpnt->result|=status; + }/*end of switch*/ +} +else{ /* Convert MegaRAID status to Linux error code */ switch (status) { - case 0x00: /* SUCCESS */ - case 0x02: /* ERROR_ABORTED */ + case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/ SCpnt->result |= (DID_OK << 16); break; - case 0x8: /* ERR_DEST_DRIVE_FAILED */ - SCpnt->result |= (DID_BUS_BUSY << 16); + case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */ + /*set sense_buffer and result fields*/ + if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){ + memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14); + SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status; + } + else{ + SCpnt->sense_buffer[0]=0x70; + SCpnt->sense_buffer[2]=ABORTED_COMMAND; + SCpnt->result |= (CHECK_CONDITION << 1); + } + break; + case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */ + SCpnt->result |= (DID_BUS_BUSY << 16)|status; break; - default: + default: SCpnt->result |= (DID_BAD_TARGET << 16); break; } + } + freeSCB(megaCfg, pScb); /* Add Scsi_Command to end of completed queue */ ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); @@ -741,7 +778,6 @@ if (data[0] == 0x03) { /* passthrough command */ unsigned char cdblen = data[2]; - pthru = &pScb->pthru; memset (pthru, 0, sizeof (mega_passthru)); pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0; @@ -953,7 +989,7 @@ u_char byte; u_long cmdDone; Scsi_Cmnd *SCpnt; - + mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ mboxData[0xF] = 1; /* Set busy */ @@ -963,6 +999,10 @@ } #endif +#if DEBUG + showMbox(pScb); +#endif + /* Wait until mailbox is free */ while (mega_busyWaitMbox (megaCfg)) { printk("Blocked mailbox!!\n"); @@ -984,9 +1024,9 @@ callDone(SCpnt); return 0; } + pLastScb = pScb; - /* Copy mailbox data into host structure */ memcpy (mbox, mboxData, 16); @@ -995,7 +1035,7 @@ /* Issue interrupt (non-blocking) command */ if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; + mbox->mraid_poll = 0; mbox->mraid_ack = 0; WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/megaraid.h linux.ac/drivers/scsi/megaraid.h --- linux.vanilla/drivers/scsi/megaraid.h Thu May 27 22:11:56 1999 +++ linux.ac/drivers/scsi/megaraid.h Mon Jul 19 20:52:14 1999 @@ -1,6 +1,6 @@ #ifndef __MEGARAID_H__ #define __MEGARAID_H__ - + #ifndef LINUX_VERSION_CODE #include #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/mvme16x.c linux.ac/drivers/scsi/mvme16x.c --- linux.vanilla/drivers/scsi/mvme16x.c Sun Nov 8 15:07:56 1998 +++ linux.ac/drivers/scsi/mvme16x.c Mon Jul 19 19:48:20 1999 @@ -18,7 +18,6 @@ #include "hosts.h" #include "53c7xx.h" #include "mvme16x.h" -#include "asm/mvme16xhw.h" #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.ac/drivers/scsi/ncr53c8xx.c --- linux.vanilla/drivers/scsi/ncr53c8xx.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/ncr53c8xx.c Fri Jul 2 19:14:38 1999 @@ -5003,7 +5003,7 @@ ** Force ordered tag if necessary to avoid timeouts ** and to preserve interactivity. */ - if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp && time_before_eq(lp->tags_stime + 3*HZ, jiffies)) { if (lp->tags_smap) { order = M_ORDERED_TAG; if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ @@ -9850,7 +9850,8 @@ /* PCI_CACHE_LINE_SIZE value is in 32-bit words. */ cache_line_size = 64 / sizeof(u_int32); if (initverbose >= 2) - printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size); + printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", + cache_line_size); pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size); pcibios_read_config_byte(bus, device_fn, @@ -9858,7 +9859,7 @@ } if (!latency_timer) { - latency_timer = 128; + latency_timer = 64; if (initverbose >= 2) printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer); pcibios_write_config_byte(bus, device_fn, diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/pas16.c linux.ac/drivers/scsi/pas16.c --- linux.vanilla/drivers/scsi/pas16.c Sun Nov 8 15:07:49 1998 +++ linux.ac/drivers/scsi/pas16.c Mon Jul 19 19:48:20 1999 @@ -577,6 +577,5 @@ /* Eventually this will go into an include file, but this will be later */ Scsi_Host_Template driver_template = MV_PAS16; -#include #include "scsi_module.c" #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfas.c linux.ac/drivers/scsi/qlogicfas.c --- linux.vanilla/drivers/scsi/qlogicfas.c Tue Feb 23 14:21:33 1999 +++ linux.ac/drivers/scsi/qlogicfas.c Fri Jul 2 19:22:11 1999 @@ -276,9 +276,9 @@ int i,k; k = 0; i = jiffies + WATCHDOG; - while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0)) + while ( time_after(i, jiffies) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) barrier(); - if (i <= jiffies) + if (time_before_eq(i, jiffies)) return (DID_TIME_OUT); if (qabort) return (qabort == 1 ? DID_ABORT : DID_RESET); @@ -408,8 +408,8 @@ } /*** Enter Status (and Message In) Phase ***/ k = jiffies + WATCHDOG; - while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ - if ( k <= jiffies ) { + while ( time_after(k, jiffies) && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */ + if ( time_before_eq(k, jiffies) ) { ql_zap(); return (DID_TIME_OUT << 16); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc.c linux.ac/drivers/scsi/qlogicfc.c --- linux.vanilla/drivers/scsi/qlogicfc.c Fri Apr 16 22:10:54 1999 +++ linux.ac/drivers/scsi/qlogicfc.c Mon Jul 19 03:18:18 1999 @@ -1,5 +1,5 @@ /* - * QLogic ISP2100 SCSI-FCP + * QLogic ISP2x00 SCSI-FCP * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe * @@ -17,7 +17,7 @@ /* Renamed and updated to 1.3.x by Michael Griffith */ /* This is a version of the isp1020 driver which was modified by - * Chris Loveland to support the isp2100 + * Chris Loveland to support the isp2100 and isp2200 */ /* @@ -63,28 +63,30 @@ /* Configuration section **************************************************** */ -/* Set the following macro to 1 to reload the ISP2100's firmware. This is - version 1.15.19 of the firmware. */ +/* Set the following macro to 1 to reload the ISP2x00's firmware. This is + version 1.15.37 of the isp2100's firmware and version 2.00.16 of the + isp2200's firmware. +*/ #define RELOAD_FIRMWARE 1 #define USE_NVRAM_DEFAULTS 1 -#define ISP2100_PORTDB 1 +#define ISP2x00_PORTDB 1 /* Set the following to 1 to include fabric support, fabric support is * currently not as well tested as the other aspects of the driver */ -#define ISP2100_FABRIC 0 +#define ISP2x00_FABRIC 0 /* Macros used for debugging */ /* -#define DEBUG_ISP2100 1 -#define DEBUG_ISP2100_INT 1 -#define DEBUG_ISP2100_INTR 1 -#define DEBUG_ISP2100_SETUP 1 +#define DEBUG_ISP2x00 1 +#define DEBUG_ISP2x00_INT 1 +#define DEBUG_ISP2x00_INTR 1 +#define DEBUG_ISP2x00_SETUP 1 -#define DEBUG_ISP2100_FABRIC 1 +#define DEBUG_ISP2x00_FABRIC 1 */ /* #define TRACE_ISP 1 */ @@ -127,51 +129,49 @@ #define TRACE(w, i, a) #endif -#if DEBUG_ISP2100_FABRIC +#if DEBUG_ISP2x00_FABRIC #define DEBUG_FABRIC(x) x #else #define DEBUG_FABRIC(x) -#endif /* DEBUG_ISP2100_FABRIC */ +#endif /* DEBUG_ISP2x00_FABRIC */ -#if DEBUG_ISP2100 -#define ENTER(x) printk("isp2100 : entering %s()\n", x); -#define LEAVE(x) printk("isp2100 : leaving %s()\n", x); +#if DEBUG_ISP2x00 +#define ENTER(x) printk("isp2x00 : entering %s()\n", x); +#define LEAVE(x) printk("isp2x00 : leaving %s()\n", x); #define DEBUG(x) x #else #define ENTER(x) #define LEAVE(x) #define DEBUG(x) -#endif /* DEBUG_ISP2100 */ +#endif /* DEBUG_ISP2x00 */ -#if DEBUG_ISP2100_INTR -#define ENTER_INTR(x) printk("isp2100 : entering %s()\n", x); -#define LEAVE_INTR(x) printk("isp2100 : leaving %s()\n", x); +#if DEBUG_ISP2x00_INTR +#define ENTER_INTR(x) printk("isp2x00 : entering %s()\n", x); +#define LEAVE_INTR(x) printk("isp2x00 : leaving %s()\n", x); #define DEBUG_INTR(x) x #else #define ENTER_INTR(x) #define LEAVE_INTR(x) #define DEBUG_INTR(x) -#endif /* DEBUG ISP2100_INTR */ +#endif /* DEBUG ISP2x00_INTR */ -#if defined(__i386__) -#define virt_to_bus_low32(x) virt_to_bus(x) -#define virt_to_bus_high32(x) 0x0 -#define bus_to_virt_low32(x) bus_to_virt(x) -#define bus_to_virt_high32(x) 0x0 -#elif defined(__alpha__) +#if BITS_PER_LONG > 32 #define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) #define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) #define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) #define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) +#else +#define virt_to_bus_low32(x) virt_to_bus(x) +#define virt_to_bus_high32(x) 0x0 +#define bus_to_virt_low32(x) bus_to_virt(x) +#define bus_to_virt_high32(x) 0x0 #endif -#define ISP2100_REV_ID 1 +#define ISP2100_REV_ID1 1 #define ISP2100_REV_ID3 3 - -#define MAX_TARGETS 16 -#define MAX_LUNS 8 +#define ISP2200_REV_ID5 5 /* host configuration and control registers */ #define HOST_HCCR 0xc0 /* host command and control */ @@ -219,6 +219,8 @@ #define PORT_DB_CHANGED 0x8014 #define CHANGE_NOTIFICATION 0x8015 #define SCSI_COMMAND_COMPLETE 0x8020 +#define POINT_TO_POINT_UP 0x8030 +#define CONNECTION_MODE 0x8036 struct Entry_header { u_char entry_type; @@ -228,19 +230,48 @@ }; /* entry header type commands */ +#if BITS_PER_LONG > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a +#else +#define ENTRY_COMMAND 0x11 +#define ENTRY_CONTINUATION 0x02 +#endif + #define ENTRY_STATUS 0x03 #define ENTRY_MARKER 0x04 + /* entry header flag definitions */ #define EFLAG_BUSY 2 #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 +#if BITS_PER_LONG > 32 +struct dataseg { + u_int d_base; + u_int d_base_hi; + u_int d_count; +}; + +struct Command_Entry { + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short expanded_lun; + u_short control_flags; + u_short rsvd2; + u_short time_out; + u_short segment_cnt; + u_char cdb[16]; + u_int total_byte_cnt; + struct dataseg dataseg[DATASEGS_PER_COMMAND]; +}; + +#else struct dataseg { - u_int d_base_lo; - u_int d_base_high; + u_int d_base; u_int d_count; }; @@ -249,16 +280,19 @@ u_int handle; u_char target_lun; u_char target_id; - u_short rsvd1; + u_short expanded_lun; u_short control_flags; u_short rsvd2; u_short time_out; u_short segment_cnt; u_char cdb[16]; u_int total_byte_cnt; - struct dataseg dataseg[2]; + struct dataseg dataseg[DATASEGS_PER_COMMAND]; }; +#endif + + /* command entry control flag definitions */ #define CFLAG_NODISC 0x01 #define CFLAG_HEAD_TAG 0x02 @@ -268,23 +302,18 @@ #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -struct Ext_Command_Entry { +#if BITS_PER_LONG > 32 +struct Continuation_Entry { struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short cdb_length; - u_short control_flags; - u_short rsvd; - u_short time_out; - u_short segment_cnt; - u_char cdb[44]; + struct dataseg dataseg[DATASEGS_PER_CONT]; }; - +#else struct Continuation_Entry { struct Entry_header hdr; - struct dataseg dataseg[5]; + u32 rsvd; + struct dataseg dataseg[DATASEGS_PER_CONT]; }; +#endif struct Marker_Entry { struct Entry_header hdr; @@ -292,7 +321,7 @@ u_char target_lun; u_char target_id; u_char modifier; - u_char rsvd; + u_char expanded_lun; u_char rsvds[52]; }; @@ -549,7 +578,7 @@ u_int response_high; u_short sub_len; u_short res2; - u_short data[22]; + u_char data[44]; }; /* address of instance of this struct is passed to adapter to initialize things @@ -574,6 +603,17 @@ u_int req_queue_addr_high; u_int res_queue_addr_lo; u_int res_queue_addr_high; + /* the rest of this structure only applies to the isp2200 */ + u_short lun_enables; + u_char cmd_resource_cnt; + u_char notify_resource_cnt; + u_short timeout; + u_short reserved3; + u_short add_firm_opts; + u_char res_accum_timer; + u_char irq_delay_timer; + u_short special_options; + u_short reserved4[13]; }; /* @@ -583,16 +623,24 @@ #define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) #define QUEUE_ENTRY_LEN 64 -#if ISP2100_FABRIC +#if ISP2x00_FABRIC #define QLOGICFC_MAX_ID 0xff #else -#define QLOGICFC_MAX_ID 0x80 +#define QLOGICFC_MAX_ID 0x7d #endif -struct isp2100_hostdata { +#define QLOGICFC_MAX_LOOP_ID 0x7d + +/* adapter_state values */ +#define AS_FIRMWARE_DEAD -1 +#define AS_LOOP_DOWN 0 +#define AS_LOOP_GOOD 1 +#define AS_REDO_PORTDB 2 + +struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; - /* result and request queues (shared with isp2100): */ + /* result and request queues (shared with isp2x00): */ u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ @@ -602,7 +650,7 @@ char res[RES_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; char req[QLOGICFC_REQ_QUEUE_LEN + 1][QUEUE_ENTRY_LEN]; struct init_cb control_block; - int loop_up; + int adapter_state; unsigned long int tag_ages[126]; Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; @@ -611,6 +659,7 @@ u64 wwn; u_int port_id; u_char queued; + u_char host_id; }; @@ -620,177 +669,187 @@ QLOGICFC_REQ_QUEUE_LEN) #define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) -static void isp2100_enable_irqs(struct Scsi_Host *); -static void isp2100_disable_irqs(struct Scsi_Host *); -static int isp2100_init(struct Scsi_Host *); -static int isp2100_reset_hardware(struct Scsi_Host *); -static int isp2100_mbox_command(struct Scsi_Host *, u_short[]); -static int isp2100_return_status(struct Status_Entry *); -static void isp2100_intr_handler(int, void *, struct pt_regs *); -static void do_isp2100_intr_handler(int, void *, struct pt_regs *); -static int isp2100_make_portdb(struct Scsi_Host *); +static void isp2x00_enable_irqs(struct Scsi_Host *); +static void isp2x00_disable_irqs(struct Scsi_Host *); +static int isp2x00_init(struct Scsi_Host *); +static int isp2x00_reset_hardware(struct Scsi_Host *); +static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]); +static int isp2x00_return_status(struct Status_Entry *); +static void isp2x00_intr_handler(int, void *, struct pt_regs *); +static void do_isp2x00_intr_handler(int, void *, struct pt_regs *); +static int isp2x00_make_portdb(struct Scsi_Host *); -#if ISP2100_FABRIC -static int isp2100_init_fabric(struct Scsi_Host *, struct id_name_map *, int); +#if ISP2x00_FABRIC +static int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int); #endif #if USE_NVRAM_DEFAULTS -static int isp2100_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); -static u_short isp2100_read_nvram_word(struct Scsi_Host *, u_short); +static int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); +static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short); #endif -#if DEBUG_ISP2100 -static void isp2100_print_scsi_cmd(Scsi_Cmnd *); +#if DEBUG_ISP2x00 +static void isp2x00_print_scsi_cmd(Scsi_Cmnd *); #endif -static void isp2100_print_status_entry(struct Status_Entry *); +#if DEBUG_ISP2x00_INTR +static void isp2x00_print_status_entry(struct Status_Entry *); +#endif -static struct proc_dir_entry proc_scsi_isp2100 = +static struct proc_dir_entry proc_scsi_isp2x00 = { - PROC_SCSI_QLOGICFC, 7, "isp2100", + PROC_SCSI_QLOGICFC, 7, "isp2x00", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -static inline void isp2100_enable_irqs(struct Scsi_Host *host) +static inline void isp2x00_enable_irqs(struct Scsi_Host *host) { outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); } -static inline void isp2100_disable_irqs(struct Scsi_Host *host) +static inline void isp2x00_disable_irqs(struct Scsi_Host *host) { outw(0x0, host->io_port + PCI_INTER_CTL); } -int isp2100_detect(Scsi_Host_Template * tmpt) +int isp2x00_detect(Scsi_Host_Template * tmpt) { int hosts = 0; int wait_time; struct Scsi_Host *host = NULL; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; + unsigned short device_ids[2]; + int i; - ENTER("isp2100_detect"); - tmpt->proc_dir = &proc_scsi_isp2100; + ENTER("isp2x00_detect"); + + device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100; + device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200; + + tmpt->proc_dir = &proc_scsi_isp2x00; if (pci_present() == 0) { printk("qlogicfc : PCI not present\n"); return 0; } - while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100, pdev))) { - host = scsi_register(tmpt, sizeof(struct isp2100_hostdata)); - host->max_id = QLOGICFC_MAX_ID + 1; - host->hostt->use_new_eh_code = 1; - hostdata = (struct isp2100_hostdata *) host->hostdata; - - memset(hostdata, 0, sizeof(struct isp2100_hostdata)); - hostdata->pci_dev = pdev; - - hostdata->queued = 0; - /* set up the control block */ - hostdata->control_block.version = 0x0f; - hostdata->control_block.firm_opts = 0x010c; - hostdata->control_block.max_frame_len = 2048; - hostdata->control_block.max_iocb = 256; - hostdata->control_block.exec_throttle = 8; - hostdata->control_block.retry_delay = 5; - hostdata->control_block.retry_cnt = 0; - hostdata->control_block.node_name[0] = 0x0020; - hostdata->control_block.node_name[1] = 0xE000; - hostdata->control_block.node_name[2] = 0x008B; - hostdata->control_block.node_name[3] = 0x0000; - hostdata->control_block.hard_addr = 0x0003; - hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; - hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; - hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(&hostdata->res); - hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(&hostdata->res); - hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); - hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); - - hostdata->loop_up = 0; - - if (isp2100_init(host) || isp2100_reset_hardware(host)) { - scsi_unregister(host); - continue; - } - host->this_id = 0; + for (i=0; i<2; i++){ + while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { - if (request_irq(host->irq, do_isp2100_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { - printk("qlogicfc : interrupt %d already in use\n", - host->irq); - scsi_unregister(host); - continue; - } - if (check_region(host->io_port, 0xff)) { - printk("qlogicfc : i/o region 0x%lx-0x%lx already " - "in use\n", - host->io_port, host->io_port + 0xff); - free_irq(host->irq, host); - scsi_unregister(host); - continue; - } - request_region(host->io_port, 0xff, "qlogicfc"); + host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); + host->max_id = QLOGICFC_MAX_ID + 1; + host->hostt->use_new_eh_code = 1; + hostdata = (struct isp2x00_hostdata *) host->hostdata; + + memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); + hostdata->pci_dev = pdev; + + hostdata->queued = 0; + /* set up the control block */ + hostdata->control_block.version = 0x1; + hostdata->control_block.firm_opts = 0x0108; + hostdata->control_block.max_frame_len = 2048; + hostdata->control_block.max_iocb = 256; + hostdata->control_block.exec_throttle = 8; + hostdata->control_block.retry_delay = 5; + hostdata->control_block.retry_cnt = 1; + hostdata->control_block.node_name[0] = 0x0020; + hostdata->control_block.node_name[1] = 0xE000; + hostdata->control_block.node_name[2] = 0x008B; + hostdata->control_block.node_name[3] = 0x0000; + hostdata->control_block.hard_addr = 0x0003; + hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; + hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; + hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(&hostdata->res); + hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(&hostdata->res); + hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(&hostdata->req); + hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(&hostdata->req); + + + hostdata->adapter_state = AS_LOOP_DOWN; + hostdata->host_id = hosts; + + if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { + scsi_unregister(host); + continue; + } + host->this_id = 0; - outw(0x0, host->io_port + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - isp2100_enable_irqs(host); - /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->loop_up == 0;) - barrier(); + if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { + printk("qlogicfc%d : interrupt %d already in use\n", + hostdata->host_id, host->irq); + scsi_unregister(host); + continue; + } + if (check_region(host->io_port, 0xff)) { + printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " + "in use\n", + hostdata->host_id, host->io_port, host->io_port + 0xff); + free_irq(host->irq, host); + scsi_unregister(host); + continue; + } + request_region(host->io_port, 0xff, "qlogicfc"); - if (hostdata->loop_up == 0) { - printk("qlogicfc: loop is not up\n"); - release_region(host->io_port, 0xff); - free_irq(host->irq, host); - scsi_unregister(host); - continue; + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + isp2x00_enable_irqs(host); + /* wait for the loop to come up */ + for (wait_time = jiffies + 10 * HZ; wait_time > jiffies && hostdata->adapter_state == AS_LOOP_DOWN;) + barrier(); + + if (hostdata->adapter_state == AS_LOOP_DOWN) { + printk("qlogicfc%d : link is not up\n", hostdata->host_id); + } + hosts++; } - hosts++; } - /* this busy loop should not be needed but the isp2100 seems to need + /* this busy loop should not be needed but the isp2x00 seems to need some time before recognizing it is attached to a fabric */ -#if ISP2100_FABRIC +#if ISP2x00_FABRIC for (wait_time = jiffies + 5 * HZ; wait_time > jiffies;) barrier(); #endif - LEAVE("isp2100_detect"); + LEAVE("isp2x00_detect"); return hosts; } -static int isp2100_make_portdb(struct Scsi_Host *host) +static int isp2x00_make_portdb(struct Scsi_Host *host) { short param[8]; int i, j; struct id_name_map temp[QLOGICFC_MAX_ID + 1]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); memset(temp, 0, sizeof(temp)); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; -#if ISP2100_FABRIC +#if ISP2x00_FABRIC for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { param[0] = MBOX_PORT_LOGOUT; param[1] = i << 8; param[2] = 0; param[3] = 0; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("logout failed %x %x\n", i, param[0]); + + DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0])); } } #endif @@ -798,7 +857,7 @@ param[0] = MBOX_GET_INIT_SCSI_ID; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { hostdata->port_id = ((u_int) param[3]) << 16; @@ -807,16 +866,17 @@ temp[0].wwn = hostdata->wwn; } else { - printk("qlogicfc: error getting scsi id.\n"); + printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id); } - for (i = 1, j = 1; i <= QLOGICFC_MAX_ID; i++) { - temp[i].loop_id = temp[0].loop_id; - - param[0] = MBOX_GET_PORT_NAME; + for (i = 0; i <=QLOGICFC_MAX_ID; i++) + temp[i].loop_id = temp[0].loop_id; + + for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { + param[0] = MBOX_GET_PORT_NAME; param[1] = (i << 8) & 0xff00; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { temp[j].loop_id = i; @@ -835,8 +895,8 @@ } -#if ISP2100_FABRIC - isp2100_init_fabric(host, temp, j); +#if ISP2x00_FABRIC + isp2x00_init_fabric(host, temp, j); #endif for (i = 0; i <= QLOGICFC_MAX_ID; i++) { @@ -856,7 +916,7 @@ } } if (j == QLOGICFC_MAX_ID + 1) - printk("qlogicfc.c: Too many scsi devices, no more room in port map.\n"); + printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id); if (!hostdata->port_db[j].wwn) { hostdata->port_db[j].loop_id = temp[i].loop_id; hostdata->port_db[j].wwn = temp[i].wwn; @@ -866,42 +926,70 @@ } - isp2100_enable_irqs(host); + isp2x00_enable_irqs(host); return 0; } -#if ISP2100_FABRIC +#if ISP2x00_FABRIC + +#define FABRIC_PORT 0x7e +#define FABRIC_CONTROLLER 0x7f +#define FABRIC_SNS 0x80 -int isp2100_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int j) +int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) { u_short param[8]; u64 wwn; int done = 0; u_short loop_id = 0x81; - u_short scsi_id = j; + u_short scsi_id = cur_scsi_id; u_int port_id; struct sns_cb req; u_char sns_response[608]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; - DEBUG_FABRIC(printk("qlogicfc.c: Checking for a fabric.\n")); + DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; - param[1] = 0x7E00; + param[1] = (u16)FABRIC_PORT << 8; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("fabric check result %x\n", param[0])); + DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0])); return 0; } - printk("qlogicfc.c: Fabric found.\n"); + printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); + memset(&req, 0, sizeof(req)); + + req.len = 8; + req.response_low = virt_to_bus_low32(sns_response); + req.response_high = virt_to_bus_high32(sns_response); + req.sub_len = 22; + req.data[0] = 0x17; + req.data[1] = 0x02; + req.data[8] = (u_char) (hostdata->port_id & 0xff); + req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req.data[13] = 0x01; + param[0] = MBOX_SEND_SNS; + param[1] = 30; + param[2] = virt_to_bus_low32(&req) >> 16; + param[3] = virt_to_bus_low32(&req); + param[6] = virt_to_bus_high32(&req) >> 16; + param[7] = virt_to_bus_high32(&req); + + isp2x00_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + port_id = hostdata->port_id; while (!done) { memset(&req, 0, sizeof(req)); @@ -910,9 +998,11 @@ req.response_low = virt_to_bus_low32(sns_response); req.response_high = virt_to_bus_high32(sns_response); req.sub_len = 6; - req.data[0] = 0x0100; - req.data[4] = (u_short) (port_id & 0xffff); - req.data[5] = (u_short) (port_id >> 16 & 0xffff); + req.data[0] = 0x00; + req.data[1] = 0x01; + req.data[8] = (u_char) (port_id & 0xff); + req.data[9] = (u_char) (port_id >> 8 & 0xff); + req.data[10] = (u_char) (port_id >> 16 & 0xff); param[0] = MBOX_SEND_SNS; param[1] = 14; @@ -921,10 +1011,10 @@ param[6] = virt_to_bus_high32(&req) >> 16; param[7] = virt_to_bus_high32(&req); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("found node %02x%02x%02x%02x%02x%02x%02x%02x ", sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); + DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); DEBUG_FABRIC(printk(" port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19])); port_id = ((u_int) sns_response[17]) << 16; port_id |= ((u_int) sns_response[18]) << 8; @@ -938,13 +1028,13 @@ wwn |= ((u64) sns_response[26]) << 8; wwn |= ((u64) sns_response[27]); if (hostdata->port_id >> 8 != port_id >> 8) { - DEBUG_FABRIC(printk("adding a fabric port: %x\n", port_id)); + DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id)); param[0] = MBOX_PORT_LOGIN; param[1] = loop_id << 8; param[2] = (u_short) (port_id >> 16); param[3] = (u_short) (port_id); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { port_db[scsi_id].wwn = wwn; @@ -952,15 +1042,22 @@ loop_id++; scsi_id++; } else { - printk("qlogicfc.c: Error performing port login %x\n", param[0]); - DEBUG_FABRIC(printk("loop_id: %x\n", loop_id)); + printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]); + DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id)); + param[0] = MBOX_PORT_LOGOUT; + param[1] = loop_id << 8; + param[2] = 0; + param[3] = 0; + + isp2x00_mbox_command(host, param); + } } if (hostdata->port_id == port_id) done = 1; } else { - printk("qlogicfc.c: Get All Next failed %x.\n", param[0]); + printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); return 0; } } @@ -968,42 +1065,42 @@ return 1; } -#endif /* ISP2100_FABRIC */ +#endif /* ISP2x00_FABRIC */ -int isp2100_release(struct Scsi_Host *host) +int isp2x00_release(struct Scsi_Host *host) { - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - ENTER("isp2100_release"); + ENTER("isp2x00_release"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; outw(0x0, host->io_port + PCI_INTER_CTL); free_irq(host->irq, host); release_region(host->io_port, 0xff); - LEAVE("isp2100_release"); + LEAVE("isp2x00_release"); return 0; } -const char *isp2100_info(struct Scsi_Host *host) +const char *isp2x00_info(struct Scsi_Host *host) { static char buf[80]; - struct isp2100_hostdata *hostdata; - ENTER("isp2100_info"); + struct isp2x00_hostdata *hostdata; + ENTER("isp2x00_info"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; sprintf(buf, - "QLogic ISP2100 SCSI on PCI bus %02x device %02x irq %d base 0x%lx", - hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, + "QLogic ISP%04x SCSI on PCI bus %02x device %02x irq %d base 0x%lx", + hostdata->pci_dev->device, hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, host->io_port); - LEAVE("isp2100_info"); + LEAVE("isp2x00_info"); return buf; } @@ -1015,7 +1112,7 @@ * interrupt handler may call this routine as part of * request-completion handling). */ -int isp2100_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) +int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) { int i, sg_count, n, num_free; u_int in_ptr, out_ptr; @@ -1024,25 +1121,26 @@ struct Command_Entry *cmd; struct Continuation_Entry *cont; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; - ENTER("isp2100_queuecommand"); + ENTER("isp2x00_queuecommand"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; Cmnd->scsi_done = done; - DEBUG(isp2100_print_scsi_cmd(Cmnd)); + DEBUG(isp2x00_print_scsi_cmd(Cmnd)); - if (hostdata->loop_up == 2) { - hostdata->loop_up = 1; - isp2100_make_portdb(host); + if (hostdata->adapter_state == AS_REDO_PORTDB) { + hostdata->adapter_state = AS_LOOP_GOOD; + isp2x00_make_portdb(host); + printk("qlogicfc%d : Port Database\n", hostdata->host_id); for (i = 0; hostdata->port_db[i].wwn != 0; i++) { - DEBUG(printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id)); + printk("wwn: %08x%08x scsi_id: %x loop_id: %x\n", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i, hostdata->port_db[i].loop_id); } } - if (hostdata->loop_up == -1) { - printk("qlogicfc.c: The firmware is dead, just return.\n"); + if (hostdata->adapter_state == AS_FIRMWARE_DEAD) { + printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id); host->max_id = 0; return 0; } @@ -1050,13 +1148,13 @@ out_ptr = inw(host->io_port + MBOX4); in_ptr = hostdata->req_in_ptr; - DEBUG(printk("qlogicfc : request queue depth %d\n", + DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id, REQ_QUEUE_DEPTH(in_ptr, out_ptr))); cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { - DEBUG(printk("qlogicfc : request queue overflow\n")); + DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); return 1; } if (hostdata->send_marker) { @@ -1064,7 +1162,7 @@ TRACE("queue marker", in_ptr, 0); - DEBUG(printk("qlogicfc : adding marker entry\n")); + DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id)); marker = (struct Marker_Entry *) cmd; memset(marker, 0, sizeof(struct Marker_Entry)); @@ -1077,7 +1175,7 @@ if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) { outw(in_ptr, host->io_port + MBOX4); hostdata->req_in_ptr = in_ptr; - DEBUG(printk("qlogicfc : request queue overflow\n")); + DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); return 1; } cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; @@ -1094,19 +1192,27 @@ cmd->handle = i; hostdata->handle_ptrs[i] = Cmnd; hostdata->handle_serials[i] = Cmnd->serial_number; - } else - printk("qlogicfc: no handle slots, this should not happen.\n"); + } else { + printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id); + printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr); + for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){ + if (!hostdata->handle_ptrs[i]){ + printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]); + } + } + } cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; -#if ISP2100_PORTDB + cmd->expanded_lun = Cmnd->lun; +#if ISP2x00_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; #else cmd->target_id = Cmnd->target; #endif cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; - cmd->time_out = (SCSI_TIMEOUT / HZ) * 5; + cmd->time_out = 0; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { @@ -1115,15 +1221,18 @@ ds = cmd->dataseg; /* fill in first two sg entries: */ n = sg_count; - if (n > 2) - n = 2; + if (n > DATASEGS_PER_COMMAND) + n = DATASEGS_PER_COMMAND; + for (i = 0; i < n; i++) { - ds[i].d_base_lo = virt_to_bus_low32(sg->address); - ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_base = virt_to_bus_low32(sg->address); +#if BITS_PER_LONG > 32 + ds[i].d_base_hi = virt_to_bus_high32(sg->address); +#endif ds[i].d_count = sg->length; ++sg; } - sg_count -= 2; + sg_count -= DATASEGS_PER_COMMAND; while (sg_count > 0) { ++cmd->hdr.entry_cnt; @@ -1132,28 +1241,31 @@ memset(cont, 0, sizeof(struct Continuation_Entry)); in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { - DEBUG(printk("isp2100: unexpected request queue overflow\n")); + DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id)); return 1; } TRACE("queue continuation", in_ptr, 0); cont->hdr.entry_type = ENTRY_CONTINUATION; ds = cont->dataseg; n = sg_count; - if (n > 5) - n = 5; + if (n > DATASEGS_PER_CONT) + n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base_lo = virt_to_bus_low32(sg->address); - ds[i].d_base_high = virt_to_bus_high32(sg->address); + ds[i].d_base = virt_to_bus_low32(sg->address); +#if BITS_PER_LONG > 32 + ds[i].d_base_hi = virt_to_bus_high32(sg->address); +#endif ds[i].d_count = sg->length; ++sg; } sg_count -= n; } } else { - cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->request_buffer); - cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->request_buffer); - cmd->dataseg[0].d_count = - (u_int) Cmnd->request_bufflen; + cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer); +#if BITS_PER_LONG > 32 + cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); +#endif + cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; cmd->segment_cnt = 1; } @@ -1161,12 +1273,15 @@ case WRITE_10: case WRITE_6: case WRITE_BUFFER: + case MODE_SELECT: cmd->control_flags = CFLAG_WRITE; break; case REQUEST_SENSE: /* scsi.c expects sense info in a different buffer */ - cmd->dataseg[0].d_base_lo = virt_to_bus_low32(Cmnd->sense_buffer); - cmd->dataseg[0].d_base_high = virt_to_bus_high32(Cmnd->sense_buffer); + cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); +#if BITS_PER_LONG > 32 + cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); +#endif cmd->segment_cnt = 1; cmd->control_flags = CFLAG_READ; break; @@ -1197,6 +1312,7 @@ hostdata->req_in_ptr = in_ptr; hostdata->queued++; + num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); num_free = (num_free > 2) ? num_free - 2 : 0; host->can_queue = hostdata->queued + num_free; @@ -1207,11 +1323,11 @@ /* this is really gross */ if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc.c crosses its fingers.\n")); + DEBUG(printk("qlogicfc%d.c crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } - LEAVE("isp2100_queuecommand"); + LEAVE("isp2x00_queuecommand"); return 0; } @@ -1220,33 +1336,33 @@ #define ASYNC_EVENT_INTERRUPT 0x01 -void do_isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +void do_isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); - isp2100_intr_handler(irq, dev_id, regs); + isp2x00_intr_handler(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags); } -void isp2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd *Cmnd; struct Status_Entry *sts; struct Scsi_Host *host = dev_id; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; u_int in_ptr, out_ptr, handle, num_free; u_short status; - ENTER_INTR("isp2100_intr_handler"); + ENTER_INTR("isp2x00_intr_handler"); - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; - DEBUG_INTR(printk("qlogicfc : interrupt on line %d\n", irq)); + DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq)); if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { /* spurious interrupts can happen legally */ - DEBUG_INTR(printk("qlogicfc: got spurious interrupt\n")); + DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id)); return; } in_ptr = inw(host->io_port + MBOX5); @@ -1255,26 +1371,32 @@ if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { status = inw(host->io_port + MBOX0); - DEBUG_INTR(printk("qlogicfc : mbox completion status: %x\n", - status)); + DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n", + hostdata->host_id, status)); switch (status) { case LOOP_UP: - hostdata->loop_up = 2; + case POINT_TO_POINT_UP: + printk("qlogicfc%d : link is up\n", hostdata->host_id); + hostdata->adapter_state = AS_REDO_PORTDB; break; case LOOP_DOWN: - hostdata->loop_up = 0; + printk("qlogicfc%d : link is down\n", hostdata->host_id); + hostdata->adapter_state = AS_LOOP_DOWN; + break; + case CONNECTION_MODE: + printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1)); break; case LIP_OCCURED: case CHANGE_NOTIFICATION: case PORT_DB_CHANGED: case LIP_RECEIVED: - if (hostdata->loop_up == 1) - hostdata->loop_up = 2; + if (hostdata->adapter_state == AS_LOOP_GOOD) + hostdata->adapter_state = AS_REDO_PORTDB; break; case SYSTEM_ERROR: - printk("The firmware just choked.\n"); - hostdata->loop_up = -1; + printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id); + hostdata->adapter_state = AS_FIRMWARE_DEAD; break; case SCSI_COMMAND_COMPLETE: handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); @@ -1286,7 +1408,7 @@ Cmnd->result = 0x0; (*Cmnd->scsi_done) (Cmnd); } else - printk("qlogicfc.c: got a null value out of handle_ptrs, this sucks\n"); + printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id); break; case MBOX_COMMAND_COMPLETE: case INVALID_COMMAND: @@ -1301,37 +1423,54 @@ outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); return; default: - printk("qlogicfc: got an unknown status? %x\n", status); + printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status); } outw(0x0, host->io_port + PCI_SEMAPHORE); } else { - DEBUG_INTR(printk("qlogicfc : response queue update\n")); - DEBUG_INTR(printk("qlogicfc : response queue depth %d\n", RES_QUEUE_DEPTH(in_ptr, out_ptr))); + DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id)); + DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr))); while (out_ptr != in_ptr) { sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; TRACE("done", out_ptr, Cmnd); - DEBUG_INTR(isp2100_print_status_entry(sts)); - if (sts->hdr.entry_type == ENTRY_STATUS) { - Cmnd = hostdata->handle_ptrs[sts->handle]; - Cmnd->result = isp2100_return_status(sts); + DEBUG_INTR(isp2x00_print_status_entry(sts)); + if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { + Cmnd->result = isp2x00_return_status(sts); hostdata->handle_ptrs[sts->handle] = NULL; hostdata->queued--; - if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number) { + + /* + * if any of the following are true we do not + * call scsi_done. if the status is CS_ABORTED + * we dont have to call done because the upper + * level should already know its aborted. + */ + if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number + || sts->completion_status == CS_ABORTED){ hostdata->handle_serials[sts->handle] = 0; outw(out_ptr, host->io_port + MBOX5); continue; } - hostdata->handle_serials[sts->handle] = 0; + /* + * if we get back an error indicating the port + * is not there or if the link is down and + * this is a device that used to be there + * allow the command to timeout. + * the device may well be back in a couple of + * seconds. + */ + if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){ + outw(out_ptr, host->io_port + MBOX5); + continue; + } } else { outw(out_ptr, host->io_port + MBOX5); continue; } if (sts->completion_status == CS_RESET_OCCURRED - || sts->completion_status == CS_ABORTED || (sts->status_flags & STF_BUS_RESET)) hostdata->send_marker = 1; @@ -1345,7 +1484,7 @@ if (Cmnd->scsi_done != NULL) { (*Cmnd->scsi_done) (Cmnd); } else - printk("Ouch, scsi done is NULL\n"); + printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id); } hostdata->res_out_ptr = out_ptr; } @@ -1363,19 +1502,19 @@ if (host->can_queue <= host->host_busy){ if (host->can_queue+2 < host->host_busy) - DEBUG(printk("qlogicfc crosses its fingers.\n")); + DEBUG(printk("qlogicfc%d : crosses its fingers.\n", hostdata->host_id)); host->can_queue = host->host_busy + 1; } outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - LEAVE_INTR("isp2100_intr_handler"); + LEAVE_INTR("isp2x00_intr_handler"); } -static int isp2100_return_status(struct Status_Entry *sts) +static int isp2x00_return_status(struct Status_Entry *sts) { int host_status = DID_ERROR; -#if DEBUG_ISP2100_INTR +#if DEBUG_ISP2x00_INTR static char *reason[] = { "DID_OK", @@ -1389,9 +1528,9 @@ "DID_RESET", "DID_BAD_INTR" }; -#endif /* DEBUG_ISP2100_INTR */ +#endif /* DEBUG_ISP2x00_INTR */ - ENTER("isp2100_return_status"); + ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", sts->completion_status)); @@ -1436,93 +1575,105 @@ DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", reason[host_status], sts->scsi_status)); - LEAVE("isp2100_return_status"); + LEAVE("isp2x00_return_status"); return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -int isp2100_abort(Scsi_Cmnd * Cmnd) +int isp2x00_abort(Scsi_Cmnd * Cmnd) { u_short param[8]; int i; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; - int return_status = SCSI_ABORT_SUCCESS; + struct isp2x00_hostdata *hostdata; + int return_status = SUCCESS; - ENTER("isp2100_abort"); + ENTER("isp2x00_abort"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++) if (hostdata->handle_ptrs[i] == Cmnd) break; - if (i == QLOGICFC_REQ_QUEUE_LEN) - return SCSI_ABORT_ERROR; + if (i == QLOGICFC_REQ_QUEUE_LEN){ + return SUCCESS; + } - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); param[0] = MBOX_ABORT_IOCB; +#if ISP2x00_PORTDB + param[1] = (((u_short) hostdata->port_db[Cmnd->target].loop_id) << 8) | Cmnd->lun; +#else param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = i >> 16; - param[3] = i & 0xffff; +#endif + param[2] = i & 0xffff; + param[3] = i >> 16; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : scsi abort failure: %x\n", param[0]); + printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]); if (param[0] == 0x4005) Cmnd->result = DID_ERROR << 16; if (param[0] == 0x4006) Cmnd->result = DID_BAD_TARGET << 16; - (*Cmnd->scsi_done) (Cmnd); - return_status = SCSI_ABORT_ERROR; + return_status = FAILED; + } + + if (return_status != SUCCESS){ + param[0] = MBOX_GET_FIRMWARE_STATE; + isp2x00_mbox_command(host, param); + printk("qlogicfc%d : abort failed\n", hostdata->host_id); + printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]); } - isp2100_enable_irqs(host); - LEAVE("isp2100_abort"); + isp2x00_enable_irqs(host); + + LEAVE("isp2x00_abort"); return return_status; } -int isp2100_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) +int isp2x00_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) { u_short param[8]; struct Scsi_Host *host; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; int return_status = SCSI_RESET_SUCCESS; - ENTER("isp2100_reset"); + ENTER("isp2x00_reset"); host = Cmnd->host; - hostdata = (struct isp2100_hostdata *) host->hostdata; + hostdata = (struct isp2x00_hostdata *) host->hostdata; param[0] = MBOX_BUS_RESET; param[1] = 3; - isp2100_disable_irqs(host); + isp2x00_disable_irqs(host); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : scsi bus reset failure: %x\n", param[0]); + printk("qlogicfc%d : scsi bus reset failure: %x\n", hostdata->host_id, param[0]); return_status = SCSI_RESET_ERROR; } - isp2100_enable_irqs(host); + isp2x00_enable_irqs(host); - LEAVE("isp2100_reset"); + LEAVE("isp2x00_reset"); return return_status;; } -int isp2100_biosparam(Disk * disk, kdev_t n, int ip[]) +int isp2x00_biosparam(Disk * disk, kdev_t n, int ip[]) { int size = disk->capacity; - ENTER("isp2100_biosparam"); + ENTER("isp2x00_biosparam"); ip[0] = 64; ip[1] = 32; @@ -1532,19 +1683,21 @@ ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); } - LEAVE("isp2100_biosparam"); + LEAVE("isp2x00_biosparam"); return 0; } -static int isp2100_reset_hardware(struct Scsi_Host *host) +static int isp2x00_reset_hardware(struct Scsi_Host *host) { u_short param[8]; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; int loop_count; - ENTER("isp2100_reset_hardware"); + ENTER("isp2x00_reset_hardware"); + + hostdata = (struct isp2x00_hostdata *) host->hostdata; outw(0x01, host->io_port + ISP_CTRL_STATUS); outw(HCCR_RESET, host->io_port + HOST_HCCR); @@ -1555,35 +1708,46 @@ while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) barrier(); if (!loop_count) - printk("qlogicfc: reset_hardware loop timeout\n"); + printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id); -#if DEBUG_ISP2100 - printk("qlogicfc : mbox 0 0x%04x \n", inw(host->io_port + MBOX0)); - printk("qlogicfc : mbox 1 0x%04x \n", inw(host->io_port + MBOX1)); - printk("qlogicfc : mbox 2 0x%04x \n", inw(host->io_port + MBOX2)); - printk("qlogicfc : mbox 3 0x%04x \n", inw(host->io_port + MBOX3)); - printk("qlogicfc : mbox 4 0x%04x \n", inw(host->io_port + MBOX4)); - printk("qlogicfc : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); - printk("qlogicfc : mbox 6 0x%04x \n", inw(host->io_port + MBOX6)); - printk("qlogicfc : mbox 7 0x%04x \n", inw(host->io_port + MBOX7)); -#endif /* DEBUG_ISP2100 */ +#if DEBUG_ISP2x00 + printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX0)); + printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX1)); + printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX2)); + printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX3)); + printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX4)); + printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX5)); + printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX6)); + printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX7)); +#endif /* DEBUG_ISP2x00 */ - DEBUG(printk("qlogicfc : verifying checksum\n")); + DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id)); #if RELOAD_FIRMWARE { int i; - for (i = 0; i < risc_code_length01; i++) { + unsigned short * risc_code = NULL; + unsigned short risc_code_len = 0; + if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2100){ + risc_code = risc_code2100; + risc_code_len = risc_code_length2100; + } + else if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2200){ + risc_code = risc_code2200; + risc_code_len = risc_code_length2200; + } + + for (i = 0; i < risc_code_len; i++) { param[0] = MBOX_WRITE_RAM_WORD; param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; + param[2] = risc_code[i]; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : firmware load failure\n"); + printk("qlogicfc%d : firmware load failure\n", hostdata->host_id); return 1; } } @@ -1593,36 +1757,34 @@ param[0] = MBOX_VERIFY_CHECKSUM; param[1] = risc_code_addr01; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : ram checksum failure\n"); + printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id); return 1; } - DEBUG(printk("qlogicfc : executing firmware\n")); + DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id)); param[0] = MBOX_EXEC_FIRMWARE; param[1] = risc_code_addr01; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); param[0] = MBOX_ABOUT_FIRMWARE; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc : about firmware failure\n"); + printk("qlogicfc%d : about firmware failure\n", hostdata->host_id); return 1; } - DEBUG(printk("qlogicfc : firmware major revision %d\n", param[1])); - DEBUG(printk("qlogicfc : firmware minor revision %d\n", param[2])); - - hostdata = (struct isp2100_hostdata *) host->hostdata; + DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id, param[1])); + DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id, param[2])); #ifdef USE_NVRAM_DEFAULTS - if (isp2100_get_nvram_defaults(host, &hostdata->control_block) != 0) { - printk("qlogicfc: Could not read from NVRAM\n"); + if (isp2x00_get_nvram_defaults(host, &hostdata->control_block) != 0) { + printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id); } #endif @@ -1642,38 +1804,38 @@ param[5] = 0; param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc.c: Ouch 0x%04x\n", param[0]); + printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; - isp2100_mbox_command(host, param); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc.c: 0x%04x\n", param[0]); + printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); return 1; } - LEAVE("isp2100_reset_hardware"); + LEAVE("isp2x00_reset_hardware"); return 0; } #ifdef USE_NVRAM_DEFAULTS -static int isp2100_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) +static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) { u_short value; - if (isp2100_read_nvram_word(host, 0) != 0x5349) + if (isp2x00_read_nvram_word(host, 0) != 0x5349) return 1; - value = isp2100_read_nvram_word(host, 8); - control_block->node_name[0] = isp2100_read_nvram_word(host, 9); - control_block->node_name[1] = isp2100_read_nvram_word(host, 10); - control_block->node_name[2] = isp2100_read_nvram_word(host, 11); - control_block->node_name[3] = isp2100_read_nvram_word(host, 12); - control_block->hard_addr = isp2100_read_nvram_word(host, 13); + value = isp2x00_read_nvram_word(host, 8); + control_block->node_name[0] = isp2x00_read_nvram_word(host, 9); + control_block->node_name[1] = isp2x00_read_nvram_word(host, 10); + control_block->node_name[2] = isp2x00_read_nvram_word(host, 11); + control_block->node_name[3] = isp2x00_read_nvram_word(host, 12); + control_block->hard_addr = isp2x00_read_nvram_word(host, 13); return 0; @@ -1681,54 +1843,53 @@ #endif -static int isp2100_init(struct Scsi_Host *sh) +static int isp2x00_init(struct Scsi_Host *sh) { u_int io_base; - struct isp2100_hostdata *hostdata; + struct isp2x00_hostdata *hostdata; u_char revision; u_int irq; u_short command; struct pci_dev *pdev; - ENTER("isp2100_init"); + ENTER("isp2x00_init"); - hostdata = (struct isp2100_hostdata *) sh->hostdata; + hostdata = (struct isp2x00_hostdata *) sh->hostdata; pdev = hostdata->pci_dev; if (pci_read_config_word(pdev, PCI_COMMAND, &command) || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) { - printk("qlogicfc : error reading PCI configuration\n"); + printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id); return 1; } io_base = pdev->base_address[0]; irq = pdev->irq; - if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { - printk("qlogicfc : 0x%04x is not QLogic vendor ID\n", + printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, pdev->vendor); return 1; } - if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100) { - printk("qlogicfc : 0x%04x does not match ISP2100 device id\n", + if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100 && pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2200) { + printk("qlogicfc%d : 0x%04x does not match ISP2100 or ISP2200 device id\n", hostdata->host_id, pdev->device); return 1; } if (command & PCI_COMMAND_IO && (io_base & 3) == 1) io_base &= PCI_BASE_ADDRESS_IO_MASK; else { - printk("qlogicfc : i/o mapping is disabled\n"); + printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id); return 1; } if (!(command & PCI_COMMAND_MASTER)) { - printk("qlogicfc : bus mastering is disabled\n"); + printk("qlogicfc%d : bus mastering is disabled\n", hostdata->host_id); return 1; } - if (revision != ISP2100_REV_ID && revision != ISP2100_REV_ID3) - printk("qlogicfc : new isp2100 revision ID (%d)\n", revision); + if (revision != ISP2100_REV_ID1 && revision != ISP2100_REV_ID3 && revision != ISP2200_REV_ID5) + printk("qlogicfc%d : new isp2x00 revision ID (%d)\n", hostdata->host_id, revision); hostdata->revision = revision; @@ -1736,7 +1897,7 @@ sh->irq = irq; sh->io_port = io_base; - LEAVE("isp2100_init"); + LEAVE("isp2x00_init"); return 0; } @@ -1746,7 +1907,7 @@ #define NVRAM_DELAY() udelay(10) /* 10 microsecond delay */ -u_short isp2100_read_nvram_word(struct Scsi_Host * host, u_short byte) +u_short isp2x00_read_nvram_word(struct Scsi_Host * host, u_short byte) { int i; u_short value, output, input; @@ -1795,26 +1956,27 @@ * currently, this is only called during initialization or abort/reset, * at which times interrupts are disabled, so polling is OK, I guess... */ -static int isp2100_mbox_command(struct Scsi_Host *host, u_short param[]) +static int isp2x00_mbox_command(struct Scsi_Host *host, u_short param[]) { int loop_count; - struct isp2100_hostdata *hostdata = (struct isp2100_hostdata *) host->hostdata; + struct isp2x00_hostdata *hostdata = (struct isp2x00_hostdata *) host->hostdata; - if (mbox_param[param[0]] == 0) + if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD) return 1; loop_count = DEFAULT_LOOP_COUNT; while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) barrier(); if (!loop_count) { - printk("qlogicfc: mbox_command loop timeout #1\n"); + printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id); param[0] = 0x4006; + hostdata->adapter_state = AS_FIRMWARE_DEAD; return 1; } hostdata->mbox_done = 0; if (mbox_param[param[0]] == 0) - printk("qlogicfc: invalid mbox command\n"); + printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id); if (mbox_param[param[0]] & 0x80) outw(param[7], host->io_port + MBOX7); @@ -1843,10 +2005,11 @@ } if (!loop_count) { - printk("qlogicfc: mbox_command loop timeout #2\n"); + hostdata->adapter_state = AS_FIRMWARE_DEAD; + printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id); break; } - isp2100_intr_handler(host->irq, host, NULL); + isp2x00_intr_handler(host->irq, host, NULL); if (hostdata->mbox_done == 1) break; @@ -1858,7 +2021,7 @@ barrier(); } if (!loop_count) - printk("qlogicfc: mbox_command loop timeout #3\n"); + printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id); param[7] = inw(host->io_port + MBOX7); param[6] = inw(host->io_port + MBOX6); @@ -1873,19 +2036,21 @@ outw(0x0, host->io_port + PCI_SEMAPHORE); if (inw(host->io_port + HOST_HCCR) & 0x0080) { - printk("mbox op is still pending\n"); + hostdata->adapter_state = AS_FIRMWARE_DEAD; + printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id); } return 0; } +#if DEBUG_ISP2x00_INTR -void isp2100_print_status_entry(struct Status_Entry *status) +void isp2x00_print_status_entry(struct Status_Entry *status) { - printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", + printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", status->scsi_status, status->completion_status); - printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", + printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", status->state_flags, status->status_flags); printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", status->res_info_len, status->req_sense_len); @@ -1893,15 +2058,16 @@ } +#endif /* DEBUG_ISP2x00_INTR */ -#if DEBUG_ISP2100 +#if DEBUG_ISP2x00 -void isp2100_print_scsi_cmd(Scsi_Cmnd * cmd) +void isp2x00_print_scsi_cmd(Scsi_Cmnd * cmd) { int i; - printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", cmd->target, cmd->lun, cmd->cmd_len); printk("qlogicfc : command = "); for (i = 0; i < cmd->cmd_len; i++) @@ -1909,7 +2075,7 @@ printk("\n"); } -#endif /* DEBUG_ISP2100 */ +#endif /* DEBUG_ISP2x00 */ #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc.h linux.ac/drivers/scsi/qlogicfc.h --- linux.vanilla/drivers/scsi/qlogicfc.h Wed Mar 10 21:13:05 1999 +++ linux.ac/drivers/scsi/qlogicfc.h Mon Jul 19 03:18:18 1999 @@ -1,5 +1,5 @@ /* - * QLogic ISP2100 SCSI-FCP + * QLogic ISP2x00 SCSI-FCP * * Written by Erik H. Moe, ehm@cris.com * Copyright 1995, Erik H. Moe @@ -18,7 +18,7 @@ /* Renamed and updated to 1.3.x by Michael Griffith */ /* This is a version of the isp1020 driver which was modified by - * Chris Loveland to support the isp2100 + * Chris Loveland to support the isp2x00 */ @@ -61,39 +61,48 @@ * requests are queued serially and the scatter/gather limit is * determined for each queue request anew. */ -#define QLOGICFC_REQ_QUEUE_LEN 63 /* must be power of two - 1 */ -#define QLOGICFC_MAX_SG(ql) (2 + (((ql) > 0) ? 5*((ql) - 1) : 0)) + +#if BITS_PER_LONG > 32 +#define DATASEGS_PER_COMMAND 2 +#define DATASEGS_PER_CONT 5 +#else +#define DATASEGS_PER_COMMAND 3 +#define DATASEGS_PER_CONT 7 +#endif + +#define QLOGICFC_REQ_QUEUE_LEN 127 /* must be power of two - 1 */ +#define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0)) #define QLOGICFC_CMD_PER_LUN 8 -int isp2100_detect(Scsi_Host_Template *); -int isp2100_release(struct Scsi_Host *); -const char * isp2100_info(struct Scsi_Host *); -int isp2100_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); -int isp2100_abort(Scsi_Cmnd *); -int isp2100_reset(Scsi_Cmnd *, unsigned int); -int isp2100_biosparam(Disk *, kdev_t, int[]); +int isp2x00_detect(Scsi_Host_Template *); +int isp2x00_release(struct Scsi_Host *); +const char * isp2x00_info(struct Scsi_Host *); +int isp2x00_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int isp2x00_abort(Scsi_Cmnd *); +int isp2x00_reset(Scsi_Cmnd *, unsigned int); +int isp2x00_biosparam(Disk *, kdev_t, int[]); #ifndef NULL #define NULL (0) #endif -extern struct proc_dir_entry proc_scsi_isp2100; +extern struct proc_dir_entry proc_scsi_isp2x00; #define QLOGICFC { \ - detect: isp2100_detect, \ - release: isp2100_release, \ - info: isp2100_info, \ - queuecommand: isp2100_queuecommand, \ - abort: isp2100_abort, \ - reset: isp2100_reset, \ - bios_param: isp2100_biosparam, \ + detect: isp2x00_detect, \ + release: isp2x00_release, \ + info: isp2x00_info, \ + queuecommand: isp2x00_queuecommand, \ + eh_abort_handler: isp2x00_abort, \ + reset: isp2x00_reset, \ + bios_param: isp2x00_biosparam, \ can_queue: QLOGICFC_REQ_QUEUE_LEN, \ this_id: -1, \ sg_tablesize: QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN), \ - cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ + cmd_per_lun: QLOGICFC_CMD_PER_LUN, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING \ + use_clustering: ENABLE_CLUSTERING \ } #endif /* _QLOGICFC_H */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicfc_asm.c linux.ac/drivers/scsi/qlogicfc_asm.c --- linux.vanilla/drivers/scsi/qlogicfc_asm.c Fri Apr 16 22:10:55 1999 +++ linux.ac/drivers/scsi/qlogicfc_asm.c Mon Jul 19 03:18:20 1999 @@ -1,160 +1,141 @@ -/************************************************************************ - * * - * --- ISP2100 Fabric Initiator/Target Firmware --- * - * * - * * - ************************************************************************ - * * - * NOTICE * - * * - * COPYRIGHT 1998 QLOGIC CORPORATION * - * ALL RIGHTS RESERVED * - * * - ************************************************************************ - */ /* - * Firmware Version 1.15.19 (14:58 Jan 19, 1999) + * Firmware Version 1.15.37 (15:37 May 03, 1999) */ -unsigned short risc_code_version = 1*1024+15; - -unsigned char firmware_version[] = {1,15,19}; - -#define FW_VERSION_STRING "1.15.19" - unsigned short risc_code_addr01 = 0x1000 ; +unsigned short risc_code_length2100 = 0x65db; +unsigned short risc_code_length2200 = 0x81bd; -unsigned short risc_code01[] = { - 0x0078, 0x1029, 0x0000, 0x65e6, 0x0000, 0x2043, 0x4f50, 0x5952, +unsigned short risc_code2100[] = { + 0x0078, 0x1029, 0x0000, 0x65db, 0x0000, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x3620, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3135, 0x2020, 0x2020, - 0x2400, 0x20c1, 0x0021, 0x20a1, 0x75e6, 0x2009, 0x0000, 0x20a9, - 0x071a, 0x41a4, 0x3400, 0x20c9, 0x7aff, 0x2091, 0x2000, 0x2059, - 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x20a0, 0x2051, 0x7600, + 0x2400, 0x20c1, 0x0021, 0x20a1, 0x75db, 0x2009, 0x0000, 0x20a9, + 0x0725, 0x41a4, 0x3400, 0x20c9, 0x7aff, 0x2091, 0x2000, 0x2059, + 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x209a, 0x2051, 0x7600, 0x2a70, 0x705b, 0x9500, 0x705f, 0xffff, 0x7057, 0x94f9, 0x7063, - 0x0300, 0x1078, 0x1282, 0x20a1, 0x7d00, 0x715c, 0x810d, 0x810d, + 0x0300, 0x1078, 0x127a, 0x20a1, 0x7d00, 0x715c, 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0007, 0xa112, 0xa00e, 0x21a8, 0x41a4, 0x3400, 0x8211, 0x00c0, 0x1058, 0x715c, 0x3400, 0xa102, 0x0040, 0x1068, 0x0048, 0x1068, 0x20a8, 0xa00e, 0x41a4, - 0x1078, 0x1249, 0x1078, 0x136e, 0x1078, 0x14f3, 0x1078, 0x19c8, - 0x1078, 0x3615, 0x1078, 0x5b94, 0x1078, 0x12f9, 0x1078, 0x242f, - 0x1078, 0x3c56, 0x1078, 0x3a2e, 0x1078, 0x4494, 0x1078, 0x1e5b, - 0x1078, 0x46d3, 0x1078, 0x4174, 0x1078, 0x1d7a, 0x1078, 0x1e3a, + 0x1078, 0x1241, 0x1078, 0x1366, 0x1078, 0x14eb, 0x1078, 0x19c0, + 0x1078, 0x360d, 0x1078, 0x5b8c, 0x1078, 0x12f1, 0x1078, 0x2429, + 0x1078, 0x3c4e, 0x1078, 0x3a26, 0x1078, 0x448c, 0x1078, 0x1e55, + 0x1078, 0x46cb, 0x1078, 0x416c, 0x1078, 0x1d74, 0x1078, 0x1e34, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x109d, 0x7820, 0xa086, 0x0002, 0x00c0, 0x109d, 0x7823, 0x4000, 0x0068, 0x1095, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, 0xa08e, 0x0003, - 0x00c0, 0x10bd, 0x1078, 0x2d8d, 0x1078, 0x2457, 0x1078, 0x3ca6, - 0x1078, 0x3b19, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, - 0x10c1, 0x1078, 0x44ac, 0x0078, 0x10a4, 0x1079, 0x10c5, 0x0078, - 0x10aa, 0x1078, 0x5866, 0x0078, 0x10b9, 0x10cf, 0x10d0, 0x114b, - 0x10cd, 0x11c6, 0x1246, 0x1247, 0x1248, 0x1078, 0x12d5, 0x007c, - 0x127e, 0x0f7e, 0x2091, 0x8000, 0x1078, 0x2eb2, 0x2079, 0x0100, - 0x7844, 0xa005, 0x00c0, 0x113c, 0x2011, 0x3542, 0x1078, 0x456e, + 0x00c0, 0x10bd, 0x1078, 0x2d7e, 0x1078, 0x2451, 0x1078, 0x3c9e, + 0x1078, 0x3b11, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, + 0x10c1, 0x1078, 0x44a4, 0x0078, 0x10a4, 0x1079, 0x10c5, 0x0078, + 0x10aa, 0x1078, 0x585e, 0x0078, 0x10b9, 0x10cf, 0x10d0, 0x1143, + 0x10cd, 0x11be, 0x123e, 0x123f, 0x1240, 0x1078, 0x12cd, 0x007c, + 0x127e, 0x0f7e, 0x2091, 0x8000, 0x1078, 0x2ea3, 0x2079, 0x0100, + 0x7844, 0xa005, 0x00c0, 0x1134, 0x2011, 0x353a, 0x1078, 0x4566, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, - 0x73b8, 0x1078, 0x2d4a, 0x1078, 0x56b1, 0x2011, 0x0004, 0x1078, - 0x6953, 0x1078, 0x39c8, 0x70c7, 0x0000, 0x70bf, 0x0000, 0x70c3, - 0x0000, 0x1078, 0x113f, 0x2011, 0x0000, 0x2079, 0x7651, 0x7804, - 0xd0ac, 0x0040, 0x1104, 0xc295, 0x70a4, 0xa005, 0x0040, 0x1109, - 0xc29d, 0x72be, 0xa296, 0x0004, 0x0040, 0x112a, 0x2011, 0x0001, - 0x1078, 0x6953, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, - 0x0f7f, 0x1078, 0x2150, 0x2011, 0x0005, 0x1078, 0x57c0, 0x1078, - 0x4c7a, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x127f, - 0x0078, 0x113e, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, - 0x2011, 0x0005, 0x1078, 0x57c0, 0x1078, 0x4c7a, 0x0c7e, 0x2061, + 0x73b8, 0x1078, 0x2d3b, 0x1078, 0x56a9, 0x2011, 0x0004, 0x1078, + 0x694d, 0x1078, 0x39c0, 0x70c7, 0x0000, 0x70c3, 0x0000, 0x1078, + 0x1137, 0x72bc, 0x2079, 0x7651, 0x7804, 0xd0ac, 0x0040, 0x1101, + 0xc295, 0x72be, 0xa296, 0x0004, 0x0040, 0x1122, 0x2011, 0x0001, + 0x1078, 0x694d, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, + 0x0f7f, 0x1078, 0x214a, 0x2011, 0x0005, 0x1078, 0x57b8, 0x1078, + 0x4c72, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x127f, + 0x0078, 0x1136, 0x708b, 0x0000, 0x708f, 0xffff, 0x7003, 0x0002, + 0x2011, 0x0005, 0x1078, 0x57b8, 0x1078, 0x4c72, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, 0x0f7f, 0x127f, 0x007c, 0x0c7e, - 0x20a9, 0x0082, 0x2009, 0x007e, 0x1078, 0x380d, 0x8108, 0x00f0, - 0x1144, 0x0c7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x708c, 0xa086, - 0xffff, 0x0040, 0x1159, 0x1078, 0x2150, 0x1078, 0x4c7a, 0x0078, - 0x11c4, 0x70bc, 0xd09c, 0x0040, 0x1181, 0xd084, 0x0040, 0x1181, + 0x20a9, 0x0082, 0x2009, 0x007e, 0x1078, 0x3805, 0x8108, 0x00f0, + 0x113c, 0x0c7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x708c, 0xa086, + 0xffff, 0x0040, 0x1151, 0x1078, 0x214a, 0x1078, 0x4c72, 0x0078, + 0x11bc, 0x70bc, 0xd09c, 0x0040, 0x1179, 0xd084, 0x0040, 0x1179, 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, - 0x0040, 0x1181, 0x70c0, 0xa086, 0xffff, 0x0040, 0x117d, 0x1078, - 0x2245, 0x1078, 0x4c7a, 0x2011, 0x0001, 0x2019, 0x0000, 0x1078, - 0x227d, 0x1078, 0x4c7a, 0x0078, 0x11c4, 0x70c4, 0xa005, 0x00c0, - 0x11c4, 0x7088, 0xa005, 0x00c0, 0x11c4, 0x2001, 0x7652, 0x2004, - 0xd0ac, 0x0040, 0x11a7, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x017e, 0x1078, 0x3825, 0x00c0, 0x119a, 0x6000, 0xd0ec, - 0x00c0, 0x11a2, 0x017f, 0x8108, 0x00f0, 0x1191, 0x0c7f, 0x157f, - 0x0078, 0x11a7, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x11c4, 0x7003, - 0x0003, 0x708f, 0xffff, 0x2001, 0x0000, 0x1078, 0x202b, 0x1078, - 0x2dc8, 0x2001, 0x7837, 0x2004, 0xa086, 0x0005, 0x00c0, 0x11bc, - 0x2011, 0x0000, 0x1078, 0x57c0, 0x2011, 0x0000, 0x1078, 0x57ca, - 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x127f, 0x007c, 0x017e, 0x0f7e, + 0x0040, 0x1179, 0x70c0, 0xa086, 0xffff, 0x0040, 0x1175, 0x1078, + 0x223f, 0x1078, 0x4c72, 0x2011, 0x0001, 0x2019, 0x0000, 0x1078, + 0x2277, 0x1078, 0x4c72, 0x0078, 0x11bc, 0x70c4, 0xa005, 0x00c0, + 0x11bc, 0x7088, 0xa005, 0x00c0, 0x11bc, 0x2001, 0x7652, 0x2004, + 0xd0ac, 0x0040, 0x119f, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x017e, 0x1078, 0x381d, 0x00c0, 0x1192, 0x6000, 0xd0ec, + 0x00c0, 0x119a, 0x017f, 0x8108, 0x00f0, 0x1189, 0x0c7f, 0x157f, + 0x0078, 0x119f, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x11bc, 0x7003, + 0x0003, 0x708f, 0xffff, 0x2001, 0x0000, 0x1078, 0x2025, 0x1078, + 0x2db9, 0x2001, 0x7837, 0x2004, 0xa086, 0x0005, 0x00c0, 0x11b4, + 0x2011, 0x0000, 0x1078, 0x57b8, 0x2011, 0x0000, 0x1078, 0x57c2, + 0x1078, 0x4c72, 0x1078, 0x4d32, 0x127f, 0x007c, 0x017e, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x7940, 0xa18c, 0x0010, - 0x7942, 0x7924, 0xd1b4, 0x0040, 0x11d7, 0x7827, 0x0040, 0xd19c, - 0x0040, 0x11dc, 0x7827, 0x0008, 0x007e, 0x037e, 0x157e, 0x7900, - 0xa18a, 0x0003, 0x0050, 0x1202, 0x7954, 0xd1ac, 0x00c0, 0x1202, - 0x2009, 0x00f8, 0x1078, 0x35e4, 0x7843, 0x0090, 0x7843, 0x0010, - 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x11fa, 0x7824, 0xd0ac, - 0x00c0, 0x1236, 0x00f0, 0x11f2, 0x2001, 0x0001, 0x1078, 0x202b, - 0x0078, 0x123f, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0008, - 0x00e0, 0x1208, 0x2091, 0x6000, 0x00f0, 0x1208, 0x7853, 0x0400, - 0x782f, 0x0000, 0x2009, 0x00f8, 0x1078, 0x35e4, 0x20a9, 0x000e, - 0x0005, 0x00f0, 0x1218, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, + 0x7942, 0x7924, 0xd1b4, 0x0040, 0x11cf, 0x7827, 0x0040, 0xd19c, + 0x0040, 0x11d4, 0x7827, 0x0008, 0x007e, 0x037e, 0x157e, 0x7900, + 0xa18a, 0x0003, 0x0050, 0x11fa, 0x7954, 0xd1ac, 0x00c0, 0x11fa, + 0x2009, 0x00f8, 0x1078, 0x35dc, 0x7843, 0x0090, 0x7843, 0x0010, + 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x11f2, 0x7824, 0xd0ac, + 0x00c0, 0x122e, 0x00f0, 0x11ea, 0x2001, 0x0001, 0x1078, 0x2025, + 0x0078, 0x1237, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0008, + 0x00e0, 0x1200, 0x2091, 0x6000, 0x00f0, 0x1200, 0x7853, 0x0400, + 0x782f, 0x0000, 0x2009, 0x00f8, 0x1078, 0x35dc, 0x20a9, 0x000e, + 0x0005, 0x00f0, 0x1210, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, - 0x122d, 0x7824, 0xd0ac, 0x00c0, 0x1236, 0x8319, 0x00c0, 0x1223, - 0x2001, 0x0001, 0x1078, 0x202b, 0x0078, 0x123d, 0x7828, 0xc09d, + 0x1225, 0x7824, 0xd0ac, 0x00c0, 0x122e, 0x8319, 0x00c0, 0x121b, + 0x2001, 0x0001, 0x1078, 0x2025, 0x0078, 0x1235, 0x7828, 0xc09d, 0x782a, 0x7827, 0x0008, 0x7827, 0x0040, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, - 0x1255, 0x704f, 0xffff, 0x0078, 0x1257, 0x704f, 0x0000, 0x7053, + 0x124d, 0x704f, 0xffff, 0x0078, 0x124f, 0x704f, 0x0000, 0x7053, 0xffff, 0x7067, 0x0000, 0x706b, 0x0000, 0x2061, 0x7820, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0x7828, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, - 0x0000, 0x007c, 0x1078, 0x12a8, 0x2011, 0x0000, 0x81ff, 0x0040, - 0x12a7, 0xa186, 0x0001, 0x00c0, 0x1297, 0x705f, 0x8fff, 0x7057, - 0x8501, 0x7063, 0x0100, 0x705b, 0x8500, 0x0078, 0x12a5, 0xa186, - 0x0002, 0x00c0, 0x129f, 0x2011, 0x0000, 0x0078, 0x12a5, 0xa186, - 0x0005, 0x00c0, 0x12a5, 0x2011, 0x0001, 0x1078, 0x12cf, 0x007c, - 0x2009, 0x0000, 0x2011, 0x0000, 0x1078, 0x12cf, 0x2019, 0xaaaa, + 0x0000, 0x007c, 0x1078, 0x12a0, 0x2011, 0x0000, 0x81ff, 0x0040, + 0x129f, 0xa186, 0x0001, 0x00c0, 0x128f, 0x705f, 0x8fff, 0x7057, + 0x8501, 0x7063, 0x0100, 0x705b, 0x8500, 0x0078, 0x129d, 0xa186, + 0x0002, 0x00c0, 0x1297, 0x2011, 0x0000, 0x0078, 0x129d, 0xa186, + 0x0005, 0x00c0, 0x129d, 0x2011, 0x0001, 0x1078, 0x12c7, 0x007c, + 0x2009, 0x0000, 0x2011, 0x0000, 0x1078, 0x12c7, 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2362, 0x2c24, 0x2061, 0x7fff, 0x2c04, 0xa406, - 0x0040, 0x12bd, 0xc18d, 0x0078, 0x12ca, 0xc185, 0x2011, 0x0001, - 0x1078, 0x12cf, 0x2061, 0xffff, 0x2362, 0x2c04, 0xa306, 0x00c0, - 0x12ca, 0xc195, 0x2011, 0x0001, 0x1078, 0x12cf, 0x007c, 0x3800, + 0x0040, 0x12b5, 0xc18d, 0x0078, 0x12c2, 0xc185, 0x2011, 0x0001, + 0x1078, 0x12c7, 0x2061, 0xffff, 0x2362, 0x2c04, 0xa306, 0x00c0, + 0x12c2, 0xc195, 0x2011, 0x0001, 0x1078, 0x12c7, 0x007c, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x007c, 0x2091, 0x8000, 0x0068, - 0x12d7, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, - 0x00c0, 0x12dd, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, + 0x12cf, 0x007e, 0x017e, 0x2079, 0x0000, 0x7818, 0xa084, 0x0000, + 0x00c0, 0x12d5, 0x017f, 0x792e, 0x007f, 0x782a, 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12f6, + 0x2091, 0x4080, 0x2079, 0x7600, 0x7803, 0x0005, 0x0078, 0x12ee, 0x007c, 0x2071, 0x7600, 0x7158, 0x712e, 0x2021, 0x0001, 0xa190, - 0x002d, 0xa298, 0x002d, 0x0048, 0x130f, 0x705c, 0xa302, 0x00c8, - 0x130f, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x1301, 0x200b, + 0x002d, 0xa298, 0x002d, 0x0048, 0x1307, 0x705c, 0xa302, 0x00c8, + 0x1307, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, 0x12f9, 0x200b, 0x0000, 0x749e, 0x74a2, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, - 0x2071, 0x7600, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x1322, 0xa06e, - 0x0078, 0x132c, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, + 0x2071, 0x7600, 0x70a0, 0xa0ea, 0x0010, 0x00c8, 0x131a, 0xa06e, + 0x0078, 0x1324, 0x8001, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x127e, 0x2091, 0x8000, 0x70a0, 0x8001, 0x00c8, - 0x133c, 0xa06e, 0x0078, 0x1345, 0x70a2, 0x702c, 0x2068, 0x2d04, + 0x1334, 0xa06e, 0x0078, 0x133d, 0x70a2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, 0x8000, 0x70a2, 0x127f, 0x0e7f, 0x007c, - 0x8dff, 0x0040, 0x1364, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, - 0x1348, 0x0d7f, 0x0078, 0x1358, 0x007c, 0x0e7e, 0x2071, 0x7600, + 0x8dff, 0x0040, 0x135c, 0x6804, 0x6807, 0x0000, 0x007e, 0x1078, + 0x1340, 0x0d7f, 0x0078, 0x1350, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x70a0, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, 0x007c, 0x0e7e, 0x2270, 0x700b, 0x0000, 0x2071, 0x7859, 0x7018, 0xa088, 0x7862, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, - 0x1397, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a8, 0x0f7f, 0x0e7f, - 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7004, 0xa005, 0x00c0, 0x13a6, - 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a8, 0x0f7f, 0x0e7f, 0x007c, - 0x7000, 0x0079, 0x13ab, 0x13af, 0x1419, 0x1436, 0x1436, 0x7018, - 0x711c, 0xa106, 0x00c0, 0x13b7, 0x7007, 0x0000, 0x007c, 0x0d7e, + 0x138f, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a0, 0x0f7f, 0x0e7f, + 0x007c, 0x0e7e, 0x2071, 0x7859, 0x7004, 0xa005, 0x00c0, 0x139e, + 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13a0, 0x0f7f, 0x0e7f, 0x007c, + 0x7000, 0x0079, 0x13a3, 0x13a7, 0x1411, 0x142e, 0x142e, 0x7018, + 0x711c, 0xa106, 0x00c0, 0x13af, 0x7007, 0x0000, 0x007c, 0x0d7e, 0xa180, 0x7862, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, - 0x0d7f, 0xd084, 0x0040, 0x13d9, 0x7007, 0x0001, 0x1078, 0x13de, - 0x007c, 0x7007, 0x0002, 0x1078, 0x13f4, 0x007c, 0x017e, 0x027e, - 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13e9, 0x2110, + 0x0d7f, 0xd084, 0x0040, 0x13d1, 0x7007, 0x0001, 0x1078, 0x13d6, + 0x007c, 0x7007, 0x0002, 0x1078, 0x13ec, 0x007c, 0x017e, 0x027e, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x13e1, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, 0x137e, 0x147e, 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, - 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1408, 0x2110, 0xa006, + 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1400, 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0001, 0x3300, 0x7016, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f, 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0x76e5, 0x20a1, 0x0018, @@ -167,1088 +148,1088 @@ 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0x7711, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e, 0x2071, 0x7859, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, - 0xd1fc, 0x0040, 0x1479, 0xa18c, 0x0700, 0x0040, 0x1476, 0x7008, - 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, 0x1479, 0x7004, 0x1079, - 0x147d, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13a8, 0x1485, 0x14a7, - 0x14c1, 0x14ea, 0x1483, 0x0078, 0x1483, 0x137e, 0x147e, 0x157e, + 0xd1fc, 0x0040, 0x1471, 0xa18c, 0x0700, 0x0040, 0x146e, 0x7008, + 0xa080, 0x0002, 0x2003, 0x0200, 0x0078, 0x1471, 0x7004, 0x1079, + 0x1475, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13a0, 0x147d, 0x149f, + 0x14b9, 0x14e2, 0x147b, 0x0078, 0x147b, 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f, 0x137f, 0x700c, 0xa005, - 0x0040, 0x14ae, 0x1078, 0x13de, 0x007c, 0x7008, 0xa080, 0x0002, - 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x13a8, 0x007c, 0x700c, - 0xa005, 0x0040, 0x14ae, 0x1078, 0x13f4, 0x007c, 0x0d7e, 0x7008, + 0x0040, 0x14a6, 0x1078, 0x13d6, 0x007c, 0x7008, 0xa080, 0x0002, + 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x13a0, 0x007c, 0x700c, + 0xa005, 0x0040, 0x14a6, 0x1078, 0x13ec, 0x007c, 0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, - 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a8, + 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x13a0, 0x007c, 0x137e, 0x147e, 0x157e, 0x2001, 0x76e3, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, - 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14e0, 0x2001, + 0x53a5, 0x2001, 0x76e5, 0x2004, 0xd0bc, 0x0040, 0x14d8, 0x2001, 0x76ee, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, - 0x157f, 0x147f, 0x137f, 0x7007, 0x0000, 0x1078, 0x3d4f, 0x1078, - 0x13a8, 0x007c, 0x2001, 0x7713, 0x2003, 0x0100, 0x7007, 0x0000, - 0x1078, 0x13a8, 0x007c, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, + 0x157f, 0x147f, 0x137f, 0x7007, 0x0000, 0x1078, 0x3d47, 0x1078, + 0x13a0, 0x007c, 0x2001, 0x7713, 0x2003, 0x0100, 0x7007, 0x0000, + 0x1078, 0x13a0, 0x007c, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0x786a, 0x7003, 0x0000, 0x700f, 0x7870, 0x7013, 0x7870, 0x780f, 0x0070, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079, - 0x1509, 0x1511, 0x1557, 0x1511, 0x1511, 0x1511, 0x153c, 0x1520, - 0x1515, 0xa085, 0x0001, 0x0078, 0x1571, 0x684c, 0xd0bc, 0x0040, - 0x1511, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x155f, - 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1511, 0x684c, 0xd0bc, - 0x0040, 0x1511, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, - 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, - 0x6832, 0x6858, 0x0078, 0x1567, 0xa18c, 0x00ff, 0xa186, 0x0015, - 0x00c0, 0x1511, 0x684c, 0xd0ac, 0x0040, 0x1511, 0x6804, 0x681a, - 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, - 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x1567, 0x684c, - 0xd0ac, 0x0040, 0x1511, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, - 0x000f, 0xa188, 0x1c84, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, + 0x1501, 0x1509, 0x154f, 0x1509, 0x1509, 0x1509, 0x1534, 0x1518, + 0x150d, 0xa085, 0x0001, 0x0078, 0x1569, 0x684c, 0xd0bc, 0x0040, + 0x1509, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x1557, + 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1509, 0x684c, 0xd0bc, + 0x0040, 0x1509, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, + 0x6832, 0x6858, 0x0078, 0x155f, 0xa18c, 0x00ff, 0xa186, 0x0015, + 0x00c0, 0x1509, 0x684c, 0xd0ac, 0x0040, 0x1509, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, + 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x155f, 0x684c, + 0xd0ac, 0x0040, 0x1509, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, + 0x000f, 0xa188, 0x1c7e, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a, - 0x2004, 0x82ff, 0x0040, 0x158c, 0xa280, 0x0004, 0x0d7e, 0x206c, - 0x684c, 0xd0dc, 0x00c0, 0x1588, 0x1078, 0x1504, 0x10c0, 0x12d5, + 0x2004, 0x82ff, 0x0040, 0x1584, 0xa280, 0x0004, 0x0d7e, 0x206c, + 0x684c, 0xd0dc, 0x00c0, 0x1580, 0x1078, 0x14fc, 0x10c0, 0x12cd, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0, - 0x15a0, 0x7206, 0x2001, 0x15b4, 0x007e, 0x2260, 0x0078, 0x16cc, + 0x1598, 0x7206, 0x2001, 0x15ac, 0x007e, 0x2260, 0x0078, 0x16c4, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, - 0x788b, 0x0048, 0x15ad, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, - 0x00c0, 0x15b4, 0x1078, 0x16b5, 0x127f, 0x007c, 0x127e, 0x027e, + 0x788b, 0x0048, 0x15a5, 0x2009, 0x7870, 0x710e, 0x7000, 0xa005, + 0x00c0, 0x15ac, 0x1078, 0x16ad, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, 0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, 0x0d7e, 0x0c7e, 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, - 0xa005, 0x0040, 0x1608, 0x6808, 0xa005, 0x0040, 0x166e, 0x7000, - 0xa005, 0x00c0, 0x15d5, 0x0078, 0x1602, 0x700c, 0x7110, 0xa106, - 0x00c0, 0x1672, 0x7004, 0xa406, 0x00c0, 0x1602, 0x2001, 0x0005, - 0x2004, 0xd08c, 0x0040, 0x15eb, 0x047e, 0x1078, 0x178d, 0x047f, - 0x2460, 0x0078, 0x15cb, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, - 0x15de, 0x7804, 0xa084, 0x6000, 0x0040, 0x15fc, 0xa086, 0x6000, - 0x0040, 0x15fc, 0x0078, 0x15de, 0x7803, 0x0004, 0x7003, 0x0000, - 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5c29, 0x0078, 0x1672, - 0x6808, 0xa005, 0x0040, 0x166e, 0x7000, 0xa005, 0x00c0, 0x1612, - 0x0078, 0x166e, 0x700c, 0x7110, 0xa106, 0x00c0, 0x161b, 0x7004, - 0xa406, 0x00c0, 0x166e, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, - 0x1628, 0x047e, 0x1078, 0x178d, 0x047f, 0x2460, 0x0078, 0x1608, - 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x161b, 0x2001, 0x0005, - 0x2004, 0xd08c, 0x00c0, 0x1621, 0x7804, 0xa084, 0x6000, 0x0040, - 0x163f, 0xa086, 0x6000, 0x0040, 0x163f, 0x0078, 0x161b, 0x7007, - 0x0000, 0xa016, 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x1660, - 0xa08e, 0x0002, 0x00c0, 0x166e, 0x0c7e, 0x0e7e, 0x6818, 0x2060, - 0x1078, 0x1c59, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x165c, - 0x7308, 0x720c, 0x0078, 0x165e, 0x7310, 0x7214, 0x0e7f, 0x0c7f, + 0xa005, 0x0040, 0x1600, 0x6808, 0xa005, 0x0040, 0x1666, 0x7000, + 0xa005, 0x00c0, 0x15cd, 0x0078, 0x15fa, 0x700c, 0x7110, 0xa106, + 0x00c0, 0x166a, 0x7004, 0xa406, 0x00c0, 0x15fa, 0x2001, 0x0005, + 0x2004, 0xd08c, 0x0040, 0x15e3, 0x047e, 0x1078, 0x1785, 0x047f, + 0x2460, 0x0078, 0x15c3, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, + 0x15d6, 0x7804, 0xa084, 0x6000, 0x0040, 0x15f4, 0xa086, 0x6000, + 0x0040, 0x15f4, 0x0078, 0x15d6, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x5c21, 0x0078, 0x166a, + 0x6808, 0xa005, 0x0040, 0x1666, 0x7000, 0xa005, 0x00c0, 0x160a, + 0x0078, 0x1666, 0x700c, 0x7110, 0xa106, 0x00c0, 0x1613, 0x7004, + 0xa406, 0x00c0, 0x1666, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, + 0x1620, 0x047e, 0x1078, 0x1785, 0x047f, 0x2460, 0x0078, 0x1600, + 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1613, 0x2001, 0x0005, + 0x2004, 0xd08c, 0x00c0, 0x1619, 0x7804, 0xa084, 0x6000, 0x0040, + 0x1637, 0xa086, 0x6000, 0x0040, 0x1637, 0x0078, 0x1613, 0x7007, + 0x0000, 0xa016, 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x1658, + 0xa08e, 0x0002, 0x00c0, 0x1666, 0x0c7e, 0x0e7e, 0x6818, 0x2060, + 0x1078, 0x1c53, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x1654, + 0x7308, 0x720c, 0x0078, 0x1656, 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, 0x7824, 0xa211, 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, - 0x2071, 0x786a, 0x7000, 0xa086, 0x0000, 0x0040, 0x16b2, 0x7004, - 0xac06, 0x00c0, 0x16a3, 0x2079, 0x0030, 0x7804, 0xd0fc, 0x00c0, - 0x169f, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1685, 0x7803, - 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1691, 0x7803, 0x0002, 0x7803, - 0x0009, 0x7003, 0x0003, 0x7007, 0x0000, 0x0078, 0x16a3, 0x1078, - 0x178d, 0x0078, 0x167a, 0x157e, 0x20a9, 0x0009, 0x2009, 0x7870, - 0x2104, 0xac06, 0x00c0, 0x16ad, 0x200a, 0xa188, 0x0003, 0x00f0, - 0x16a8, 0x157f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, 0x7110, 0xa106, - 0x00c0, 0x16bd, 0x7003, 0x0000, 0x007c, 0x2104, 0x7006, 0x2060, + 0x1078, 0x5c21, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, + 0x2071, 0x786a, 0x7000, 0xa086, 0x0000, 0x0040, 0x16aa, 0x7004, + 0xac06, 0x00c0, 0x169b, 0x2079, 0x0030, 0x7804, 0xd0fc, 0x00c0, + 0x1697, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x167d, 0x7803, + 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1689, 0x7803, 0x0002, 0x7803, + 0x0009, 0x7003, 0x0003, 0x7007, 0x0000, 0x0078, 0x169b, 0x1078, + 0x1785, 0x0078, 0x1672, 0x157e, 0x20a9, 0x0009, 0x2009, 0x7870, + 0x2104, 0xac06, 0x00c0, 0x16a5, 0x200a, 0xa188, 0x0003, 0x00f0, + 0x16a0, 0x157f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, 0x7110, 0xa106, + 0x00c0, 0x16b5, 0x7003, 0x0000, 0x007c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, 0x788b, 0x0048, - 0x16cb, 0x2009, 0x7870, 0x7112, 0x8cff, 0x00c0, 0x16d3, 0x1078, - 0x1958, 0x0078, 0x16fa, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, - 0x00c0, 0x16de, 0x682c, 0xa306, 0x0040, 0x16e2, 0x1078, 0x1ca4, - 0x00c0, 0x16cf, 0x684c, 0xd0f4, 0x00c0, 0x16cf, 0x6824, 0x2050, + 0x16c3, 0x2009, 0x7870, 0x7112, 0x8cff, 0x00c0, 0x16cb, 0x1078, + 0x1950, 0x0078, 0x16f2, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, + 0x00c0, 0x16d6, 0x682c, 0xa306, 0x0040, 0x16da, 0x1078, 0x1c9e, + 0x00c0, 0x16c7, 0x684c, 0xd0f4, 0x00c0, 0x16c7, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009, - 0x0011, 0x1078, 0x16fb, 0x0040, 0x16f9, 0x2009, 0x0001, 0x1078, - 0x16fb, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x1788, 0xa03e, 0x2730, - 0x6850, 0xd0fc, 0x00c0, 0x171a, 0x0d7e, 0x2804, 0xac68, 0x2900, - 0x0079, 0x170a, 0x176a, 0x172a, 0x172a, 0x176a, 0x176a, 0x1762, - 0x176a, 0x172a, 0x176a, 0x1730, 0x1730, 0x176a, 0x176a, 0x176a, - 0x1759, 0x1730, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, - 0x0d7e, 0xd99c, 0x0040, 0x176d, 0x2804, 0xac68, 0x6f08, 0x6e0c, - 0x0078, 0x176d, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x176d, - 0x7b0c, 0xd3bc, 0x0040, 0x1751, 0x7004, 0x0e7e, 0x2070, 0x701c, - 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1751, 0x7b08, 0xa39c, 0x0fff, - 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, 0x00c0, 0x174c, 0x6810, - 0xa302, 0x0048, 0x174c, 0x6b10, 0x2011, 0x0000, 0x2468, 0x0078, - 0x1753, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, - 0x176d, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, - 0x00c0, 0x176a, 0x0d7f, 0x1078, 0x1c40, 0x00c0, 0x16fb, 0xa00e, - 0x0078, 0x1788, 0x0d7f, 0x1078, 0x12d5, 0x7b22, 0x7a26, 0x7d32, + 0x0011, 0x1078, 0x16f3, 0x0040, 0x16f1, 0x2009, 0x0001, 0x1078, + 0x16f3, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x1780, 0xa03e, 0x2730, + 0x6850, 0xd0fc, 0x00c0, 0x1712, 0x0d7e, 0x2804, 0xac68, 0x2900, + 0x0079, 0x1702, 0x1762, 0x1722, 0x1722, 0x1762, 0x1762, 0x175a, + 0x1762, 0x1722, 0x1762, 0x1728, 0x1728, 0x1762, 0x1762, 0x1762, + 0x1751, 0x1728, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, + 0x0d7e, 0xd99c, 0x0040, 0x1765, 0x2804, 0xac68, 0x6f08, 0x6e0c, + 0x0078, 0x1765, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1765, + 0x7b0c, 0xd3bc, 0x0040, 0x1749, 0x7004, 0x0e7e, 0x2070, 0x701c, + 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1749, 0x7b08, 0xa39c, 0x0fff, + 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, 0x00c0, 0x1744, 0x6810, + 0xa302, 0x0048, 0x1744, 0x6b10, 0x2011, 0x0000, 0x2468, 0x0078, + 0x174b, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, + 0x1765, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, + 0x00c0, 0x1762, 0x0d7f, 0x1078, 0x1c3a, 0x00c0, 0x16f3, 0xa00e, + 0x0078, 0x1780, 0x0d7f, 0x1078, 0x12cd, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x2300, 0x6b10, - 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, 0x6816, 0x1078, 0x1c40, - 0x007c, 0x1078, 0x12d5, 0x1078, 0x12d5, 0x127e, 0x2091, 0x2100, + 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, 0x6816, 0x1078, 0x1c3a, + 0x007c, 0x1078, 0x12cd, 0x1078, 0x12cd, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, - 0xa184, 0x0700, 0x00c0, 0x178b, 0xa184, 0x0003, 0xa086, 0x0003, - 0x0040, 0x178b, 0x7000, 0x0079, 0x17a5, 0x17ad, 0x17af, 0x1887, - 0x18ef, 0x1906, 0x17ad, 0x17ad, 0x17ad, 0x1078, 0x12d5, 0x8001, - 0x7002, 0xa184, 0x0880, 0x00c0, 0x17c4, 0x8aff, 0x0040, 0x1827, - 0x2009, 0x0001, 0x1078, 0x16fb, 0x0040, 0x1918, 0x2009, 0x0001, - 0x1078, 0x16fb, 0x0078, 0x1918, 0x7803, 0x0004, 0x7003, 0x0000, - 0xd1bc, 0x00c0, 0x180f, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x7820, + 0xa184, 0x0700, 0x00c0, 0x1783, 0xa184, 0x0003, 0xa086, 0x0003, + 0x0040, 0x1783, 0x7000, 0x0079, 0x179d, 0x17a5, 0x17a7, 0x187f, + 0x18e7, 0x18fe, 0x17a5, 0x17a5, 0x17a5, 0x1078, 0x12cd, 0x8001, + 0x7002, 0xa184, 0x0880, 0x00c0, 0x17bc, 0x8aff, 0x0040, 0x181f, + 0x2009, 0x0001, 0x1078, 0x16f3, 0x0040, 0x1910, 0x2009, 0x0001, + 0x1078, 0x16f3, 0x0078, 0x1910, 0x7803, 0x0004, 0x7003, 0x0000, + 0xd1bc, 0x00c0, 0x1807, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x7820, 0x6910, 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x037f, - 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c59, 0x2a00, + 0x027f, 0x7830, 0x681e, 0x7834, 0x6822, 0x1078, 0x1c53, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x6850, - 0xc0fd, 0x6852, 0x6808, 0x8001, 0x680a, 0x00c0, 0x1801, 0x684c, - 0xd0e4, 0x0040, 0x1801, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, - 0x5c29, 0x7808, 0xd0ec, 0x00c0, 0x180b, 0x7803, 0x0009, 0x7003, - 0x0004, 0x0078, 0x1918, 0x1078, 0x16b5, 0x0078, 0x1918, 0x057e, - 0x7d0c, 0xd5bc, 0x00c0, 0x1816, 0x1078, 0x7592, 0x057f, 0x1078, - 0x191c, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, - 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x684c, - 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x183f, 0x7003, 0x0000, - 0x6808, 0x8001, 0x680a, 0x00c0, 0x183b, 0x7004, 0x2060, 0x2009, - 0x0048, 0x1078, 0x5c29, 0x1078, 0x16b5, 0x0078, 0x1918, 0x7814, + 0xc0fd, 0x6852, 0x6808, 0x8001, 0x680a, 0x00c0, 0x17f9, 0x684c, + 0xd0e4, 0x0040, 0x17f9, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, + 0x5c21, 0x7808, 0xd0ec, 0x00c0, 0x1803, 0x7803, 0x0009, 0x7003, + 0x0004, 0x0078, 0x1910, 0x1078, 0x16ad, 0x0078, 0x1910, 0x057e, + 0x7d0c, 0xd5bc, 0x00c0, 0x180e, 0x1078, 0x7587, 0x057f, 0x1078, + 0x1914, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, + 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x684c, + 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x1837, 0x7003, 0x0000, + 0x6808, 0x8001, 0x680a, 0x00c0, 0x1833, 0x7004, 0x2060, 0x2009, + 0x0048, 0x1078, 0x5c21, 0x1078, 0x16ad, 0x0078, 0x1910, 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, - 0x1078, 0x1983, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, - 0x7804, 0xd0fc, 0x0040, 0x1860, 0x7803, 0x0002, 0x7803, 0x0004, + 0x1078, 0x197b, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, + 0x7804, 0xd0fc, 0x0040, 0x1858, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x0070, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x1078, 0x19a6, 0x0040, 0x183b, 0x7908, 0xd1ec, - 0x00c0, 0x187e, 0x2009, 0x0009, 0x0078, 0x1880, 0x2009, 0x0019, - 0x7902, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x8001, - 0x7002, 0xd194, 0x0040, 0x1899, 0x7804, 0xd0fc, 0x00c0, 0x1795, - 0x8aff, 0x0040, 0x1918, 0x2009, 0x0001, 0x1078, 0x16fb, 0x0078, - 0x1918, 0xa184, 0x0880, 0x00c0, 0x18a6, 0x8aff, 0x0040, 0x1918, - 0x2009, 0x0001, 0x1078, 0x16fb, 0x0078, 0x1918, 0x7803, 0x0004, - 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x18da, 0x027e, 0x037e, 0x6b28, - 0x6a2c, 0x1078, 0x1c59, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, 0xac68, - 0x6034, 0xd09c, 0x00c0, 0x18ca, 0x6808, 0x2008, 0xa31a, 0x680c, + 0x1078, 0x5c21, 0x1078, 0x199e, 0x0040, 0x1833, 0x7908, 0xd1ec, + 0x00c0, 0x1876, 0x2009, 0x0009, 0x0078, 0x1878, 0x2009, 0x0019, + 0x7902, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x8001, + 0x7002, 0xd194, 0x0040, 0x1891, 0x7804, 0xd0fc, 0x00c0, 0x178d, + 0x8aff, 0x0040, 0x1910, 0x2009, 0x0001, 0x1078, 0x16f3, 0x0078, + 0x1910, 0xa184, 0x0880, 0x00c0, 0x189e, 0x8aff, 0x0040, 0x1910, + 0x2009, 0x0001, 0x1078, 0x16f3, 0x0078, 0x1910, 0x7803, 0x0004, + 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x18d2, 0x027e, 0x037e, 0x6b28, + 0x6a2c, 0x1078, 0x1c53, 0x0d7e, 0x0f7e, 0x2d78, 0x2804, 0xac68, + 0x6034, 0xd09c, 0x00c0, 0x18c2, 0x6808, 0x2008, 0xa31a, 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101, 0x7816, - 0x0078, 0x18d6, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, 0x7810, + 0x0078, 0x18ce, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213, 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, 0x7816, 0x0f7f, 0x0d7f, - 0x0078, 0x17cf, 0x057e, 0x7d0c, 0x1078, 0x7592, 0x057f, 0x1078, - 0x191c, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, - 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1918, 0x7803, - 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0040, 0x1902, 0x6808, - 0x8001, 0x680a, 0x00c0, 0x1902, 0x7004, 0x2060, 0x2009, 0x0048, - 0x1078, 0x5c29, 0x1078, 0x16b5, 0x0078, 0x1918, 0x7803, 0x0004, - 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0040, 0x1902, - 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x16cc, - 0x017f, 0x007f, 0x127f, 0x007c, 0x1078, 0x192d, 0x20e1, 0x9028, + 0x0078, 0x17c7, 0x057e, 0x7d0c, 0x1078, 0x7587, 0x057f, 0x1078, + 0x1914, 0x682b, 0xffff, 0x682f, 0xffff, 0x697c, 0x6912, 0x6980, + 0x6916, 0x7803, 0x0009, 0x7003, 0x0003, 0x0078, 0x1910, 0x7803, + 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0040, 0x18fa, 0x6808, + 0x8001, 0x680a, 0x00c0, 0x18fa, 0x7004, 0x2060, 0x2009, 0x0048, + 0x1078, 0x5c21, 0x1078, 0x16ad, 0x0078, 0x1910, 0x7803, 0x0004, + 0x7003, 0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0040, 0x18fa, + 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x16c4, + 0x017f, 0x007f, 0x127f, 0x007c, 0x1078, 0x1925, 0x20e1, 0x9028, 0x700f, 0x7870, 0x7013, 0x7870, 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x2001, 0x0138, 0x2202, 0x007c, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, - 0x00c0, 0x194a, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, - 0x194a, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, 0x194a, 0x8421, - 0x00c0, 0x1934, 0x007c, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, - 0xa005, 0x00c0, 0x1957, 0x8109, 0x00c0, 0x194f, 0x007c, 0x007c, - 0x1078, 0x194b, 0x0040, 0x1980, 0x7908, 0xd1ec, 0x00c0, 0x1970, - 0x1078, 0x19a6, 0x0040, 0x1970, 0x7803, 0x0009, 0x7904, 0xd1fc, - 0x0040, 0x1966, 0x7803, 0x0006, 0x1078, 0x194b, 0x0040, 0x1980, - 0x780c, 0xd0a4, 0x00c0, 0x1980, 0x7007, 0x0000, 0x1078, 0x19a6, - 0x0040, 0x1982, 0x7803, 0x0019, 0x7003, 0x0003, 0x0078, 0x1982, - 0x1078, 0x191c, 0x007c, 0x3c00, 0x007e, 0x0e7e, 0x2071, 0x0200, - 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x192d, 0x20e1, 0x7000, + 0x00c0, 0x1942, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, + 0x1942, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, 0x1942, 0x8421, + 0x00c0, 0x192c, 0x007c, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, + 0xa005, 0x00c0, 0x194f, 0x8109, 0x00c0, 0x1947, 0x007c, 0x007c, + 0x1078, 0x1943, 0x0040, 0x1978, 0x7908, 0xd1ec, 0x00c0, 0x1968, + 0x1078, 0x199e, 0x0040, 0x1968, 0x7803, 0x0009, 0x7904, 0xd1fc, + 0x0040, 0x195e, 0x7803, 0x0006, 0x1078, 0x1943, 0x0040, 0x1978, + 0x780c, 0xd0a4, 0x00c0, 0x1978, 0x7007, 0x0000, 0x1078, 0x199e, + 0x0040, 0x197a, 0x7803, 0x0019, 0x7003, 0x0003, 0x0078, 0x197a, + 0x1078, 0x1914, 0x007c, 0x3c00, 0x007e, 0x0e7e, 0x2071, 0x0200, + 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1925, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x0e7f, 0x007f, 0x20e0, 0x007c, 0x3c00, 0x007e, - 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x19b3, 0xa085, - 0x0001, 0x0078, 0x19c5, 0x2001, 0x020a, 0x81ff, 0x0040, 0x19be, + 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x19ab, 0xa085, + 0x0001, 0x0078, 0x19bd, 0x2001, 0x020a, 0x81ff, 0x0040, 0x19b6, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x007f, 0x20e0, 0x007c, 0x0e7e, 0x2071, 0x788b, 0x7003, 0x0000, 0x0e7f, 0x007c, 0x0d7e, - 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1a4a, 0x6934, - 0xa184, 0x0007, 0x0079, 0x19dc, 0x19e4, 0x1a35, 0x19e4, 0x19e4, - 0x19e4, 0x1a1a, 0x19f7, 0x19e6, 0x1078, 0x12d5, 0x684c, 0xd0b4, - 0x0040, 0x1b4c, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, - 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1a3d, 0x6834, - 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x19e4, 0x684c, 0xd0b4, - 0x0040, 0x1b4c, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, + 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1a42, 0x6934, + 0xa184, 0x0007, 0x0079, 0x19d4, 0x19dc, 0x1a2d, 0x19dc, 0x19dc, + 0x19dc, 0x1a12, 0x19ef, 0x19de, 0x1078, 0x12cd, 0x684c, 0xd0b4, + 0x0040, 0x1b46, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, + 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1a35, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x19dc, 0x684c, 0xd0b4, + 0x0040, 0x1b46, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, - 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6958, - 0x0078, 0x1a46, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, 0x1a4a, - 0x684c, 0xd0b4, 0x0040, 0x1b4c, 0x6804, 0x681a, 0xa080, 0x000d, - 0x2004, 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6958, - 0xa006, 0x682e, 0x682a, 0x0078, 0x1a46, 0x684c, 0xd0b4, 0x0040, - 0x1789, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, - 0xa084, 0x000f, 0xa080, 0x1c84, 0x2004, 0x6832, 0x6926, 0x684c, + 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6958, + 0x0078, 0x1a3e, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0, 0x1a42, + 0x684c, 0xd0b4, 0x0040, 0x1b46, 0x6804, 0x681a, 0xa080, 0x000d, + 0x2004, 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6958, + 0xa006, 0x682e, 0x682a, 0x0078, 0x1a3e, 0x684c, 0xd0b4, 0x0040, + 0x1781, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, + 0xa084, 0x000f, 0xa080, 0x1c7e, 0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, 0x0f7e, 0x2079, 0x0020, 0x7804, - 0xd0fc, 0x10c0, 0x1b50, 0x0e7e, 0x0d7e, 0x2071, 0x788b, 0x7000, - 0xa005, 0x00c0, 0x1ac6, 0x0c7e, 0x7206, 0xa280, 0x0004, 0x205c, - 0x7004, 0x2068, 0x6818, 0x0d7e, 0x2068, 0x686c, 0x7812, 0x6890, - 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, - 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, 0x6824, 0x2050, 0x6818, - 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0xa184, - 0x0007, 0x0040, 0x1a88, 0x017e, 0x2009, 0x0008, 0xa102, 0x017f, - 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, 0x0000, 0x781e, - 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, - 0x00c0, 0x1a9f, 0x6928, 0x6810, 0xa106, 0x0040, 0x1aac, 0x037e, - 0x047e, 0x6b14, 0x6c10, 0x1078, 0x1ca4, 0x047f, 0x037f, 0x0040, - 0x1aac, 0x0c7f, 0x0078, 0x1ac6, 0x8aff, 0x00c0, 0x1ab4, 0x0c7f, - 0xa085, 0x0001, 0x0078, 0x1ac6, 0x127e, 0x2091, 0x8000, 0x2079, - 0x0020, 0x2009, 0x0001, 0x1078, 0x1aca, 0x0040, 0x1ac3, 0x2009, - 0x0001, 0x1078, 0x1aca, 0x127f, 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, - 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, 0x037e, 0x027e, - 0x8aff, 0x0040, 0x1b45, 0x700c, 0x7214, 0xa202, 0x7010, 0x7218, - 0xa203, 0x0048, 0x1b44, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, - 0x1af7, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1ae7, 0x1b26, - 0x1b07, 0x1b07, 0x1b26, 0x1b26, 0x1b1e, 0x1b26, 0x1b07, 0x1b26, - 0x1b0d, 0x1b0d, 0x1b26, 0x1b26, 0x1b26, 0x1b15, 0x1b0d, 0xc0fc, - 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1b2a, - 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x1b29, 0x6b08, - 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1b29, 0x6b10, 0x6a14, 0x6d00, - 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1b29, 0x0d7f, 0x0d7e, 0x6834, - 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1b26, 0x0d7f, 0x1078, - 0x1c40, 0x00c0, 0x1ad0, 0xa00e, 0x0078, 0x1b45, 0x0d7f, 0x1078, - 0x12d5, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, - 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, - 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, - 0x1078, 0x1c40, 0x0078, 0x1b45, 0xa006, 0x027f, 0x037f, 0x047f, - 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x12d5, 0x1078, 0x12d5, - 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, 0x0e7e, 0x0d7e, - 0x0c7e, 0x2079, 0x0020, 0x2071, 0x788b, 0x2b68, 0x6818, 0x2060, - 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, 0x1b4e, 0x7000, - 0x0079, 0x1b6a, 0x1c11, 0x1b6e, 0x1bde, 0x1c0f, 0x8001, 0x7002, - 0xd19c, 0x00c0, 0x1b82, 0x8aff, 0x0040, 0x1ba1, 0x2009, 0x0001, - 0x1078, 0x1aca, 0x0040, 0x1c11, 0x2009, 0x0001, 0x1078, 0x1aca, - 0x0078, 0x1c11, 0x7803, 0x0004, 0xd194, 0x0040, 0x1b92, 0x6850, - 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1b97, 0x684c, 0xc0f5, 0x684e, - 0x0078, 0x1b97, 0x1078, 0x1c59, 0x6850, 0xc0fd, 0x6852, 0x2a00, - 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0078, - 0x1c11, 0x711c, 0x81ff, 0x0040, 0x1bb7, 0x7918, 0x7922, 0x7827, - 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, 0x700c, 0xa100, - 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, 0x1c11, 0x0f7e, - 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, - 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x7820, 0xd0bc, 0x00c0, - 0x1bc5, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, 0x007f, 0xa102, - 0x78c6, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, - 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1c11, 0x8001, 0x7002, - 0xd194, 0x0040, 0x1bf3, 0x7804, 0xd0fc, 0x00c0, 0x1b60, 0xd19c, - 0x00c0, 0x1c0d, 0x8aff, 0x0040, 0x1c11, 0x2009, 0x0001, 0x1078, - 0x1aca, 0x0078, 0x1c11, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, - 0x1c59, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1c06, - 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1c0a, 0x6810, 0xa31a, - 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1b92, 0x0078, 0x1b92, 0x1078, - 0x12d5, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, - 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x788b, 0x7000, 0xa086, 0x0000, - 0x0040, 0x1c3d, 0x2079, 0x0020, 0x20e1, 0x9040, 0x7804, 0xd0fc, - 0x0040, 0x1c24, 0x1078, 0x1b50, 0x7000, 0xa086, 0x0000, 0x00c0, - 0x1c24, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, 0x1c33, 0x20e1, - 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, - 0x8840, 0x2804, 0xa005, 0x00c0, 0x1c54, 0x6004, 0xa005, 0x0040, - 0x1c56, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x1c84, - 0x2044, 0x88ff, 0x1040, 0x12d5, 0x8a51, 0x007c, 0x2051, 0x0000, - 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x1c73, 0x2c00, - 0xad06, 0x0040, 0x1c68, 0x6000, 0xa005, 0x00c0, 0x1c68, 0x2d00, - 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x1c94, 0x2044, - 0x88ff, 0x1040, 0x12d5, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, - 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, - 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x1c79, 0x1c75, 0x0000, - 0x0000, 0x1c83, 0x0000, 0x1c79, 0x0000, 0x1c80, 0x1c7d, 0x0000, - 0x0000, 0x0000, 0x1c83, 0x1c80, 0x0000, 0x1c7b, 0x1c7b, 0x0000, - 0x0000, 0x1c83, 0x0000, 0x1c7b, 0x0000, 0x1c81, 0x1c81, 0x0000, - 0x0000, 0x0000, 0x1c83, 0x1c81, 0x0a7e, 0x097e, 0x087e, 0x6858, - 0xa055, 0x0040, 0x1d45, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0, - 0x1c84, 0xa986, 0x0007, 0x0040, 0x1cbd, 0xa986, 0x000e, 0x0040, - 0x1cbd, 0xa986, 0x000f, 0x00c0, 0x1cc1, 0x605c, 0xa422, 0x6060, - 0xa31a, 0x2804, 0xa045, 0x00c0, 0x1ccf, 0x0050, 0x1cc9, 0x0078, - 0x1d45, 0x6004, 0xa065, 0x0040, 0x1d45, 0x0078, 0x1cac, 0x2804, - 0xa005, 0x0040, 0x1ced, 0xac68, 0xd99c, 0x00c0, 0x1cdd, 0x6808, - 0xa422, 0x680c, 0xa31b, 0x0078, 0x1ce1, 0x6810, 0xa422, 0x6814, - 0xa31b, 0x0048, 0x1d0c, 0x2300, 0xa405, 0x0040, 0x1cf3, 0x8a51, - 0x0040, 0x1d45, 0x8840, 0x0078, 0x1ccf, 0x6004, 0xa065, 0x0040, - 0x1d45, 0x0078, 0x1cac, 0x8a51, 0x0040, 0x1d45, 0x8840, 0x2804, - 0xa005, 0x00c0, 0x1d06, 0x6004, 0xa065, 0x0040, 0x1d45, 0x6034, - 0xa0cc, 0x000f, 0xa9c0, 0x1c84, 0x2804, 0x2040, 0x2b68, 0x6850, - 0xc0fc, 0x6852, 0x0078, 0x1d39, 0x8422, 0x8420, 0x831a, 0xa399, - 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, 0x00c0, - 0x1d27, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1048, - 0x12d5, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x1d33, 0x6910, - 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x12d5, 0x6800, - 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd, - 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x007f, - 0x007f, 0x007f, 0xa006, 0x0078, 0x1d4a, 0x087f, 0x097f, 0x0a7f, - 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, 0xa084, 0x0007, - 0x0079, 0x1d52, 0x1d5a, 0x1d5b, 0x1d5e, 0x1d61, 0x1d66, 0x1d69, - 0x1d6e, 0x1d73, 0x007c, 0x1078, 0x1b50, 0x007c, 0x1078, 0x178d, - 0x007c, 0x1078, 0x178d, 0x1078, 0x1b50, 0x007c, 0x1078, 0x145e, - 0x007c, 0x1078, 0x1b50, 0x1078, 0x145e, 0x007c, 0x1078, 0x178d, - 0x1078, 0x145e, 0x007c, 0x1078, 0x178d, 0x1078, 0x1b50, 0x1078, - 0x145e, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, 0x0200, 0x2071, - 0x7b80, 0x2069, 0x7600, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, - 0x1078, 0x2058, 0x781b, 0x0002, 0x20e1, 0x8700, 0x127f, 0x007c, - 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, 0x0079, 0x1d98, - 0x1dbc, 0x1da0, 0x1da4, 0x1da8, 0x1dae, 0x1db2, 0x1db6, 0x1dba, - 0x1078, 0x417d, 0x0078, 0x1dbc, 0x1078, 0x41ac, 0x0078, 0x1dbc, - 0x1078, 0x417d, 0x1078, 0x41ac, 0x0078, 0x1dbc, 0x1078, 0x1dbe, - 0x0078, 0x1dbc, 0x1078, 0x1dbe, 0x0078, 0x1dbc, 0x1078, 0x1dbe, - 0x0078, 0x1dbc, 0x1078, 0x1dbe, 0x127f, 0x007c, 0x007e, 0x017e, - 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, 0x1dc8, 0x1078, 0x12d5, - 0xa184, 0x0030, 0x0040, 0x1dd9, 0x6a00, 0xa286, 0x0003, 0x00c0, - 0x1dd3, 0x1078, 0x12d5, 0x1078, 0x357b, 0x20e1, 0x9010, 0x0078, - 0x1de5, 0xa184, 0x00c0, 0x0040, 0x1ddf, 0x1078, 0x12d5, 0xa184, - 0x0300, 0x0040, 0x1de5, 0x20e1, 0x9020, 0x7932, 0x027f, 0x017f, - 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, 0x7600, 0x7128, - 0x2001, 0x7823, 0x2102, 0x2001, 0x782b, 0x2102, 0xa182, 0x0211, - 0x00c8, 0x1dfe, 0x2009, 0x0008, 0x0078, 0x1e28, 0xa182, 0x0259, - 0x00c8, 0x1e06, 0x2009, 0x0007, 0x0078, 0x1e28, 0xa182, 0x02c1, - 0x00c8, 0x1e0e, 0x2009, 0x0006, 0x0078, 0x1e28, 0xa182, 0x0349, - 0x00c8, 0x1e16, 0x2009, 0x0005, 0x0078, 0x1e28, 0xa182, 0x0421, - 0x00c8, 0x1e1e, 0x2009, 0x0004, 0x0078, 0x1e28, 0xa182, 0x0581, - 0x00c8, 0x1e26, 0x2009, 0x0003, 0x0078, 0x1e28, 0x2009, 0x0002, - 0x2079, 0x0200, 0x7912, 0xa182, 0x0005, 0x00c8, 0x1e32, 0x7916, - 0x0078, 0x1e34, 0x7817, 0x0004, 0x1078, 0x2058, 0x0f7f, 0x0e7f, - 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, 0x0100, 0x2071, - 0x7600, 0x6024, 0x6026, 0x6033, 0x00ef, 0x60e7, 0x0000, 0x60eb, - 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, - 0x0080, 0x602f, 0x0000, 0x6007, 0x0caf, 0x600f, 0x00ff, 0x602b, - 0x002f, 0x127f, 0x007c, 0x2001, 0x762d, 0x2003, 0x0000, 0x2001, - 0x762c, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x007e, - 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, 0x1e73, 0xa184, - 0x0007, 0x0079, 0x1e79, 0xa195, 0x0004, 0xa284, 0x0007, 0x0079, - 0x1e79, 0x1ea5, 0x1e81, 0x1e85, 0x1e89, 0x1e8f, 0x1e93, 0x1e99, - 0x1e9f, 0x1078, 0x46e6, 0x0078, 0x1ea5, 0x1078, 0x47d5, 0x0078, - 0x1ea5, 0x1078, 0x47d5, 0x1078, 0x46e6, 0x0078, 0x1ea5, 0x1078, - 0x1eaa, 0x0078, 0x1ea5, 0x1078, 0x46e6, 0x1078, 0x1eaa, 0x0078, - 0x1ea5, 0x1078, 0x47d5, 0x1078, 0x1eaa, 0x0078, 0x1ea5, 0x1078, - 0x47d5, 0x1078, 0x46e6, 0x1078, 0x1eaa, 0x027f, 0x017f, 0x007f, - 0x127f, 0x007c, 0xd1ac, 0x0040, 0x1f5e, 0x017e, 0x047e, 0x0c7e, - 0x644c, 0x74ba, 0xa48c, 0xff00, 0xa196, 0xff00, 0x0040, 0x1ed9, - 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, 0x1ed9, 0x7130, - 0xd18c, 0x00c0, 0x1ed9, 0x2011, 0x7652, 0x2214, 0xd2ec, 0x0040, - 0x1ecd, 0xc18d, 0x7132, 0x0078, 0x1ed9, 0x6240, 0xa294, 0x0010, - 0x0040, 0x1f1b, 0x6248, 0xa294, 0xff00, 0xa296, 0xff00, 0x00c0, - 0x1f1b, 0x037e, 0x73b8, 0x2011, 0x8013, 0x1078, 0x2d4a, 0x037f, - 0x7130, 0xc185, 0x7132, 0x2011, 0x7652, 0x220c, 0xd1a4, 0x0040, - 0x1f03, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x46b4, - 0x2019, 0x000e, 0x1078, 0x74d9, 0xa484, 0x00ff, 0xa080, 0x232f, - 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, - 0x1078, 0x7541, 0x017f, 0xd1ac, 0x00c0, 0x1f0c, 0x2019, 0x0004, - 0x1078, 0x2299, 0x0078, 0x1f1b, 0x157e, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x1078, 0x3825, 0x00c0, 0x1f17, 0x1078, 0x3621, 0x8108, - 0x00f0, 0x1f11, 0x157f, 0x0c7f, 0x047f, 0x6043, 0x0000, 0x2009, - 0x00f7, 0x1078, 0x35e4, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, - 0x0000, 0x0040, 0x1f33, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, - 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, 0x1078, 0x57c0, - 0x2011, 0x0002, 0x1078, 0x57ca, 0x1078, 0x56d6, 0x1078, 0x45eb, - 0x037e, 0x2019, 0x0000, 0x1078, 0x5768, 0x037f, 0x60e3, 0x0000, - 0x017f, 0x2001, 0x7600, 0x2014, 0xa296, 0x0004, 0x00c0, 0x1f56, - 0xd19c, 0x00c0, 0x1f56, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, - 0x2001, 0x7620, 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, - 0x1fff, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, 0x0001, 0x00c0, - 0x1f82, 0x017e, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, - 0x7803, 0x1000, 0x7803, 0x0000, 0x2079, 0x7836, 0x7807, 0x0000, - 0x7833, 0x0000, 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x017f, 0x0f7f, - 0x0078, 0x1fff, 0x0f7f, 0x017e, 0x6220, 0xd2b4, 0x0040, 0x1fb7, - 0x1078, 0x45eb, 0x1078, 0x5582, 0x6027, 0x0004, 0x0d7e, 0x2069, - 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1f9a, 0x6803, 0x1000, - 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0x7836, 0x6028, 0xa09a, - 0x0002, 0x00c8, 0x1faa, 0x8000, 0x602a, 0x0c7f, 0x1078, 0x5574, - 0x0078, 0x1ffe, 0x2019, 0x783f, 0x2304, 0xa065, 0x0040, 0x1fb4, - 0x2009, 0x0027, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x1ffe, 0xd2bc, - 0x0040, 0x1ffe, 0x1078, 0x45f9, 0x6017, 0x0010, 0x6027, 0x0004, - 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1fcc, + 0xd0fc, 0x10c0, 0x1b4a, 0x0e7e, 0x0d7e, 0x2071, 0x788b, 0x7000, + 0xa005, 0x00c0, 0x1ac0, 0x0c7e, 0x7206, 0xa280, 0x0004, 0x205c, + 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x0d7e, 0x2068, 0x686c, + 0x7812, 0x6890, 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, + 0x2079, 0x0100, 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x6908, 0xa184, 0x0007, 0x0040, 0x1a82, 0x017e, 0x2009, 0x0008, + 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081, + 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, + 0x6814, 0xa106, 0x00c0, 0x1a99, 0x6928, 0x6810, 0xa106, 0x0040, + 0x1aa6, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, 0x1c9e, 0x047f, + 0x037f, 0x0040, 0x1aa6, 0x0c7f, 0x0078, 0x1ac0, 0x8aff, 0x00c0, + 0x1aae, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x1ac0, 0x127e, 0x2091, + 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, 0x1ac4, 0x0040, + 0x1abd, 0x2009, 0x0001, 0x1078, 0x1ac4, 0x127f, 0x0c7f, 0xa006, + 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e, + 0x037e, 0x027e, 0x8aff, 0x0040, 0x1b3f, 0x700c, 0x7214, 0xa202, + 0x7010, 0x7218, 0xa203, 0x0048, 0x1b3e, 0xa03e, 0x2730, 0x6850, + 0xd0fc, 0x00c0, 0x1af1, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, + 0x1ae1, 0x1b20, 0x1b01, 0x1b01, 0x1b20, 0x1b20, 0x1b18, 0x1b20, + 0x1b01, 0x1b20, 0x1b07, 0x1b07, 0x1b20, 0x1b20, 0x1b20, 0x1b0f, + 0x1b07, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, + 0x0040, 0x1b24, 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, + 0x1b23, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1b23, 0x6b10, + 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1b23, 0x0d7f, + 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1b20, + 0x0d7f, 0x1078, 0x1c3a, 0x00c0, 0x1aca, 0xa00e, 0x0078, 0x1b3f, + 0x0d7f, 0x1078, 0x12cd, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, + 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, + 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, + 0xa201, 0x7012, 0x1078, 0x1c3a, 0x0078, 0x1b3f, 0xa006, 0x027f, + 0x037f, 0x047f, 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x12cd, + 0x1078, 0x12cd, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e, + 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0x788b, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, + 0x1b48, 0x7000, 0x0079, 0x1b64, 0x1c0b, 0x1b68, 0x1bd8, 0x1c09, + 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1b7c, 0x8aff, 0x0040, 0x1b9b, + 0x2009, 0x0001, 0x1078, 0x1ac4, 0x0040, 0x1c0b, 0x2009, 0x0001, + 0x1078, 0x1ac4, 0x0078, 0x1c0b, 0x7803, 0x0004, 0xd194, 0x0040, + 0x1b8c, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1b91, 0x684c, + 0xc0f5, 0x684e, 0x0078, 0x1b91, 0x1078, 0x1c53, 0x6850, 0xc0fd, + 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, + 0x0000, 0x0078, 0x1c0b, 0x711c, 0x81ff, 0x0040, 0x1bb1, 0x7918, + 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002, + 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078, + 0x1c0b, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079, + 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x7820, + 0xd0bc, 0x00c0, 0x1bbf, 0x79c8, 0x007f, 0xa102, 0x78ca, 0x79c4, + 0x007f, 0xa102, 0x78c6, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, + 0x027f, 0x0f7f, 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1c0b, + 0x8001, 0x7002, 0xd194, 0x0040, 0x1bed, 0x7804, 0xd0fc, 0x00c0, + 0x1b5a, 0xd19c, 0x00c0, 0x1c07, 0x8aff, 0x0040, 0x1c0b, 0x2009, + 0x0001, 0x1078, 0x1ac4, 0x0078, 0x1c0b, 0x027e, 0x037e, 0x6b28, + 0x6a2c, 0x1078, 0x1c53, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, + 0x00c0, 0x1c00, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1c04, + 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1b8c, 0x0078, + 0x1b8c, 0x1078, 0x12cd, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, + 0x007f, 0x127f, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x788b, 0x7000, + 0xa086, 0x0000, 0x0040, 0x1c37, 0x2079, 0x0020, 0x20e1, 0x9040, + 0x7804, 0xd0fc, 0x0040, 0x1c1e, 0x1078, 0x1b4a, 0x7000, 0xa086, + 0x0000, 0x00c0, 0x1c1e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0, + 0x1c2d, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f, + 0x0f7f, 0x007c, 0x8840, 0x2804, 0xa005, 0x00c0, 0x1c4e, 0x6004, + 0xa005, 0x0040, 0x1c50, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, + 0xa080, 0x1c7e, 0x2044, 0x88ff, 0x1040, 0x12cd, 0x8a51, 0x007c, + 0x2051, 0x0000, 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, + 0x1c6d, 0x2c00, 0xad06, 0x0040, 0x1c62, 0x6000, 0xa005, 0x00c0, + 0x1c62, 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, + 0x1c8e, 0x2044, 0x88ff, 0x1040, 0x12cd, 0x007c, 0x0000, 0x0011, + 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, + 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x1c73, + 0x1c6f, 0x0000, 0x0000, 0x1c7d, 0x0000, 0x1c73, 0x0000, 0x1c7a, + 0x1c77, 0x0000, 0x0000, 0x0000, 0x1c7d, 0x1c7a, 0x0000, 0x1c75, + 0x1c75, 0x0000, 0x0000, 0x1c7d, 0x0000, 0x1c75, 0x0000, 0x1c7b, + 0x1c7b, 0x0000, 0x0000, 0x0000, 0x1c7d, 0x1c7b, 0x0a7e, 0x097e, + 0x087e, 0x6858, 0xa055, 0x0040, 0x1d3f, 0x2d60, 0x6034, 0xa0cc, + 0x000f, 0xa9c0, 0x1c7e, 0xa986, 0x0007, 0x0040, 0x1cb7, 0xa986, + 0x000e, 0x0040, 0x1cb7, 0xa986, 0x000f, 0x00c0, 0x1cbb, 0x605c, + 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x1cc9, 0x0050, + 0x1cc3, 0x0078, 0x1d3f, 0x6004, 0xa065, 0x0040, 0x1d3f, 0x0078, + 0x1ca6, 0x2804, 0xa005, 0x0040, 0x1ce7, 0xac68, 0xd99c, 0x00c0, + 0x1cd7, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x1cdb, 0x6810, + 0xa422, 0x6814, 0xa31b, 0x0048, 0x1d06, 0x2300, 0xa405, 0x0040, + 0x1ced, 0x8a51, 0x0040, 0x1d3f, 0x8840, 0x0078, 0x1cc9, 0x6004, + 0xa065, 0x0040, 0x1d3f, 0x0078, 0x1ca6, 0x8a51, 0x0040, 0x1d3f, + 0x8840, 0x2804, 0xa005, 0x00c0, 0x1d00, 0x6004, 0xa065, 0x0040, + 0x1d3f, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x1c7e, 0x2804, 0x2040, + 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0078, 0x1d33, 0x8422, 0x8420, + 0x831a, 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, + 0xd99c, 0x00c0, 0x1d21, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, + 0xa11b, 0x1048, 0x12cd, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, + 0x1d2d, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, + 0x12cd, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, + 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, + 0x6826, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x1d44, 0x087f, + 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, + 0xa084, 0x0007, 0x0079, 0x1d4c, 0x1d54, 0x1d55, 0x1d58, 0x1d5b, + 0x1d60, 0x1d63, 0x1d68, 0x1d6d, 0x007c, 0x1078, 0x1b4a, 0x007c, + 0x1078, 0x1785, 0x007c, 0x1078, 0x1785, 0x1078, 0x1b4a, 0x007c, + 0x1078, 0x1456, 0x007c, 0x1078, 0x1b4a, 0x1078, 0x1456, 0x007c, + 0x1078, 0x1785, 0x1078, 0x1456, 0x007c, 0x1078, 0x1785, 0x1078, + 0x1b4a, 0x1078, 0x1456, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, + 0x0200, 0x2071, 0x7b80, 0x2069, 0x7600, 0x2009, 0x0004, 0x7912, + 0x7817, 0x0004, 0x1078, 0x2052, 0x781b, 0x0002, 0x20e1, 0x8700, + 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, + 0x0079, 0x1d92, 0x1db6, 0x1d9a, 0x1d9e, 0x1da2, 0x1da8, 0x1dac, + 0x1db0, 0x1db4, 0x1078, 0x4175, 0x0078, 0x1db6, 0x1078, 0x41a4, + 0x0078, 0x1db6, 0x1078, 0x4175, 0x1078, 0x41a4, 0x0078, 0x1db6, + 0x1078, 0x1db8, 0x0078, 0x1db6, 0x1078, 0x1db8, 0x0078, 0x1db6, + 0x1078, 0x1db8, 0x0078, 0x1db6, 0x1078, 0x1db8, 0x127f, 0x007c, + 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, 0x1dc2, + 0x1078, 0x12cd, 0xa184, 0x0030, 0x0040, 0x1dd3, 0x6a00, 0xa286, + 0x0003, 0x00c0, 0x1dcd, 0x1078, 0x12cd, 0x1078, 0x3573, 0x20e1, + 0x9010, 0x0078, 0x1ddf, 0xa184, 0x00c0, 0x0040, 0x1dd9, 0x1078, + 0x12cd, 0xa184, 0x0300, 0x0040, 0x1ddf, 0x20e1, 0x9020, 0x7932, + 0x027f, 0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, + 0x7600, 0x7128, 0x2001, 0x7823, 0x2102, 0x2001, 0x782b, 0x2102, + 0xa182, 0x0211, 0x00c8, 0x1df8, 0x2009, 0x0008, 0x0078, 0x1e22, + 0xa182, 0x0259, 0x00c8, 0x1e00, 0x2009, 0x0007, 0x0078, 0x1e22, + 0xa182, 0x02c1, 0x00c8, 0x1e08, 0x2009, 0x0006, 0x0078, 0x1e22, + 0xa182, 0x0349, 0x00c8, 0x1e10, 0x2009, 0x0005, 0x0078, 0x1e22, + 0xa182, 0x0421, 0x00c8, 0x1e18, 0x2009, 0x0004, 0x0078, 0x1e22, + 0xa182, 0x0581, 0x00c8, 0x1e20, 0x2009, 0x0003, 0x0078, 0x1e22, + 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0xa182, 0x0005, 0x00c8, + 0x1e2c, 0x7916, 0x0078, 0x1e2e, 0x7817, 0x0004, 0x1078, 0x2052, + 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, + 0x0100, 0x2071, 0x7600, 0x6024, 0x6026, 0x6033, 0x00ef, 0x60e7, + 0x0000, 0x60eb, 0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, + 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x0caf, 0x600f, + 0x00ff, 0x602b, 0x002f, 0x127f, 0x007c, 0x2001, 0x762d, 0x2003, + 0x0000, 0x2001, 0x762c, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, + 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, + 0x1e6d, 0xa184, 0x0007, 0x0079, 0x1e73, 0xa195, 0x0004, 0xa284, + 0x0007, 0x0079, 0x1e73, 0x1e9f, 0x1e7b, 0x1e7f, 0x1e83, 0x1e89, + 0x1e8d, 0x1e93, 0x1e99, 0x1078, 0x46de, 0x0078, 0x1e9f, 0x1078, + 0x47cd, 0x0078, 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x46de, 0x0078, + 0x1e9f, 0x1078, 0x1ea4, 0x0078, 0x1e9f, 0x1078, 0x46de, 0x1078, + 0x1ea4, 0x0078, 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x1ea4, 0x0078, + 0x1e9f, 0x1078, 0x47cd, 0x1078, 0x46de, 0x1078, 0x1ea4, 0x027f, + 0x017f, 0x007f, 0x127f, 0x007c, 0xd1ac, 0x0040, 0x1f58, 0x017e, + 0x047e, 0x0c7e, 0x644c, 0x74ba, 0xa48c, 0xff00, 0xa196, 0xff00, + 0x0040, 0x1ed3, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, + 0x1ed3, 0x7130, 0xd18c, 0x00c0, 0x1ed3, 0x2011, 0x7652, 0x2214, + 0xd2ec, 0x0040, 0x1ec7, 0xc18d, 0x7132, 0x0078, 0x1ed3, 0x6240, + 0xa294, 0x0010, 0x0040, 0x1f15, 0x6248, 0xa294, 0xff00, 0xa296, + 0xff00, 0x00c0, 0x1f15, 0x037e, 0x73b8, 0x2011, 0x8013, 0x1078, + 0x2d3b, 0x037f, 0x7130, 0xc185, 0x7132, 0x2011, 0x7652, 0x220c, + 0xd1a4, 0x0040, 0x1efd, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100, + 0x1078, 0x46ac, 0x2019, 0x000e, 0x1078, 0x74ce, 0xa484, 0x00ff, + 0xa080, 0x2329, 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, + 0x2009, 0x000e, 0x1078, 0x7536, 0x017f, 0xd1ac, 0x00c0, 0x1f06, + 0x2019, 0x0004, 0x1078, 0x2293, 0x0078, 0x1f15, 0x157e, 0x20a9, + 0x007f, 0x2009, 0x0000, 0x1078, 0x381d, 0x00c0, 0x1f11, 0x1078, + 0x3619, 0x8108, 0x00f0, 0x1f0b, 0x157f, 0x0c7f, 0x047f, 0x6043, + 0x0000, 0x2009, 0x00f7, 0x1078, 0x35dc, 0x0f7e, 0x2079, 0x7849, + 0x783c, 0xa086, 0x0000, 0x0040, 0x1f2d, 0x6027, 0x0004, 0x783f, + 0x0000, 0x2079, 0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, + 0x1078, 0x57b8, 0x2011, 0x0002, 0x1078, 0x57c2, 0x1078, 0x56ce, + 0x1078, 0x45e3, 0x037e, 0x2019, 0x0000, 0x1078, 0x5760, 0x037f, + 0x60e3, 0x0000, 0x017f, 0x2001, 0x7600, 0x2014, 0xa296, 0x0004, + 0x00c0, 0x1f50, 0xd19c, 0x00c0, 0x1f50, 0x6228, 0xc29d, 0x622a, + 0x2003, 0x0001, 0x2001, 0x7620, 0x2003, 0x0000, 0x6027, 0x0020, + 0xd194, 0x0040, 0x1ff9, 0x0f7e, 0x2079, 0x7849, 0x783c, 0xa086, + 0x0001, 0x00c0, 0x1f7c, 0x017e, 0x6027, 0x0004, 0x783f, 0x0000, + 0x2079, 0x0140, 0x7803, 0x1000, 0x7803, 0x0000, 0x2079, 0x7836, + 0x7807, 0x0000, 0x7833, 0x0000, 0x1078, 0x4c72, 0x1078, 0x4d32, + 0x017f, 0x0f7f, 0x0078, 0x1ff9, 0x0f7f, 0x017e, 0x6220, 0xd2b4, + 0x0040, 0x1fb1, 0x1078, 0x45e3, 0x1078, 0x557a, 0x6027, 0x0004, + 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x1f94, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0x7836, - 0x6044, 0xa09a, 0x0002, 0x00c8, 0x1fed, 0x8000, 0x6046, 0x603c, - 0x0c7f, 0xa005, 0x0040, 0x1ffe, 0x1078, 0x45f0, 0xa080, 0x0007, - 0x2004, 0xa086, 0x0006, 0x00c0, 0x1fe9, 0x6017, 0x0012, 0x0078, - 0x1ffe, 0x6017, 0x0016, 0x0078, 0x1ffe, 0x037e, 0x2019, 0x0001, - 0x1078, 0x5768, 0x037f, 0x2019, 0x7845, 0x2304, 0xa065, 0x0040, - 0x1ffd, 0x2009, 0x004f, 0x1078, 0x5c29, 0x0c7f, 0x017f, 0xd19c, - 0x0040, 0x2027, 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, - 0x1078, 0x57c0, 0x2011, 0x0002, 0x1078, 0x57ca, 0x1078, 0x56d6, - 0x1078, 0x45eb, 0x037e, 0x2019, 0x0000, 0x1078, 0x5768, 0x037f, - 0x60e3, 0x0000, 0x1078, 0x75b0, 0x1078, 0x75ce, 0x2001, 0x7600, - 0x2003, 0x0004, 0x6027, 0x0008, 0x1078, 0x11c6, 0x017f, 0xa18c, - 0xffd0, 0x6126, 0x007c, 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, - 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x71b0, 0x70b2, 0xa116, - 0x0040, 0x2051, 0x81ff, 0x0040, 0x2043, 0x2011, 0x8011, 0x1078, - 0x2d4a, 0x0078, 0x2051, 0x2011, 0x8012, 0x1078, 0x2d4a, 0x037e, - 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, 0x1078, 0x2299, 0x0c7f, - 0x037f, 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, - 0x0c7e, 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x2073, - 0x2204, 0x60f2, 0xa192, 0x0005, 0x00c8, 0x206a, 0xa190, 0x207c, - 0x0078, 0x206c, 0x2011, 0x2080, 0x2204, 0x60ee, 0x027f, 0x007f, - 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, - 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, - 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0x2130, 0xa094, - 0xff00, 0x00c0, 0x208e, 0x81ff, 0x0040, 0x2092, 0x1078, 0x4330, - 0x0078, 0x2099, 0xa080, 0x232f, 0x200c, 0xa18c, 0xff00, 0x810f, - 0xa006, 0x007c, 0xa080, 0x232f, 0x200c, 0xa18c, 0x00ff, 0x007c, - 0x20c0, 0x20c4, 0x20c8, 0x20ce, 0x20d4, 0x20da, 0x20e0, 0x20e8, - 0x20f0, 0x20f6, 0x20fc, 0x2104, 0x210c, 0x2114, 0x211c, 0x2126, - 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, - 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, 0x2130, - 0x107e, 0x007e, 0x0078, 0x2149, 0x107e, 0x007e, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1e64, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x0078, 0x2149, - 0x107e, 0x007e, 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1d4b, - 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, 0x1078, 0x1e64, - 0x1078, 0x1d4b, 0x1078, 0x1d90, 0x0078, 0x2149, 0x107e, 0x007e, - 0x1078, 0x1e64, 0x1078, 0x1d4b, 0x1078, 0x1d90, 0x0078, 0x2149, - 0x0005, 0x0078, 0x2130, 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, - 0x2139, 0x2149, 0x20c6, 0x20ca, 0x20d0, 0x20d6, 0x20dc, 0x20e2, - 0x20ea, 0x20f2, 0x20f8, 0x20fe, 0x2106, 0x210e, 0x2116, 0x211e, - 0x2128, 0x0008, 0x2133, 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, - 0x0c7e, 0x027e, 0x2041, 0x007e, 0x70bc, 0xd09c, 0x0040, 0x215a, - 0x2041, 0x007f, 0x2001, 0x010c, 0x203c, 0x727c, 0x82ff, 0x0040, - 0x21a5, 0x037e, 0x738c, 0xa38e, 0xffff, 0x00c0, 0x2169, 0x2019, - 0x0001, 0x8314, 0xa2e0, 0x7cc0, 0x2c04, 0xa38c, 0x0001, 0x0040, - 0x2176, 0xa084, 0xff00, 0x8007, 0x0078, 0x2178, 0xa084, 0x00ff, - 0xa70e, 0x0040, 0x219a, 0xa08e, 0x00ff, 0x0040, 0x21a0, 0x2009, - 0x0000, 0x1078, 0x2085, 0x1078, 0x37ee, 0x00c0, 0x219d, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2194, 0x1078, 0x21f7, - 0x0040, 0x219d, 0x0078, 0x219a, 0x1078, 0x22fb, 0x1078, 0x221e, - 0x0040, 0x219d, 0x8318, 0x0078, 0x2169, 0x738e, 0x0078, 0x21a2, - 0x708f, 0xffff, 0x037f, 0x0078, 0x21f4, 0xa780, 0x232f, 0x203c, - 0xa7bc, 0xff00, 0x873f, 0x708c, 0xa096, 0xffff, 0x0040, 0x21b7, - 0xa812, 0x00c8, 0x21c7, 0x708f, 0xffff, 0x0078, 0x21f1, 0x2009, - 0x0000, 0x70bc, 0xd09c, 0x0040, 0x21c2, 0xd094, 0x0040, 0x21c2, - 0x2009, 0x007e, 0x2100, 0xa802, 0x20a8, 0x0078, 0x21cb, 0x2008, - 0x2810, 0xa202, 0x20a8, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, - 0x21e8, 0x1078, 0x37ee, 0x00c0, 0x21f1, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x00c0, 0x21e2, 0x1078, 0x21f7, 0x0040, 0x21f1, - 0x0078, 0x21e8, 0x1078, 0x22fb, 0x1078, 0x221e, 0x0040, 0x21f1, - 0x017f, 0x8108, 0x157f, 0x00f0, 0x21cb, 0x708f, 0xffff, 0x0078, - 0x21f4, 0x017f, 0x157f, 0x718e, 0x027f, 0x0c7f, 0x007c, 0x017e, - 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2219, - 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x2001, 0x0000, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, - 0x8000, 0x708a, 0x127f, 0x2009, 0x0004, 0x1078, 0x5c29, 0xa085, - 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, - 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2240, 0x2d00, - 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, - 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, - 0x0080, 0x1078, 0x37ee, 0x00c0, 0x2253, 0x1078, 0x2256, 0x0040, - 0x2253, 0x70c3, 0xffff, 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, - 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b9c, 0x0040, 0x2278, 0x2d00, - 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x70c4, 0x8000, - 0x70c6, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x2009, - 0x007f, 0x1078, 0x37ee, 0x00c0, 0x2296, 0x2c68, 0x1078, 0x5b9c, - 0x0040, 0x2296, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, - 0x2009, 0x0022, 0x1078, 0x5c29, 0xa085, 0x0001, 0x0d7f, 0x0c7f, - 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, 0x4969, - 0x1078, 0x4919, 0x1078, 0x6103, 0x20a9, 0x007f, 0x2009, 0x0000, - 0x017e, 0x1078, 0x3825, 0x00c0, 0x22b1, 0x1078, 0x39a6, 0x1078, - 0x3621, 0x017f, 0x8108, 0x00f0, 0x22a8, 0x027f, 0x037f, 0x067f, - 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, - 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x017f, 0x2e60, 0x1078, - 0x39a6, 0x6210, 0x6314, 0x1078, 0x3621, 0x6212, 0x6316, 0x017f, - 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x6018, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x22f1, 0x2071, 0x7600, - 0x7088, 0xa005, 0x0040, 0x22ee, 0x8001, 0x708a, 0x007f, 0x0e7f, - 0x007c, 0x2071, 0x7600, 0x70c4, 0xa005, 0x0040, 0x22ee, 0x8001, - 0x70c6, 0x0078, 0x22ee, 0x6000, 0xc08c, 0x6002, 0x007c, 0x0e7e, - 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x81ff, 0x00c0, 0x230c, - 0x20a9, 0x0001, 0x0078, 0x2310, 0x20a9, 0x007f, 0x2011, 0x0000, - 0x027e, 0xa2e0, 0x7720, 0x2c64, 0x8cff, 0x0040, 0x2322, 0x2019, - 0x0029, 0x1078, 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, - 0x1078, 0x39a6, 0x027f, 0x8210, 0x00f0, 0x2310, 0x027e, 0x027f, - 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x7eef, - 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, - 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, - 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, - 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, - 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, - 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, - 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, - 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, - 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, - 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, - 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, - 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, - 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, - 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, - 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, - 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, - 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, - 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, - 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, - 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, - 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, - 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, - 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, - 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, - 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, - 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, + 0x6028, 0xa09a, 0x0002, 0x00c8, 0x1fa4, 0x8000, 0x602a, 0x0c7f, + 0x1078, 0x556c, 0x0078, 0x1ff8, 0x2019, 0x783f, 0x2304, 0xa065, + 0x0040, 0x1fae, 0x2009, 0x0027, 0x1078, 0x5c21, 0x0c7f, 0x0078, + 0x1ff8, 0xd2bc, 0x0040, 0x1ff8, 0x1078, 0x45f1, 0x6017, 0x0010, + 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, + 0x0040, 0x1fc6, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, + 0x2061, 0x7836, 0x6044, 0xa09a, 0x0002, 0x00c8, 0x1fe7, 0x8000, + 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040, 0x1ff8, 0x1078, 0x45e8, + 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, 0x1fe3, 0x6017, + 0x0012, 0x0078, 0x1ff8, 0x6017, 0x0016, 0x0078, 0x1ff8, 0x037e, + 0x2019, 0x0001, 0x1078, 0x5760, 0x037f, 0x2019, 0x7845, 0x2304, + 0xa065, 0x0040, 0x1ff7, 0x2009, 0x004f, 0x1078, 0x5c21, 0x0c7f, + 0x017f, 0xd19c, 0x0040, 0x2021, 0x017e, 0x6028, 0xc09c, 0x602a, + 0x2011, 0x0003, 0x1078, 0x57b8, 0x2011, 0x0002, 0x1078, 0x57c2, + 0x1078, 0x56ce, 0x1078, 0x45e3, 0x037e, 0x2019, 0x0000, 0x1078, + 0x5760, 0x037f, 0x60e3, 0x0000, 0x1078, 0x75a5, 0x1078, 0x75c3, + 0x2001, 0x7600, 0x2003, 0x0004, 0x6027, 0x0008, 0x1078, 0x11be, + 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, 0x007e, 0x017e, 0x027e, + 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7600, 0x71b0, + 0x70b2, 0xa116, 0x0040, 0x204b, 0x81ff, 0x0040, 0x203d, 0x2011, + 0x8011, 0x1078, 0x2d3b, 0x0078, 0x204b, 0x2011, 0x8012, 0x1078, + 0x2d3b, 0x037e, 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, 0x1078, + 0x2293, 0x0c7f, 0x037f, 0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, + 0x007f, 0x007c, 0x0c7e, 0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, + 0xa190, 0x206d, 0x2204, 0x60f2, 0xa192, 0x0005, 0x00c8, 0x2064, + 0xa190, 0x2076, 0x0078, 0x2066, 0x2011, 0x207a, 0x2204, 0x60ee, + 0x027f, 0x007f, 0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, + 0x0580, 0x0420, 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, + 0x01a8, 0x01a8, 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, + 0x2130, 0xa094, 0xff00, 0x00c0, 0x2088, 0x81ff, 0x0040, 0x208c, + 0x1078, 0x4328, 0x0078, 0x2093, 0xa080, 0x2329, 0x200c, 0xa18c, + 0xff00, 0x810f, 0xa006, 0x007c, 0xa080, 0x2329, 0x200c, 0xa18c, + 0x00ff, 0x007c, 0x20ba, 0x20be, 0x20c2, 0x20c8, 0x20ce, 0x20d4, + 0x20da, 0x20e2, 0x20ea, 0x20f0, 0x20f6, 0x20fe, 0x2106, 0x210e, + 0x2116, 0x2120, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, + 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, 0x212a, + 0x212a, 0x212a, 0x107e, 0x007e, 0x0078, 0x2143, 0x107e, 0x007e, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1e5e, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, + 0x0078, 0x2143, 0x107e, 0x007e, 0x1078, 0x1d8a, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, 0x107e, 0x007e, + 0x1078, 0x1e5e, 0x1078, 0x1d45, 0x1078, 0x1d8a, 0x0078, 0x2143, + 0x107e, 0x007e, 0x1078, 0x1e5e, 0x1078, 0x1d45, 0x1078, 0x1d8a, + 0x0078, 0x2143, 0x0005, 0x0078, 0x212a, 0xb084, 0x003c, 0x8004, + 0x8004, 0x0079, 0x2133, 0x2143, 0x20c0, 0x20c4, 0x20ca, 0x20d0, + 0x20d6, 0x20dc, 0x20e4, 0x20ec, 0x20f2, 0x20f8, 0x2100, 0x2108, + 0x2110, 0x2118, 0x2122, 0x0008, 0x212d, 0x007f, 0x107f, 0x2091, + 0x8001, 0x007c, 0x0c7e, 0x027e, 0x2041, 0x007e, 0x70bc, 0xd09c, + 0x0040, 0x2154, 0x2041, 0x007f, 0x2001, 0x010c, 0x203c, 0x727c, + 0x82ff, 0x0040, 0x219f, 0x037e, 0x738c, 0xa38e, 0xffff, 0x00c0, + 0x2163, 0x2019, 0x0001, 0x8314, 0xa2e0, 0x7cc0, 0x2c04, 0xa38c, + 0x0001, 0x0040, 0x2170, 0xa084, 0xff00, 0x8007, 0x0078, 0x2172, + 0xa084, 0x00ff, 0xa70e, 0x0040, 0x2194, 0xa08e, 0x00ff, 0x0040, + 0x219a, 0x2009, 0x0000, 0x1078, 0x207f, 0x1078, 0x37e6, 0x00c0, + 0x2197, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x218e, + 0x1078, 0x21f1, 0x0040, 0x2197, 0x0078, 0x2194, 0x1078, 0x22f5, + 0x1078, 0x2218, 0x0040, 0x2197, 0x8318, 0x0078, 0x2163, 0x738e, + 0x0078, 0x219c, 0x708f, 0xffff, 0x037f, 0x0078, 0x21ee, 0xa780, + 0x2329, 0x203c, 0xa7bc, 0xff00, 0x873f, 0x708c, 0xa096, 0xffff, + 0x0040, 0x21b1, 0xa812, 0x00c8, 0x21c1, 0x708f, 0xffff, 0x0078, + 0x21eb, 0x2009, 0x0000, 0x70bc, 0xd09c, 0x0040, 0x21bc, 0xd094, + 0x0040, 0x21bc, 0x2009, 0x007e, 0x2100, 0xa802, 0x20a8, 0x0078, + 0x21c5, 0x2008, 0x2810, 0xa202, 0x20a8, 0x2700, 0x157e, 0x017e, + 0xa106, 0x0040, 0x21e2, 0x1078, 0x37e6, 0x00c0, 0x21eb, 0x6004, + 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x21dc, 0x1078, 0x21f1, + 0x0040, 0x21eb, 0x0078, 0x21e2, 0x1078, 0x22f5, 0x1078, 0x2218, + 0x0040, 0x21eb, 0x017f, 0x8108, 0x157f, 0x00f0, 0x21c5, 0x708f, + 0xffff, 0x0078, 0x21ee, 0x017f, 0x157f, 0x718e, 0x027f, 0x0c7f, + 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, + 0x0040, 0x2213, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, + 0x1078, 0x37b5, 0x2001, 0x0000, 0x1078, 0x37c9, 0x127e, 0x2091, + 0x8000, 0x7088, 0x8000, 0x708a, 0x127f, 0x2009, 0x0004, 0x1078, + 0x5c21, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, + 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, 0x0040, + 0x223a, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, + 0x7088, 0x8000, 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x027e, 0x2009, 0x0080, 0x1078, 0x37e6, 0x00c0, 0x224d, 0x1078, + 0x2250, 0x0040, 0x224d, 0x70c3, 0xffff, 0x027f, 0x0c7f, 0x007c, + 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x5b94, 0x0040, + 0x2272, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, + 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, + 0x70c4, 0x8000, 0x70c6, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e, + 0x0d7e, 0x2009, 0x007f, 0x1078, 0x37e6, 0x00c0, 0x2290, 0x2c68, + 0x1078, 0x5b94, 0x0040, 0x2290, 0x2d00, 0x601a, 0x6312, 0x601f, + 0x0001, 0x620a, 0x2009, 0x0022, 0x1078, 0x5c21, 0xa085, 0x0001, + 0x0d7f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, + 0x1078, 0x4961, 0x1078, 0x4911, 0x1078, 0x60f9, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, 0x00c0, 0x22ab, 0x1078, + 0x399e, 0x1078, 0x3619, 0x017f, 0x8108, 0x00f0, 0x22a2, 0x027f, + 0x037f, 0x067f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, + 0x027e, 0x017e, 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, + 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x017f, + 0x2e60, 0x1078, 0x399e, 0x6210, 0x6314, 0x1078, 0x3619, 0x6212, + 0x6316, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, + 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x22eb, + 0x2071, 0x7600, 0x7088, 0xa005, 0x0040, 0x22e8, 0x8001, 0x708a, + 0x007f, 0x0e7f, 0x007c, 0x2071, 0x7600, 0x70c4, 0xa005, 0x0040, + 0x22e8, 0x8001, 0x70c6, 0x0078, 0x22e8, 0x6000, 0xc08c, 0x6002, + 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x81ff, + 0x00c0, 0x2306, 0x20a9, 0x0001, 0x0078, 0x230a, 0x20a9, 0x007f, + 0x2011, 0x0000, 0x027e, 0xa2e0, 0x7720, 0x2c64, 0x8cff, 0x0040, + 0x231c, 0x2019, 0x0029, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, + 0x1078, 0x7370, 0x1078, 0x399e, 0x027f, 0x8210, 0x00f0, 0x230a, + 0x027e, 0x027f, 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, + 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, + 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, + 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, + 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, + 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, + 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, + 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, + 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, + 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, + 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, + 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, + 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, + 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, + 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, + 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, + 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, + 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, + 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, + 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, + 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, + 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, + 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, + 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, + 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, + 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, + 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, - 0x766d, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, - 0x7033, 0x767d, 0x7037, 0x767d, 0x7007, 0x0001, 0x2061, 0x76bd, - 0x6003, 0x0002, 0x007c, 0x0090, 0x2456, 0x0068, 0x2456, 0x2071, - 0x766d, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2456, 0x2a60, 0x7820, - 0xa08e, 0x0069, 0x00c0, 0x253d, 0x0079, 0x24da, 0x007c, 0x2071, - 0x766d, 0x7004, 0x0079, 0x245c, 0x2460, 0x2461, 0x246b, 0x247d, - 0x007c, 0x0090, 0x246a, 0x0068, 0x246a, 0x2b78, 0x7818, 0xd084, - 0x0040, 0x2489, 0x007c, 0x2b78, 0x2061, 0x76bd, 0x6008, 0xa08e, - 0x0100, 0x0040, 0x2478, 0xa086, 0x0200, 0x0040, 0x2535, 0x007c, - 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, 0x6834, - 0xa086, 0x0103, 0x0040, 0x2485, 0x007c, 0x2a60, 0x2b78, 0x7018, - 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2492, 0x61b0, - 0x0079, 0x249a, 0x2100, 0xa08a, 0x0036, 0x00c8, 0x2531, 0x61b0, - 0x0079, 0x24da, 0x2513, 0x2545, 0x254d, 0x2551, 0x2559, 0x255f, - 0x2563, 0x256c, 0x2570, 0x2578, 0x257c, 0x2531, 0x2531, 0x2531, - 0x2580, 0x2531, 0x2590, 0x25a7, 0x25be, 0x263a, 0x263f, 0x266c, - 0x26b9, 0x26c8, 0x26e9, 0x271f, 0x2729, 0x2736, 0x2749, 0x2761, - 0x276a, 0x27a7, 0x27ad, 0x2531, 0x27bd, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x27c1, 0x27c7, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x27cf, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x27dc, 0x27e2, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2578, 0x257c, 0x2531, 0x2531, 0x27f4, 0x2531, - 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, 0x2531, - 0x2531, 0x2531, 0x2841, 0x290e, 0x2922, 0x2929, 0x298c, 0x29e7, - 0x29f2, 0x2a34, 0x2a41, 0x2a4e, 0x2a51, 0x27f8, 0x2a7a, 0x2ac1, - 0x2ace, 0x2bc8, 0x2cb6, 0x2cdd, 0x2dd5, 0x2de3, 0x2df0, 0x2e2a, - 0x713c, 0x0078, 0x2513, 0x2021, 0x4000, 0x1078, 0x2d24, 0x127e, - 0x2091, 0x8000, 0x0068, 0x2520, 0x7818, 0xd084, 0x0040, 0x2523, - 0x127f, 0x0078, 0x2517, 0x781b, 0x0001, 0x7c22, 0x7926, 0x7a2a, - 0x7b2e, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, 0x127f, - 0x007c, 0x2021, 0x4001, 0x0078, 0x2515, 0x2021, 0x4002, 0x0078, - 0x2515, 0x2021, 0x4003, 0x0078, 0x2515, 0x2021, 0x4005, 0x0078, - 0x2515, 0x2021, 0x4006, 0x0078, 0x2515, 0xa02e, 0x2520, 0x7b28, - 0x7a2c, 0x7824, 0x7930, 0x0078, 0x2d33, 0x7823, 0x0004, 0x7824, - 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, - 0x2d37, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2513, 0x7924, - 0x2114, 0x0078, 0x2513, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, - 0x0007, 0x53a3, 0x0078, 0x2513, 0x7824, 0x2060, 0x0078, 0x2582, - 0x2009, 0x0001, 0x2011, 0x000f, 0x2019, 0x0013, 0x0078, 0x2513, - 0x7d38, 0x7c3c, 0x0078, 0x2547, 0x7d38, 0x7c3c, 0x0078, 0x2553, - 0x2061, 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, - 0x00c0, 0x2584, 0x2010, 0xa005, 0x0040, 0x2513, 0x0078, 0x2539, - 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2541, 0x8019, - 0x0040, 0x2541, 0x604a, 0x6142, 0x782c, 0x6052, 0x7828, 0x6056, - 0xa006, 0x605a, 0x605e, 0x1078, 0x3c71, 0x0078, 0x2513, 0x2061, - 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2541, 0x8019, 0x0040, - 0x2541, 0x604e, 0x6146, 0x782c, 0x6062, 0x7828, 0x6066, 0xa006, - 0x606a, 0x606e, 0x1078, 0x3a47, 0x0078, 0x2513, 0xa02e, 0x2520, - 0x81ff, 0x00c0, 0x253d, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, - 0x20a1, 0x7674, 0x41a1, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x2009, - 0x0020, 0x1078, 0x2d33, 0x701b, 0x25d6, 0x007c, 0x6834, 0x2008, - 0xa084, 0x00ff, 0xa096, 0x0011, 0x0040, 0x25e2, 0xa096, 0x0019, - 0x00c0, 0x253d, 0x810f, 0xa18c, 0x00ff, 0x0040, 0x253d, 0x710e, - 0x700c, 0x8001, 0x0040, 0x2613, 0x700e, 0x1078, 0x2cfb, 0x0040, - 0x253d, 0x2009, 0x0020, 0x2061, 0x76bd, 0x6224, 0x6328, 0x642c, - 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0x1078, 0x2d33, 0x701b, 0x2606, 0x007c, 0x6834, 0xa084, - 0x00ff, 0xa096, 0x0002, 0x0040, 0x2611, 0xa096, 0x000a, 0x00c0, - 0x253d, 0x0078, 0x25e8, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, - 0x1078, 0x3722, 0x00c0, 0x2621, 0x7007, 0x0003, 0x701b, 0x2623, - 0x007c, 0x1078, 0x3b0a, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, - 0x2099, 0x7674, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, - 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, - 0x0078, 0x2d37, 0x6198, 0x7824, 0x609a, 0x0078, 0x2513, 0x2091, - 0x8000, 0x7823, 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, - 0x2020, 0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, - 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, - 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, - 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, 0xa08a, 0x0003, - 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff, 0x00c0, 0x253d, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x7c28, 0x7d2c, 0x1078, 0x3969, 0xd28c, - 0x00c0, 0x267e, 0x1078, 0x38f9, 0x0078, 0x2680, 0x1078, 0x3935, - 0x00c0, 0x26aa, 0x2061, 0x7d00, 0x127e, 0x2091, 0x8000, 0x6000, - 0xa086, 0x0000, 0x0040, 0x2698, 0x6010, 0xa06d, 0x0040, 0x2698, - 0x683c, 0xa406, 0x00c0, 0x2698, 0x6840, 0xa506, 0x0040, 0x26a3, - 0x127f, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, - 0x253d, 0x0078, 0x2684, 0x1078, 0x6738, 0x127f, 0x0040, 0x253d, - 0x0078, 0x2513, 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b0a, 0x127e, - 0x2091, 0x8000, 0x1078, 0x6b47, 0x1078, 0x3a7a, 0x127f, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38ae, 0x1078, 0x397a, 0x0040, 0x253d, 0x0078, 0x2513, - 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x2031, - 0x000f, 0x1078, 0x38ae, 0x8631, 0x00c8, 0x26d1, 0x2019, 0x0005, - 0x1078, 0x399b, 0x0040, 0x253d, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x2541, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x457b, 0x0078, - 0x2513, 0x127e, 0x2091, 0x8000, 0x81ff, 0x00c0, 0x2719, 0x2029, - 0x00ff, 0x644c, 0x2400, 0xa506, 0x0040, 0x2713, 0x2508, 0x1078, - 0x3825, 0x00c0, 0x2713, 0x2031, 0x000f, 0x1078, 0x38ae, 0x8631, - 0x00c8, 0x26fd, 0x2019, 0x0004, 0x1078, 0x399b, 0x0040, 0x2719, - 0x7824, 0xa08a, 0x1000, 0x00c8, 0x271c, 0x8003, 0x800b, 0x810b, - 0xa108, 0x1078, 0x457b, 0x8529, 0x00c8, 0x26f2, 0x127f, 0x0078, - 0x2513, 0x127f, 0x0078, 0x253d, 0x127f, 0x0078, 0x2541, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x1078, 0x38de, 0x1078, 0x3969, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38c7, 0x1078, 0x3969, 0x0078, 0x2513, 0x81ff, 0x00c0, - 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3938, 0x0040, - 0x253d, 0x1078, 0x376a, 0x1078, 0x38f2, 0x1078, 0x3969, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x38ae, 0x62a0, - 0x2019, 0x0005, 0x0c7e, 0x1078, 0x39a6, 0x0c7f, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x1078, 0x3969, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3969, 0x2208, - 0x0078, 0x2513, 0x157e, 0x0d7e, 0x0e7e, 0x2069, 0x76ff, 0x6810, - 0x6914, 0xa10a, 0x00c8, 0x2776, 0x2009, 0x0000, 0x6816, 0x2011, - 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, 0x7720, 0x2d04, - 0xa075, 0x0040, 0x278b, 0x704c, 0x1078, 0x2795, 0xa210, 0x7080, - 0x1078, 0x2795, 0xa318, 0x8d68, 0x00f0, 0x277f, 0x2300, 0xa218, - 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x2513, 0x0f7e, 0x017e, 0xa07d, - 0x0040, 0x27a4, 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0040, - 0x27a4, 0x2178, 0x0078, 0x279c, 0x017f, 0x0f7f, 0x007c, 0x2069, - 0x76ff, 0x6910, 0x629c, 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, - 0x614c, 0xa190, 0x232f, 0x2214, 0xa294, 0x00ff, 0x6068, 0xa084, - 0xff00, 0xa215, 0x6364, 0x0078, 0x2513, 0x613c, 0x6240, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x0078, 0x2513, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x6244, 0x6338, 0x0078, 0x2513, 0x613c, - 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0x7651, 0x831f, - 0xa305, 0x6816, 0x0078, 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x0078, 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x7828, 0xa00d, - 0x0040, 0x2541, 0x782c, 0xa005, 0x0040, 0x2541, 0x6244, 0x6146, - 0x6338, 0x603a, 0x0078, 0x2513, 0x7d38, 0x7c3c, 0x0078, 0x25c0, - 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x253d, 0x624c, - 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x2810, 0x2001, 0x7640, - 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d37, - 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x253d, 0x0c7e, 0x1078, - 0x2cfb, 0x0c7f, 0x0040, 0x253d, 0x6837, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x1078, 0x6a41, 0x0040, 0x253d, 0x7007, 0x0003, 0x701b, - 0x2832, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x253d, 0xad80, - 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, - 0x2d37, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x2009, 0x001c, 0x7a2c, - 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2d33, 0x701b, 0x2850, 0x007c, - 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x2541, 0x6804, 0xd0ac, - 0x0040, 0x285d, 0xd0a4, 0x0040, 0x2541, 0xd094, 0x0040, 0x2868, - 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, 0x6106, 0x0c7f, - 0xd08c, 0x0040, 0x2873, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18d, - 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0002, - 0x0048, 0x2888, 0xd084, 0x0040, 0x2888, 0x6a28, 0xa28a, 0x007f, - 0x00c8, 0x2541, 0xa288, 0x232f, 0x210c, 0xa18c, 0x00ff, 0x6152, - 0xd0dc, 0x0040, 0x2891, 0x6828, 0xa08a, 0x007f, 0x00c8, 0x2541, - 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x2541, 0xa08a, 0x0841, - 0x00c8, 0x2541, 0xa084, 0x0007, 0x00c0, 0x2541, 0x680c, 0xa005, - 0x0040, 0x2541, 0x6810, 0xa005, 0x0040, 0x2541, 0x6848, 0x6940, - 0xa10a, 0x00c8, 0x2541, 0x8001, 0x0040, 0x2541, 0x684c, 0x6944, - 0xa10a, 0x00c8, 0x2541, 0x8001, 0x0040, 0x2541, 0x20a9, 0x001c, - 0x2d98, 0x2069, 0x7651, 0x2da0, 0x53a3, 0x6814, 0xa08c, 0x00ff, - 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, 0x3c71, 0x1078, - 0x3a47, 0x6000, 0xa086, 0x0000, 0x00c0, 0x290c, 0x6808, 0x602a, - 0x1078, 0x1dea, 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, - 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, - 0x0040, 0x28ec, 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, - 0x8217, 0x831f, 0x0078, 0x28ee, 0xa084, 0xf0ff, 0x6006, 0x610a, - 0x620e, 0x6312, 0x1078, 0x4607, 0x0c7e, 0x2061, 0x0100, 0x602f, - 0x0040, 0x602f, 0x0000, 0x0c7f, 0x60b4, 0xa005, 0x0040, 0x2908, - 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x357b, 0x0078, 0x290c, - 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x2513, 0x6000, 0xa086, - 0x0000, 0x0040, 0x253d, 0x2069, 0x7651, 0x7830, 0x6842, 0x7834, - 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x0078, 0x2d37, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x357b, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x617c, 0x81ff, 0x0040, 0x2943, - 0x703f, 0x0000, 0x2001, 0x7cc0, 0x2009, 0x0040, 0x7a2c, 0x7b28, - 0x7c3c, 0x7d38, 0x127e, 0x2091, 0x8000, 0x1078, 0x2d37, 0x701b, - 0x2510, 0x127f, 0x007c, 0x703f, 0x0001, 0x0d7e, 0x2069, 0x7cc0, - 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2019, 0xffff, 0x43a4, 0x654c, - 0xa588, 0x232f, 0x210c, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, - 0x0002, 0x2100, 0xa506, 0x0040, 0x2975, 0x1078, 0x3825, 0x00c0, - 0x2975, 0x6014, 0x821c, 0x0048, 0x296d, 0xa398, 0x7cc0, 0xa085, - 0xff00, 0x8007, 0x201a, 0x0078, 0x2974, 0xa398, 0x7cc0, 0x2324, - 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, 0xa182, 0x0080, - 0x00c8, 0x297c, 0x0078, 0x2959, 0x8201, 0x8007, 0x2d0c, 0xa105, - 0x206a, 0x0d7f, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2099, 0x7cc0, - 0x1078, 0x35c4, 0x0078, 0x2932, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x0c7e, 0x1078, 0x2cfb, 0x0c7f, 0x0040, 0x253d, 0x2001, 0x7652, - 0x2004, 0xd0b4, 0x0040, 0x29b9, 0x6000, 0xd08c, 0x00c0, 0x29b9, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x29b9, 0x6837, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a79, 0x0040, 0x253d, - 0x7007, 0x0003, 0x701b, 0x29b5, 0x007c, 0x1078, 0x2d13, 0x0040, - 0x2541, 0x20a9, 0x0029, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, - 0x20a9, 0x0002, 0xac80, 0x0004, 0x2098, 0xad80, 0x0004, 0x20a0, - 0x1078, 0x35c4, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, - 0x0006, 0x20a0, 0x1078, 0x35c4, 0x20a9, 0x0004, 0xac80, 0x000a, - 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x35c4, 0x2d00, 0x2009, - 0x0029, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d37, 0x81ff, - 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, 0x1078, 0x3985, - 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, 0x7828, 0xa08a, 0x1000, - 0x00c8, 0x2541, 0x1078, 0x2d13, 0x0040, 0x2541, 0x2031, 0x000f, - 0x1078, 0x38ae, 0x8631, 0x00c8, 0x2a00, 0x2019, 0x0004, 0x1078, - 0x399b, 0x7924, 0x810f, 0x7a28, 0x1078, 0x2a10, 0x0078, 0x2513, - 0xa186, 0x00ff, 0x0040, 0x2a18, 0x1078, 0x2a28, 0x0078, 0x2a27, + 0x8000, 0x2071, 0x766d, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, + 0x703a, 0x703e, 0x7033, 0x767d, 0x7037, 0x767d, 0x7007, 0x0001, + 0x2061, 0x76bd, 0x6003, 0x0002, 0x007c, 0x0090, 0x2450, 0x0068, + 0x2450, 0x2071, 0x766d, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2450, + 0x2a60, 0x7820, 0xa08e, 0x0069, 0x00c0, 0x2537, 0x0079, 0x24d4, + 0x007c, 0x2071, 0x766d, 0x7004, 0x0079, 0x2456, 0x245a, 0x245b, + 0x2465, 0x2477, 0x007c, 0x0090, 0x2464, 0x0068, 0x2464, 0x2b78, + 0x7818, 0xd084, 0x0040, 0x2483, 0x007c, 0x2b78, 0x2061, 0x76bd, + 0x6008, 0xa08e, 0x0100, 0x0040, 0x2472, 0xa086, 0x0200, 0x0040, + 0x252f, 0x007c, 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, + 0x2068, 0x6834, 0xa086, 0x0103, 0x0040, 0x247f, 0x007c, 0x2a60, + 0x2b78, 0x7018, 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, + 0x248c, 0x61b0, 0x0079, 0x2494, 0x2100, 0xa08a, 0x0036, 0x00c8, + 0x252b, 0x61b0, 0x0079, 0x24d4, 0x250d, 0x253f, 0x2547, 0x254b, + 0x2553, 0x2559, 0x255d, 0x2566, 0x256a, 0x2572, 0x2576, 0x252b, + 0x252b, 0x252b, 0x257a, 0x252b, 0x258a, 0x25a1, 0x25b8, 0x2634, + 0x2639, 0x2666, 0x26b3, 0x26c2, 0x26e3, 0x2719, 0x2723, 0x2730, + 0x2743, 0x275b, 0x2764, 0x27a1, 0x27a7, 0x252b, 0x27b7, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x27bb, 0x27c1, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x27c9, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x27d6, 0x27dc, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x2572, 0x2576, 0x252b, 0x252b, + 0x27ee, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, 0x252b, + 0x252b, 0x252b, 0x252b, 0x252b, 0x283b, 0x2908, 0x291c, 0x2923, + 0x2986, 0x29d7, 0x29e2, 0x2a24, 0x2a31, 0x2a3e, 0x2a41, 0x27f2, + 0x2a6a, 0x2ab1, 0x2abe, 0x2bb9, 0x2ca7, 0x2cce, 0x2dc6, 0x2dd4, + 0x2de1, 0x2e1b, 0x713c, 0x0078, 0x250d, 0x2021, 0x4000, 0x1078, + 0x2d15, 0x127e, 0x2091, 0x8000, 0x0068, 0x251a, 0x7818, 0xd084, + 0x0040, 0x251d, 0x127f, 0x0078, 0x2511, 0x781b, 0x0001, 0x7c22, + 0x7926, 0x7a2a, 0x7b2e, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x250f, 0x2021, + 0x4002, 0x0078, 0x250f, 0x2021, 0x4003, 0x0078, 0x250f, 0x2021, + 0x4005, 0x0078, 0x250f, 0x2021, 0x4006, 0x0078, 0x250f, 0xa02e, + 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x2d24, 0x7823, + 0x0004, 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, + 0x7930, 0x0078, 0x2d28, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, + 0x250d, 0x7924, 0x2114, 0x0078, 0x250d, 0x2099, 0x0009, 0x20a1, + 0x0009, 0x20a9, 0x0007, 0x53a3, 0x0078, 0x250d, 0x7824, 0x2060, + 0x0078, 0x257c, 0x2009, 0x0001, 0x2011, 0x000f, 0x2019, 0x0025, + 0x0078, 0x250d, 0x7d38, 0x7c3c, 0x0078, 0x2541, 0x7d38, 0x7c3c, + 0x0078, 0x254d, 0x2061, 0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, + 0x8c60, 0x8109, 0x00c0, 0x257e, 0x2010, 0xa005, 0x0040, 0x250d, + 0x0078, 0x2533, 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, + 0x253b, 0x8019, 0x0040, 0x253b, 0x604a, 0x6142, 0x782c, 0x6052, + 0x7828, 0x6056, 0xa006, 0x605a, 0x605e, 0x1078, 0x3c69, 0x0078, + 0x250d, 0x2061, 0x7651, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x253b, + 0x8019, 0x0040, 0x253b, 0x604e, 0x6146, 0x782c, 0x6062, 0x7828, + 0x6066, 0xa006, 0x606a, 0x606e, 0x1078, 0x3a3f, 0x0078, 0x250d, + 0xa02e, 0x2520, 0x81ff, 0x00c0, 0x2537, 0x7924, 0x7b28, 0x7a2c, + 0x20a9, 0x0005, 0x20a1, 0x7674, 0x41a1, 0x1078, 0x2cec, 0x0040, + 0x2537, 0x2009, 0x0020, 0x1078, 0x2d24, 0x701b, 0x25d0, 0x007c, + 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0040, 0x25dc, + 0xa096, 0x0019, 0x00c0, 0x2537, 0x810f, 0xa18c, 0x00ff, 0x0040, + 0x2537, 0x710e, 0x700c, 0x8001, 0x0040, 0x260d, 0x700e, 0x1078, + 0x2cec, 0x0040, 0x2537, 0x2009, 0x0020, 0x2061, 0x76bd, 0x6224, + 0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, + 0x0000, 0xa5a9, 0x0000, 0x1078, 0x2d24, 0x701b, 0x2600, 0x007c, + 0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0040, 0x260b, 0xa096, + 0x000a, 0x00c0, 0x2537, 0x0078, 0x25e2, 0x7010, 0x2068, 0x6838, + 0xc0fd, 0x683a, 0x1078, 0x371a, 0x00c0, 0x261b, 0x7007, 0x0003, + 0x701b, 0x261d, 0x007c, 0x1078, 0x3b02, 0x127e, 0x2091, 0x8000, + 0x20a9, 0x0005, 0x2099, 0x7674, 0x530a, 0x2100, 0xa210, 0xa399, + 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, + 0x0020, 0x127f, 0x0078, 0x2d28, 0x6198, 0x7824, 0x609a, 0x0078, + 0x250d, 0x2091, 0x8000, 0x7823, 0x4000, 0x7827, 0x4953, 0x782b, + 0x5020, 0x782f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, + 0x7836, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, + 0xa205, 0x783a, 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, + 0x2091, 0x5000, 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, + 0xa08a, 0x0003, 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff, 0x00c0, + 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x7c28, 0x7d2c, 0x1078, + 0x3961, 0xd28c, 0x00c0, 0x2678, 0x1078, 0x38f1, 0x0078, 0x267a, + 0x1078, 0x392d, 0x00c0, 0x26a4, 0x2061, 0x7d00, 0x127e, 0x2091, + 0x8000, 0x6000, 0xa086, 0x0000, 0x0040, 0x2692, 0x6010, 0xa06d, + 0x0040, 0x2692, 0x683c, 0xa406, 0x00c0, 0x2692, 0x6840, 0xa506, + 0x0040, 0x269d, 0x127f, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x2537, 0x0078, 0x267e, 0x1078, 0x6732, 0x127f, + 0x0040, 0x2537, 0x0078, 0x250d, 0xa00e, 0x2001, 0x0005, 0x1078, + 0x3b02, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b3c, 0x1078, 0x3a72, + 0x127f, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x1078, 0x38a6, 0x1078, 0x3972, 0x0040, 0x2537, + 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, + 0x253b, 0x2031, 0x000f, 0x1078, 0x38a6, 0x8631, 0x00c8, 0x26cb, + 0x2019, 0x0005, 0x1078, 0x3993, 0x0040, 0x2537, 0x7828, 0xa08a, + 0x1000, 0x00c8, 0x253b, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, + 0x4573, 0x0078, 0x250d, 0x127e, 0x2091, 0x8000, 0x81ff, 0x00c0, + 0x2713, 0x2029, 0x00ff, 0x644c, 0x2400, 0xa506, 0x0040, 0x270d, + 0x2508, 0x1078, 0x381d, 0x00c0, 0x270d, 0x2031, 0x000f, 0x1078, + 0x38a6, 0x8631, 0x00c8, 0x26f7, 0x2019, 0x0004, 0x1078, 0x3993, + 0x0040, 0x2713, 0x7824, 0xa08a, 0x1000, 0x00c8, 0x2716, 0x8003, + 0x800b, 0x810b, 0xa108, 0x1078, 0x4573, 0x8529, 0x00c8, 0x26ec, + 0x127f, 0x0078, 0x250d, 0x127f, 0x0078, 0x2537, 0x127f, 0x0078, + 0x253b, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, 0x38d6, 0x1078, + 0x3961, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x1078, 0x38bf, 0x1078, 0x3961, 0x0078, 0x250d, + 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x3930, 0x0040, 0x2537, 0x1078, 0x3762, 0x1078, 0x38ea, 0x1078, + 0x3961, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x38a6, 0x62a0, 0x2019, 0x0005, 0x0c7e, 0x1078, 0x399e, 0x0c7f, + 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x1078, + 0x3961, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, + 0x3961, 0x2208, 0x0078, 0x250d, 0x157e, 0x0d7e, 0x0e7e, 0x2069, + 0x76ff, 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2770, 0x2009, 0x0000, + 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, + 0x7720, 0x2d04, 0xa075, 0x0040, 0x2785, 0x704c, 0x1078, 0x278f, + 0xa210, 0x7080, 0x1078, 0x278f, 0xa318, 0x8d68, 0x00f0, 0x2779, + 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x250d, 0x0f7e, + 0x017e, 0xa07d, 0x0040, 0x279e, 0x2001, 0x0000, 0x8000, 0x2f0c, + 0x81ff, 0x0040, 0x279e, 0x2178, 0x0078, 0x2796, 0x017f, 0x0f7f, + 0x007c, 0x2069, 0x76ff, 0x6910, 0x629c, 0x0078, 0x250d, 0x81ff, + 0x00c0, 0x2537, 0x614c, 0xa190, 0x2329, 0x2214, 0xa294, 0x00ff, + 0x6068, 0xa084, 0xff00, 0xa215, 0x6364, 0x0078, 0x250d, 0x613c, + 0x6240, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x0078, + 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x6244, 0x6338, 0x0078, + 0x250d, 0x613c, 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, + 0x7651, 0x831f, 0xa305, 0x6816, 0x0078, 0x250d, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x0078, 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, + 0x7828, 0xa00d, 0x0040, 0x253b, 0x782c, 0xa005, 0x0040, 0x253b, + 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, 0x250d, 0x7d38, 0x7c3c, + 0x0078, 0x25ba, 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, + 0x2537, 0x624c, 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x280a, + 0x2001, 0x7640, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x0078, 0x2d28, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, + 0x253b, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2537, + 0x0c7e, 0x1078, 0x2cec, 0x0c7f, 0x0040, 0x2537, 0x6837, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a36, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x282c, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, + 0x2537, 0xad80, 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0078, 0x2d28, 0x1078, 0x2cec, 0x0040, 0x2537, 0x2009, + 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2d24, 0x701b, + 0x284a, 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x253b, + 0x6804, 0xd0ac, 0x0040, 0x2857, 0xd0a4, 0x0040, 0x253b, 0xd094, + 0x0040, 0x2862, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, + 0x6106, 0x0c7f, 0xd08c, 0x0040, 0x286d, 0x0c7e, 0x2061, 0x0100, + 0x6104, 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, + 0xa18a, 0x0002, 0x0048, 0x2882, 0xd084, 0x0040, 0x2882, 0x6a28, + 0xa28a, 0x007f, 0x00c8, 0x253b, 0xa288, 0x2329, 0x210c, 0xa18c, + 0x00ff, 0x6152, 0xd0dc, 0x0040, 0x288b, 0x6828, 0xa08a, 0x007f, + 0x00c8, 0x253b, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x253b, + 0xa08a, 0x0841, 0x00c8, 0x253b, 0xa084, 0x0007, 0x00c0, 0x253b, + 0x680c, 0xa005, 0x0040, 0x253b, 0x6810, 0xa005, 0x0040, 0x253b, + 0x6848, 0x6940, 0xa10a, 0x00c8, 0x253b, 0x8001, 0x0040, 0x253b, + 0x684c, 0x6944, 0xa10a, 0x00c8, 0x253b, 0x8001, 0x0040, 0x253b, + 0x20a9, 0x001c, 0x2d98, 0x2069, 0x7651, 0x2da0, 0x53a3, 0x6814, + 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, + 0x3c69, 0x1078, 0x3a3f, 0x6000, 0xa086, 0x0000, 0x00c0, 0x2906, + 0x6808, 0x602a, 0x1078, 0x1de4, 0x6818, 0x691c, 0x6a20, 0x6b24, + 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322, + 0x6c04, 0xd4f4, 0x0040, 0x28e6, 0x6830, 0x6934, 0x6a38, 0x6b3c, + 0x8007, 0x810f, 0x8217, 0x831f, 0x0078, 0x28e8, 0xa084, 0xf0ff, + 0x6006, 0x610a, 0x620e, 0x6312, 0x1078, 0x45ff, 0x0c7e, 0x2061, + 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x60b4, 0xa005, + 0x0040, 0x2902, 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x3573, + 0x0078, 0x2906, 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x250d, + 0x6000, 0xa086, 0x0000, 0x0040, 0x2537, 0x2069, 0x7651, 0x7830, + 0x6842, 0x7834, 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0078, 0x2d28, 0x81ff, 0x00c0, 0x2537, 0x1078, + 0x3573, 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x617c, 0x81ff, + 0x0040, 0x293d, 0x703f, 0x0000, 0x2001, 0x7cc0, 0x2009, 0x0040, + 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x127e, 0x2091, 0x8000, 0x1078, + 0x2d28, 0x701b, 0x250a, 0x127f, 0x007c, 0x703f, 0x0001, 0x0d7e, + 0x2069, 0x7cc0, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2019, 0xffff, + 0x43a4, 0x654c, 0xa588, 0x2329, 0x210c, 0xa18c, 0x00ff, 0x216a, + 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, 0x0040, 0x296f, 0x1078, + 0x381d, 0x00c0, 0x296f, 0x6014, 0x821c, 0x0048, 0x2967, 0xa398, + 0x7cc0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0078, 0x296e, 0xa398, + 0x7cc0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, + 0xa182, 0x0080, 0x00c8, 0x2976, 0x0078, 0x2953, 0x8201, 0x8007, + 0x2d0c, 0xa105, 0x206a, 0x0d7f, 0x20a9, 0x0040, 0x20a1, 0x7cc0, + 0x2099, 0x7cc0, 0x1078, 0x35bc, 0x0078, 0x292c, 0x1078, 0x2d04, + 0x0040, 0x253b, 0x0c7e, 0x1078, 0x2cec, 0x0c7f, 0x0040, 0x2537, + 0x2001, 0x7652, 0x2004, 0xd0b4, 0x0040, 0x29b3, 0x6000, 0xd08c, + 0x00c0, 0x29b3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x29b3, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6a6e, + 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, 0x29af, 0x007c, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x20a9, 0x0029, 0x2c98, 0xade8, 0x0002, + 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, + 0x0006, 0x20a0, 0x1078, 0x35bc, 0x20a9, 0x0004, 0xac80, 0x000a, + 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x35bc, 0x2d00, 0x2009, + 0x0029, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x2d28, 0x81ff, + 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, 0x1078, 0x397d, + 0x0078, 0x250d, 0x81ff, 0x00c0, 0x2537, 0x7828, 0xa08a, 0x1000, + 0x00c8, 0x253b, 0x1078, 0x2d04, 0x0040, 0x253b, 0x2031, 0x000f, + 0x1078, 0x38a6, 0x8631, 0x00c8, 0x29f0, 0x2019, 0x0004, 0x1078, + 0x3993, 0x7924, 0x810f, 0x7a28, 0x1078, 0x2a00, 0x0078, 0x250d, + 0xa186, 0x00ff, 0x0040, 0x2a08, 0x1078, 0x2a18, 0x0078, 0x2a17, 0x2029, 0x007e, 0x2061, 0x7600, 0x644c, 0x2400, 0xa506, 0x0040, - 0x2a24, 0x2508, 0x1078, 0x2a28, 0x8529, 0x00c8, 0x2a1d, 0x007c, - 0x1078, 0x3825, 0x00c0, 0x2a33, 0x2200, 0x8003, 0x800b, 0x810b, - 0xa108, 0x1078, 0x457b, 0x007c, 0x81ff, 0x00c0, 0x253d, 0x1078, - 0x2d13, 0x0040, 0x2541, 0x1078, 0x38ae, 0x1078, 0x3990, 0x0078, - 0x2513, 0x81ff, 0x00c0, 0x253d, 0x1078, 0x2d13, 0x0040, 0x2541, - 0x1078, 0x38ae, 0x1078, 0x397a, 0x0078, 0x2513, 0x6100, 0x0078, - 0x2513, 0x1078, 0x2d13, 0x0040, 0x2541, 0x6004, 0xa086, 0x0707, - 0x0040, 0x2541, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x253d, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x2a6a, + 0x2a14, 0x2508, 0x1078, 0x2a18, 0x8529, 0x00c8, 0x2a0d, 0x007c, + 0x1078, 0x381d, 0x00c0, 0x2a23, 0x2200, 0x8003, 0x800b, 0x810b, + 0xa108, 0x1078, 0x4573, 0x007c, 0x81ff, 0x00c0, 0x2537, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x1078, 0x38a6, 0x1078, 0x3988, 0x0078, + 0x250d, 0x81ff, 0x00c0, 0x2537, 0x1078, 0x2d04, 0x0040, 0x253b, + 0x1078, 0x38a6, 0x1078, 0x3972, 0x0078, 0x250d, 0x6100, 0x0078, + 0x250d, 0x1078, 0x2d04, 0x0040, 0x253b, 0x6004, 0xa086, 0x0707, + 0x0040, 0x253b, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x2537, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x2a5a, 0xace8, 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, - 0x0078, 0x2513, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0040, - 0x2a84, 0x81ff, 0x00c0, 0x253d, 0x7828, 0xa08a, 0x1000, 0x00c8, - 0x2541, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, - 0x2a98, 0xa182, 0x007f, 0x00c8, 0x2541, 0x2100, 0x1078, 0x209a, + 0x0078, 0x250d, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0040, + 0x2a74, 0x81ff, 0x00c0, 0x2537, 0x7828, 0xa08a, 0x1000, 0x00c8, + 0x253b, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, + 0x2a88, 0xa182, 0x007f, 0x00c8, 0x253b, 0x2100, 0x1078, 0x2094, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x2061, 0x7849, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x0100, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, - 0x001e, 0x2011, 0x35a0, 0x1078, 0x45fe, 0x7924, 0xa18c, 0xff00, - 0x810f, 0x7a28, 0x1078, 0x2a10, 0x127f, 0x0c7f, 0x027f, 0x0078, - 0x2513, 0x7924, 0xa18c, 0xff00, 0x810f, 0x0c7e, 0x1078, 0x37ee, - 0x2c08, 0x0c7f, 0x00c0, 0x2541, 0x0078, 0x2513, 0x81ff, 0x00c0, - 0x253d, 0x60bc, 0xd09c, 0x0040, 0x253d, 0x1078, 0x2cfb, 0x0040, - 0x253d, 0x6823, 0x0000, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x1078, 0x2d33, 0x701b, 0x2ae5, 0x007c, 0x2009, 0x0080, 0x1078, - 0x3825, 0x00c0, 0x2af2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x0040, 0x2af6, 0x2021, 0x400a, 0x0078, 0x2515, 0x0d7e, 0xade8, + 0x001e, 0x2011, 0x3598, 0x1078, 0x45f6, 0x7924, 0xa18c, 0xff00, + 0x810f, 0x7a28, 0x1078, 0x2a00, 0x127f, 0x0c7f, 0x027f, 0x0078, + 0x250d, 0x7924, 0xa18c, 0xff00, 0x810f, 0x0c7e, 0x1078, 0x37e6, + 0x2c08, 0x0c7f, 0x00c0, 0x253b, 0x0078, 0x250d, 0x81ff, 0x00c0, + 0x2537, 0x60bc, 0xd09c, 0x0040, 0x2537, 0x1078, 0x2cec, 0x0040, + 0x2537, 0x6823, 0x0000, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, + 0x1078, 0x2d24, 0x701b, 0x2ad5, 0x007c, 0x2009, 0x0080, 0x1078, + 0x381d, 0x00c0, 0x2ae2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0040, 0x2ae6, 0x2021, 0x400a, 0x0078, 0x250f, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, - 0xa0be, 0x0100, 0x0040, 0x2b68, 0xa0be, 0x0112, 0x0040, 0x2b68, - 0xa0be, 0x0113, 0x0040, 0x2b68, 0xa0be, 0x0114, 0x0040, 0x2b68, - 0xa0be, 0x0117, 0x0040, 0x2b68, 0xa0be, 0x011a, 0x0040, 0x2b68, - 0xa0be, 0x0121, 0x0040, 0x2b5e, 0xa0be, 0x0131, 0x0040, 0x2b5e, - 0xa0be, 0x0171, 0x0040, 0x2b68, 0xa0be, 0x0173, 0x0040, 0x2b68, - 0xa0be, 0x01a1, 0x00c0, 0x2b31, 0x6830, 0x8007, 0x6832, 0x0078, - 0x2b6e, 0xa0be, 0x0212, 0x0040, 0x2b64, 0xa0be, 0x0213, 0x0040, - 0x2b64, 0xa0be, 0x0214, 0x0040, 0x2b56, 0xa0be, 0x0217, 0x0040, - 0x2b50, 0xa0be, 0x021a, 0x00c0, 0x2b4a, 0x6838, 0x8007, 0x683a, - 0x0078, 0x2b68, 0xa0be, 0x0300, 0x0040, 0x2b68, 0x0078, 0x2541, - 0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x2ba4, 0xad80, 0x000e, - 0x20a9, 0x0001, 0x1078, 0x2ba4, 0x0078, 0x2b68, 0xad80, 0x000c, - 0x1078, 0x2bb2, 0x0078, 0x2b6e, 0xad80, 0x000e, 0x1078, 0x2bb2, - 0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x2ba4, 0x0c7e, 0x1078, - 0x2cfb, 0x0040, 0x2b99, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, - 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, 0x0000, - 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, 0x0c7f, - 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, - 0x1078, 0x6a5d, 0x0040, 0x253d, 0x7007, 0x0003, 0x701b, 0x2b9d, - 0x007c, 0x0c7f, 0x0d7f, 0x0078, 0x253d, 0x6820, 0xa086, 0x8001, - 0x0040, 0x253d, 0x0078, 0x2513, 0x017e, 0x2008, 0x2044, 0x8000, - 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x00f0, 0x2ba6, - 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, 0x2044, 0x8000, - 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, 0x2a0a, - 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, 0x017f, 0x007c, - 0x81ff, 0x00c0, 0x253d, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, - 0xa182, 0x0080, 0x0048, 0x2541, 0xa182, 0x00ff, 0x00c8, 0x2541, - 0x7a2c, 0x7b28, 0x6064, 0xa306, 0x00c0, 0x2be6, 0x6068, 0xa24e, - 0x0040, 0x2541, 0xa9cc, 0xff00, 0x0040, 0x2541, 0x0c7e, 0x1078, - 0x2c5a, 0x2c68, 0x0c7f, 0x0040, 0x2c0d, 0xa0c6, 0x4000, 0x00c0, - 0x2bf3, 0x0078, 0x2c0a, 0xa0c6, 0x4007, 0x00c0, 0x2bfa, 0x2408, - 0x0078, 0x2c0a, 0xa0c6, 0x4008, 0x00c0, 0x2c02, 0x2708, 0x2610, - 0x0078, 0x2c0a, 0xa0c6, 0x4009, 0x00c0, 0x2c08, 0x0078, 0x2c0a, - 0x2001, 0x4006, 0x2020, 0x0078, 0x2515, 0x017e, 0x0b7e, 0x0c7e, - 0x0e7e, 0x2c70, 0x1078, 0x5b9c, 0x0040, 0x2c48, 0x2d00, 0x601a, - 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x2cfb, 0x0c7f, 0x2b70, - 0x0040, 0x253d, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, - 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x22bb, - 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x127e, 0x2091, 0x8000, 0x7088, 0x8000, - 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c29, 0xa085, 0x0001, - 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x0040, 0x253d, 0x7007, 0x0003, - 0x701b, 0x2c53, 0x007c, 0x6830, 0xa086, 0x0100, 0x00c0, 0x2513, - 0x0078, 0x253d, 0x0e7e, 0x0d7e, 0x2029, 0x0000, 0x2021, 0x0080, - 0x20a9, 0x007f, 0x2071, 0x77a0, 0x2e04, 0xa005, 0x00c0, 0x2c6e, - 0x2100, 0xa406, 0x0040, 0x2cab, 0x0078, 0x2c9f, 0x2068, 0x6f10, - 0x2700, 0xa306, 0x00c0, 0x2c90, 0x6e14, 0x2600, 0xa206, 0x00c0, - 0x2c90, 0x2400, 0xa106, 0x00c0, 0x2c8c, 0x2d60, 0xd884, 0x0040, - 0x2cb1, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2cb1, - 0x2001, 0x4000, 0x0078, 0x2cb2, 0x2001, 0x4007, 0x0078, 0x2cb2, - 0x2400, 0xa106, 0x00c0, 0x2c9f, 0x6e14, 0x87ff, 0x00c0, 0x2c9b, - 0x86ff, 0x0040, 0x2cab, 0x2001, 0x4008, 0x0078, 0x2cb2, 0x8420, - 0x8e70, 0x00f0, 0x2c64, 0x2001, 0x4009, 0x0078, 0x2cb2, 0x2001, - 0x0001, 0x0078, 0x2cb2, 0x1078, 0x37ee, 0x00c0, 0x2ca7, 0x6312, - 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, - 0x253d, 0x1078, 0x2cfb, 0x0040, 0x253d, 0x6837, 0x0000, 0x7824, - 0xa005, 0x0040, 0x2541, 0xa096, 0x00ff, 0x0040, 0x2ccb, 0xa092, - 0x0004, 0x00c8, 0x2541, 0x2010, 0x2d18, 0x1078, 0x227d, 0x0040, - 0x253d, 0x7007, 0x0003, 0x701b, 0x2cd6, 0x007c, 0x6830, 0xa086, - 0x0100, 0x0040, 0x253d, 0x0078, 0x2513, 0x81ff, 0x00c0, 0x253d, - 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, 0x2541, - 0xa182, 0x00ff, 0x00c8, 0x2541, 0x127e, 0x2091, 0x8000, 0x1078, - 0x697f, 0x00c0, 0x2cf8, 0x1078, 0x380d, 0x127f, 0x0078, 0x2513, - 0x127f, 0x0078, 0x253d, 0x1078, 0x132f, 0x0040, 0x2d12, 0xa006, - 0x6802, 0x7010, 0xa005, 0x00c0, 0x2d0a, 0x2d00, 0x7012, 0x7016, - 0x0078, 0x2d10, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, - 0xad80, 0x000d, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x1078, - 0x3825, 0x00c0, 0x2d21, 0xa6b4, 0x00ff, 0xa682, 0x0010, 0x0048, - 0x2d22, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, 0x0040, - 0x2d2f, 0x2168, 0x6904, 0x1078, 0x1348, 0x0078, 0x2d26, 0x7112, - 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x2d39, 0x2031, - 0x0000, 0x2061, 0x76bd, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, - 0x642e, 0x6532, 0x2c10, 0x1078, 0x137f, 0x7007, 0x0002, 0x701b, - 0x2513, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0000, - 0x2001, 0x767b, 0x2004, 0xa005, 0x00c0, 0x2d65, 0x0068, 0x2d65, - 0x7818, 0xd084, 0x00c0, 0x2d65, 0x781b, 0x0001, 0x7a22, 0x7b26, - 0x7c2a, 0x2091, 0x4080, 0x0078, 0x2d8a, 0x017e, 0x0c7e, 0x0e7e, - 0x2071, 0x766d, 0x7138, 0xa182, 0x0008, 0x0048, 0x2d73, 0x7030, - 0x2060, 0x0078, 0x2d84, 0x7030, 0xa0e0, 0x0008, 0xac82, 0x76bd, - 0x0048, 0x2d7c, 0x2061, 0x767d, 0x2c00, 0x7032, 0x81ff, 0x00c0, - 0x2d82, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x0e7f, - 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, 0x766d, - 0x7038, 0xa005, 0x0040, 0x2dc6, 0x127e, 0x2091, 0x8000, 0x0068, - 0x2dc5, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x2dc4, - 0x0c7e, 0x781b, 0x0001, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, - 0x7826, 0x6008, 0x782a, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, - 0xa005, 0x00c0, 0x2dba, 0x7033, 0x767d, 0x7037, 0x767d, 0x0c7f, - 0x0078, 0x2dc4, 0xac80, 0x0008, 0xa0fa, 0x76bd, 0x0048, 0x2dc2, - 0x2001, 0x767d, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, 0x007c, - 0x027e, 0x2001, 0x7652, 0x2004, 0xd0c4, 0x0040, 0x2dd3, 0x2011, - 0x8014, 0x1078, 0x2d4a, 0x027f, 0x007c, 0x81ff, 0x00c0, 0x253d, - 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x1078, 0x357b, - 0x127f, 0x0078, 0x2513, 0x7824, 0x2008, 0xa18c, 0xfffd, 0x00c0, - 0x2dee, 0x61c8, 0xa10d, 0x61ca, 0x0078, 0x2513, 0x0078, 0x2541, - 0x81ff, 0x00c0, 0x253d, 0x6000, 0xa086, 0x0003, 0x00c0, 0x253d, - 0x2001, 0x7652, 0x2004, 0xd0a4, 0x00c0, 0x253d, 0x1078, 0x2d13, - 0x0040, 0x2541, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, - 0x2e0d, 0x7828, 0xa005, 0x0040, 0x2513, 0x0c7e, 0x1078, 0x2cfb, - 0x0c7f, 0x0040, 0x253d, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, - 0xc0fd, 0x683a, 0x1078, 0x6ae6, 0x0040, 0x253d, 0x7007, 0x0003, - 0x701b, 0x2e23, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x253d, - 0x0078, 0x2513, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x253d, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x2cfb, - 0x0040, 0x253d, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, - 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, 0x3825, - 0x00c0, 0x2e70, 0x6004, 0xa0c6, 0x0707, 0x0040, 0x2e70, 0xa084, - 0x00ff, 0xa0c6, 0x0006, 0x00c0, 0x2e70, 0x87ff, 0x0040, 0x2e63, - 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, - 0x2bb2, 0x0078, 0x2e6c, 0xac80, 0x000a, 0x2098, 0x3400, 0x20a9, - 0x0004, 0x53a3, 0x1078, 0x2bb2, 0x21a2, 0x94a0, 0xa6b0, 0x0005, - 0x8108, 0xa186, 0x007e, 0x0040, 0x2e7b, 0xa686, 0x0028, 0x0040, - 0x2e84, 0x0078, 0x2e46, 0x86ff, 0x00c0, 0x2e82, 0x7120, 0x810b, - 0x0078, 0x2513, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, - 0x772a, 0x2061, 0x76bd, 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, - 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x137f, 0x7007, - 0x0002, 0x701b, 0x2e9c, 0x007c, 0x702c, 0xa005, 0x00c0, 0x2eae, - 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0x76bd, - 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x2e46, 0x7120, 0x810b, - 0x0078, 0x2513, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, 0x2071, - 0x7600, 0x6044, 0xd0a4, 0x00c0, 0x2edb, 0xd084, 0x0040, 0x2ec4, - 0x1078, 0x3004, 0x0078, 0x2ed7, 0xd08c, 0x0040, 0x2ecb, 0x1078, - 0x2f1b, 0x0078, 0x2ed7, 0xd094, 0x0040, 0x2ed2, 0x1078, 0x2efe, - 0x0078, 0x2ed7, 0xd09c, 0x0040, 0x2ed7, 0x1078, 0x2ee5, 0x0e7f, - 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, 0x2ee2, - 0xc19d, 0x612a, 0x017f, 0x0078, 0x2ed7, 0x6043, 0x0040, 0x6043, - 0x0000, 0x706f, 0x0000, 0x7087, 0x0001, 0x70a7, 0x0000, 0x2009, - 0x7cc0, 0x200b, 0x0000, 0x707f, 0x0000, 0x7073, 0x000f, 0x2009, - 0x000f, 0x2011, 0x353b, 0x1078, 0x45fe, 0x007c, 0x7070, 0xa005, - 0x00c0, 0x2f1a, 0x2011, 0x353b, 0x1078, 0x456e, 0x6043, 0x0020, - 0x6043, 0x0000, 0x6044, 0xd08c, 0x00c0, 0x2f16, 0x7083, 0x0000, - 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x2f1a, 0x7077, 0x0000, - 0x0078, 0x2f1a, 0x007c, 0x7074, 0xa08a, 0x0003, 0x00c8, 0x2f24, - 0x1079, 0x2f27, 0x0078, 0x2f26, 0x1078, 0x12d5, 0x007c, 0x2f2a, - 0x2f79, 0x3003, 0x0f7e, 0x7077, 0x0001, 0x20e1, 0xa000, 0x20e1, - 0x8700, 0x1078, 0x1dea, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, - 0x7b00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, - 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f, - 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f, - 0x0000, 0x2079, 0x7b0c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, - 0x7605, 0x20a1, 0x7b0e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0x7b12, - 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0x7b00, 0x20a1, 0x020b, - 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x1078, - 0x3562, 0x0f7f, 0x707b, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, - 0x007c, 0x0d7e, 0x7078, 0x707b, 0x0000, 0xa025, 0x0040, 0x2fed, - 0x6020, 0xd0b4, 0x00c0, 0x2feb, 0x7184, 0x81ff, 0x0040, 0x2fd4, - 0xa486, 0x000c, 0x00c0, 0x2fdf, 0xa480, 0x0018, 0x8004, 0x20a8, - 0x2011, 0x7b80, 0x2019, 0x7b00, 0x220c, 0x2304, 0xa106, 0x00c0, - 0x2fab, 0x8210, 0x8318, 0x00f0, 0x2f94, 0x6043, 0x0004, 0x608b, - 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x7077, 0x0002, 0x7083, - 0x0002, 0x0078, 0x2feb, 0x2069, 0x7b80, 0x6930, 0xa18e, 0x1101, - 0x00c0, 0x2fdf, 0x6834, 0xa005, 0x00c0, 0x2fdf, 0x6900, 0xa18c, - 0x00ff, 0x00c0, 0x2fbf, 0x6804, 0xa005, 0x0040, 0x2fd4, 0x2011, - 0x7b8e, 0x2019, 0x7605, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, - 0x0048, 0x2fd2, 0x00c0, 0x2fdf, 0x8210, 0x8318, 0x00f0, 0x2fc5, - 0x0078, 0x2fdf, 0x7087, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, - 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x2feb, 0x60c3, - 0x000c, 0x1078, 0x3562, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0, - 0x2feb, 0x60c3, 0x000c, 0x2011, 0x7840, 0x2013, 0x0000, 0x707b, - 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, - 0x5579, 0x0078, 0x2feb, 0x007c, 0x7080, 0xa08a, 0x001d, 0x00c8, - 0x300d, 0x1079, 0x3010, 0x0078, 0x300f, 0x1078, 0x12d5, 0x007c, - 0x3034, 0x3043, 0x3074, 0x3089, 0x30b9, 0x30e1, 0x3111, 0x313b, - 0x316b, 0x3191, 0x31da, 0x31fc, 0x3220, 0x3236, 0x325e, 0x3271, - 0x327a, 0x3293, 0x32c1, 0x32e9, 0x3317, 0x3341, 0x3384, 0x33b5, - 0x33d7, 0x3415, 0x343b, 0x3454, 0x3461, 0x7003, 0x0007, 0x6004, - 0xa084, 0xfff9, 0x6006, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, - 0x6043, 0x0002, 0x7083, 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, - 0x1078, 0x4561, 0x007c, 0x0f7e, 0x7078, 0xa086, 0x0014, 0x00c0, - 0x3072, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3072, 0x2079, - 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3070, 0x7834, 0xa005, - 0x00c0, 0x3070, 0x7a38, 0xd2fc, 0x0040, 0x3066, 0x70a4, 0xa005, - 0x00c0, 0x3066, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x2011, 0x3542, - 0x1078, 0x456e, 0x7083, 0x0010, 0x1078, 0x327a, 0x0078, 0x3072, - 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0003, 0x6043, 0x0004, - 0x1078, 0x35cc, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, - 0x20a3, 0x0000, 0x00f0, 0x3080, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x30b7, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x30b3, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1102, 0x00c0, 0x30b3, 0x7834, 0xa005, 0x00c0, - 0x30b3, 0x7a38, 0xd2fc, 0x0040, 0x30ad, 0x70a4, 0xa005, 0x00c0, - 0x30ad, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0004, 0x1078, - 0x30b9, 0x0078, 0x30b7, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0005, 0x1078, 0x35cc, 0x20a3, 0x1103, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x30d3, - 0x714c, 0xa186, 0xffff, 0x0040, 0x30d3, 0x1078, 0x3506, 0x0040, - 0x30d3, 0x1078, 0x35fb, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x310f, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x310b, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1103, 0x00c0, 0x310b, 0x7834, 0xa005, 0x00c0, - 0x310b, 0x7a38, 0xd2fc, 0x0040, 0x3105, 0x70a4, 0xa005, 0x00c0, - 0x3105, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0006, 0x1078, - 0x3111, 0x0078, 0x310f, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0007, 0x1078, 0x35cc, 0x20a3, 0x1104, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x312d, - 0x7150, 0xa186, 0xffff, 0x0040, 0x312d, 0xa180, 0x232f, 0x200c, - 0xa18c, 0xff00, 0x810f, 0x1078, 0x3506, 0x20a9, 0x0008, 0x2298, - 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3169, - 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3165, - 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3165, 0x7834, - 0xa005, 0x00c0, 0x3165, 0x7a38, 0xd2fc, 0x0040, 0x315f, 0x70a4, - 0xa005, 0x00c0, 0x315f, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x0008, 0x1078, 0x316b, 0x0078, 0x3169, 0x7083, 0x0002, 0x707b, - 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0009, 0x1078, 0x35cc, 0x20a3, - 0x1105, 0x20a3, 0x0100, 0x3430, 0x706c, 0xa005, 0x00c0, 0x317e, - 0x1078, 0x3470, 0x0040, 0x318e, 0x0078, 0x3188, 0x20a9, 0x0008, - 0x2099, 0x7b8e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x1078, 0x3562, 0x0078, 0x3190, 0x1078, 0x302d, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x31d8, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x31d4, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1105, 0x00c0, 0x31d4, 0x7834, 0x2011, 0x0100, - 0xa21e, 0x00c0, 0x31bd, 0x7a38, 0xd2fc, 0x0040, 0x31b7, 0x70a4, - 0xa005, 0x00c0, 0x31b7, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x000a, 0x1078, 0x31da, 0x0078, 0x31d8, 0xa005, 0x00c0, 0x31d4, - 0x7a38, 0xd2fc, 0x0040, 0x31cc, 0x70a4, 0xa005, 0x00c0, 0x31cc, - 0x1078, 0x35fb, 0x70a7, 0x0001, 0x707f, 0x0000, 0x7083, 0x000e, - 0x1078, 0x325e, 0x0078, 0x31d8, 0x7083, 0x0002, 0x707b, 0x0000, - 0x0f7f, 0x007c, 0x7083, 0x000b, 0x2011, 0x7b0e, 0x22a0, 0x20a9, - 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, - 0x41a4, 0x1078, 0x35cc, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x6030, - 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, - 0x321e, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, 0x00c0, - 0x321a, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x321a, - 0x7834, 0xa005, 0x00c0, 0x321a, 0x7083, 0x000c, 0x1078, 0x3220, - 0x0078, 0x321e, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, - 0x7083, 0x000d, 0x1078, 0x35cc, 0x20a3, 0x1107, 0x20a3, 0x0000, - 0x2099, 0x7b8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, - 0xa005, 0x0040, 0x325c, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, - 0x0084, 0x00c0, 0x3258, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, - 0x00c0, 0x3258, 0x7834, 0xa005, 0x00c0, 0x3258, 0x707f, 0x0001, - 0x1078, 0x35be, 0x7083, 0x000e, 0x1078, 0x325e, 0x0078, 0x325c, - 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000f, - 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, - 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, - 0x007c, 0x7078, 0xa005, 0x0040, 0x3279, 0x2011, 0x3542, 0x1078, - 0x456e, 0x007c, 0x7083, 0x0011, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, - 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, - 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x32bf, - 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x32bd, - 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x32bd, 0x7834, - 0xa005, 0x00c0, 0x32bd, 0x7a38, 0xd2fc, 0x0040, 0x32b7, 0x70a4, - 0xa005, 0x00c0, 0x32b7, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, - 0x0012, 0x1078, 0x32c1, 0x0078, 0x32bf, 0x707b, 0x0000, 0x0f7f, - 0x007c, 0x7083, 0x0013, 0x1078, 0x35d8, 0x20a3, 0x1103, 0x20a3, - 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa005, 0x00c0, 0x32db, - 0x714c, 0xa186, 0xffff, 0x0040, 0x32db, 0x1078, 0x3506, 0x0040, - 0x32db, 0x1078, 0x35fb, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3315, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3313, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3313, 0x7834, 0xa005, 0x00c0, - 0x3313, 0x7a38, 0xd2fc, 0x0040, 0x330d, 0x70a4, 0xa005, 0x00c0, - 0x330d, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x7083, 0x0014, 0x1078, - 0x3317, 0x0078, 0x3315, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, - 0x0015, 0x1078, 0x35d8, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, - 0x2011, 0x7b8e, 0x706c, 0xa006, 0x00c0, 0x3333, 0x7150, 0xa186, - 0xffff, 0x0040, 0x3333, 0xa180, 0x232f, 0x200c, 0xa18c, 0xff00, - 0x810f, 0x1078, 0x3506, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x3382, 0x2011, 0x3542, - 0x1078, 0x456e, 0xa086, 0x0014, 0x00c0, 0x3380, 0x2079, 0x7b80, - 0x7a30, 0xa296, 0x1105, 0x00c0, 0x3380, 0x7834, 0x2011, 0x0100, - 0xa21e, 0x00c0, 0x3369, 0x7a38, 0xd2fc, 0x0040, 0x3367, 0x70a4, - 0xa005, 0x00c0, 0x3367, 0x1078, 0x35fb, 0x70a7, 0x0001, 0x0078, - 0x337a, 0xa005, 0x00c0, 0x3380, 0x7a38, 0xd2fc, 0x0040, 0x3378, - 0x70a4, 0xa005, 0x00c0, 0x3378, 0x1078, 0x35fb, 0x70a7, 0x0001, - 0x707f, 0x0000, 0x7083, 0x0016, 0x1078, 0x3384, 0x0078, 0x3382, + 0xa0be, 0x0100, 0x0040, 0x2b59, 0xa0be, 0x0112, 0x0040, 0x2b59, + 0xa0be, 0x0113, 0x0040, 0x2b59, 0xa0be, 0x0114, 0x0040, 0x2b59, + 0xa0be, 0x0117, 0x0040, 0x2b59, 0xa0be, 0x011a, 0x0040, 0x2b59, + 0xa0be, 0x0121, 0x0040, 0x2b4f, 0xa0be, 0x0131, 0x0040, 0x2b4f, + 0xa0be, 0x0171, 0x0040, 0x2b59, 0xa0be, 0x0173, 0x0040, 0x2b59, + 0xa0be, 0x01a1, 0x00c0, 0x2b21, 0x6830, 0x8007, 0x6832, 0x0078, + 0x2b5f, 0xa0be, 0x0212, 0x0040, 0x2b55, 0xa0be, 0x0213, 0x0040, + 0x2b55, 0xa0be, 0x0214, 0x0040, 0x2b47, 0xa0be, 0x0217, 0x0040, + 0x2b41, 0xa0be, 0x021a, 0x00c0, 0x2b3a, 0x6838, 0x8007, 0x683a, + 0x0078, 0x2b59, 0xa0be, 0x0300, 0x0040, 0x2b59, 0x0d7f, 0x0078, + 0x253b, 0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x2b95, 0xad80, + 0x000e, 0x20a9, 0x0001, 0x1078, 0x2b95, 0x0078, 0x2b59, 0xad80, + 0x000c, 0x1078, 0x2ba3, 0x0078, 0x2b5f, 0xad80, 0x000e, 0x1078, + 0x2ba3, 0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x2b95, 0x0c7e, + 0x1078, 0x2cec, 0x0040, 0x2b8a, 0x6838, 0xc0fd, 0x683a, 0x6837, + 0x0119, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, + 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, + 0x0c7f, 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, + 0x0000, 0x1078, 0x6a52, 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, + 0x2b8e, 0x007c, 0x0c7f, 0x0d7f, 0x0078, 0x2537, 0x6820, 0xa086, + 0x8001, 0x0040, 0x2537, 0x0078, 0x250d, 0x017e, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x00f0, + 0x2b97, 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, + 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, 0x017f, + 0x007c, 0x81ff, 0x00c0, 0x2537, 0x7924, 0x2140, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x0080, 0x0048, 0x253b, 0xa182, 0x00ff, 0x00c8, + 0x253b, 0x7a2c, 0x7b28, 0x6064, 0xa306, 0x00c0, 0x2bd7, 0x6068, + 0xa24e, 0x0040, 0x253b, 0xa9cc, 0xff00, 0x0040, 0x253b, 0x0c7e, + 0x1078, 0x2c4b, 0x2c68, 0x0c7f, 0x0040, 0x2bfe, 0xa0c6, 0x4000, + 0x00c0, 0x2be4, 0x0078, 0x2bfb, 0xa0c6, 0x4007, 0x00c0, 0x2beb, + 0x2408, 0x0078, 0x2bfb, 0xa0c6, 0x4008, 0x00c0, 0x2bf3, 0x2708, + 0x2610, 0x0078, 0x2bfb, 0xa0c6, 0x4009, 0x00c0, 0x2bf9, 0x0078, + 0x2bfb, 0x2001, 0x4006, 0x2020, 0x0078, 0x250f, 0x017e, 0x0b7e, + 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x5b94, 0x0040, 0x2c39, 0x2d00, + 0x601a, 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x2cec, 0x0c7f, + 0x2b70, 0x0040, 0x2537, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, + 0x22b5, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x37b5, + 0x2001, 0x0002, 0x1078, 0x37c9, 0x127e, 0x2091, 0x8000, 0x7088, + 0x8000, 0x708a, 0x127f, 0x2009, 0x0002, 0x1078, 0x5c21, 0xa085, + 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x2c44, 0x007c, 0x6830, 0xa086, 0x0100, 0x00c0, + 0x250d, 0x0078, 0x2537, 0x0e7e, 0x0d7e, 0x2029, 0x0000, 0x2021, + 0x0080, 0x20a9, 0x007f, 0x2071, 0x77a0, 0x2e04, 0xa005, 0x00c0, + 0x2c5f, 0x2100, 0xa406, 0x0040, 0x2c9c, 0x0078, 0x2c90, 0x2068, + 0x6f10, 0x2700, 0xa306, 0x00c0, 0x2c81, 0x6e14, 0x2600, 0xa206, + 0x00c0, 0x2c81, 0x2400, 0xa106, 0x00c0, 0x2c7d, 0x2d60, 0xd884, + 0x0040, 0x2ca2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, + 0x2ca2, 0x2001, 0x4000, 0x0078, 0x2ca3, 0x2001, 0x4007, 0x0078, + 0x2ca3, 0x2400, 0xa106, 0x00c0, 0x2c90, 0x6e14, 0x87ff, 0x00c0, + 0x2c8c, 0x86ff, 0x0040, 0x2c9c, 0x2001, 0x4008, 0x0078, 0x2ca3, + 0x8420, 0x8e70, 0x00f0, 0x2c55, 0x2001, 0x4009, 0x0078, 0x2ca3, + 0x2001, 0x0001, 0x0078, 0x2ca3, 0x1078, 0x37e6, 0x00c0, 0x2c98, + 0x6312, 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, + 0x00c0, 0x2537, 0x1078, 0x2cec, 0x0040, 0x2537, 0x6837, 0x0000, + 0x7824, 0xa005, 0x0040, 0x253b, 0xa096, 0x00ff, 0x0040, 0x2cbc, + 0xa092, 0x0004, 0x00c8, 0x253b, 0x2010, 0x2d18, 0x1078, 0x2277, + 0x0040, 0x2537, 0x7007, 0x0003, 0x701b, 0x2cc7, 0x007c, 0x6830, + 0xa086, 0x0100, 0x0040, 0x2537, 0x0078, 0x250d, 0x81ff, 0x00c0, + 0x2537, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, + 0x253b, 0xa182, 0x00ff, 0x00c8, 0x253b, 0x127e, 0x2091, 0x8000, + 0x1078, 0x6979, 0x00c0, 0x2ce9, 0x1078, 0x3805, 0x127f, 0x0078, + 0x250d, 0x127f, 0x0078, 0x2537, 0x1078, 0x1327, 0x0040, 0x2d03, + 0xa006, 0x6802, 0x7010, 0xa005, 0x00c0, 0x2cfb, 0x2d00, 0x7012, + 0x7016, 0x0078, 0x2d01, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, + 0x7016, 0xad80, 0x000d, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, + 0x1078, 0x381d, 0x00c0, 0x2d12, 0xa6b4, 0x00ff, 0xa682, 0x0010, + 0x0048, 0x2d13, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, + 0x0040, 0x2d20, 0x2168, 0x6904, 0x1078, 0x1340, 0x0078, 0x2d17, + 0x7112, 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x2d2a, + 0x2031, 0x0000, 0x2061, 0x76bd, 0x6606, 0x6112, 0x600e, 0x6226, + 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x1377, 0x7007, 0x0002, + 0x701b, 0x250d, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, + 0x0000, 0x2001, 0x767b, 0x2004, 0xa005, 0x00c0, 0x2d56, 0x0068, + 0x2d56, 0x7818, 0xd084, 0x00c0, 0x2d56, 0x781b, 0x0001, 0x7a22, + 0x7b26, 0x7c2a, 0x2091, 0x4080, 0x0078, 0x2d7b, 0x017e, 0x0c7e, + 0x0e7e, 0x2071, 0x766d, 0x7138, 0xa182, 0x0008, 0x0048, 0x2d64, + 0x7030, 0x2060, 0x0078, 0x2d75, 0x7030, 0xa0e0, 0x0008, 0xac82, + 0x76bd, 0x0048, 0x2d6d, 0x2061, 0x767d, 0x2c00, 0x7032, 0x81ff, + 0x00c0, 0x2d73, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, + 0x0e7f, 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, + 0x766d, 0x7038, 0xa005, 0x0040, 0x2db7, 0x127e, 0x2091, 0x8000, + 0x0068, 0x2db6, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, + 0x2db5, 0x0c7e, 0x781b, 0x0001, 0x7034, 0x2060, 0x2c04, 0x7822, + 0x6004, 0x7826, 0x6008, 0x782a, 0x2091, 0x4080, 0x7038, 0x8001, + 0x703a, 0xa005, 0x00c0, 0x2dab, 0x7033, 0x767d, 0x7037, 0x767d, + 0x0c7f, 0x0078, 0x2db5, 0xac80, 0x0008, 0xa0fa, 0x76bd, 0x0048, + 0x2db3, 0x2001, 0x767d, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, + 0x007c, 0x027e, 0x2001, 0x7652, 0x2004, 0xd0c4, 0x0040, 0x2dc4, + 0x2011, 0x8014, 0x1078, 0x2d3b, 0x027f, 0x007c, 0x81ff, 0x00c0, + 0x2537, 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x1078, + 0x3573, 0x127f, 0x0078, 0x250d, 0x7824, 0x2008, 0xa18c, 0xfffd, + 0x00c0, 0x2ddf, 0x61c8, 0xa10d, 0x61ca, 0x0078, 0x250d, 0x0078, + 0x253b, 0x81ff, 0x00c0, 0x2537, 0x6000, 0xa086, 0x0003, 0x00c0, + 0x2537, 0x2001, 0x7652, 0x2004, 0xd0a4, 0x00c0, 0x2537, 0x1078, + 0x2d04, 0x0040, 0x253b, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x00c0, 0x2dfe, 0x7828, 0xa005, 0x0040, 0x250d, 0x0c7e, 0x1078, + 0x2cec, 0x0c7f, 0x0040, 0x2537, 0x6837, 0x0000, 0x6833, 0x0000, + 0x6838, 0xc0fd, 0x683a, 0x1078, 0x6adb, 0x0040, 0x2537, 0x7007, + 0x0003, 0x701b, 0x2e14, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, + 0x2537, 0x0078, 0x250d, 0x2001, 0x7600, 0x2004, 0xa086, 0x0003, + 0x00c0, 0x2537, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, + 0x2cec, 0x0040, 0x2537, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, + 0x0000, 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, + 0x381d, 0x00c0, 0x2e61, 0x6004, 0xa0c6, 0x0707, 0x0040, 0x2e61, + 0xa084, 0x00ff, 0xa0c6, 0x0006, 0x00c0, 0x2e61, 0x87ff, 0x0040, + 0x2e54, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, + 0x1078, 0x2ba3, 0x0078, 0x2e5d, 0xac80, 0x000a, 0x2098, 0x3400, + 0x20a9, 0x0004, 0x53a3, 0x1078, 0x2ba3, 0x21a2, 0x94a0, 0xa6b0, + 0x0005, 0x8108, 0xa186, 0x007e, 0x0040, 0x2e6c, 0xa686, 0x0028, + 0x0040, 0x2e75, 0x0078, 0x2e37, 0x86ff, 0x00c0, 0x2e73, 0x7120, + 0x810b, 0x0078, 0x250d, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, + 0x7022, 0x772a, 0x2061, 0x76bd, 0x6007, 0x0000, 0x6612, 0x7024, + 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x1377, + 0x7007, 0x0002, 0x701b, 0x2e8d, 0x007c, 0x702c, 0xa005, 0x00c0, + 0x2e9f, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, + 0x76bd, 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x2e37, 0x7120, + 0x810b, 0x0078, 0x250d, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, + 0x2071, 0x7600, 0x6044, 0xd0a4, 0x00c0, 0x2ecc, 0xd084, 0x0040, + 0x2eb5, 0x1078, 0x2ff7, 0x0078, 0x2ec8, 0xd08c, 0x0040, 0x2ebc, + 0x1078, 0x2f0e, 0x0078, 0x2ec8, 0xd094, 0x0040, 0x2ec3, 0x1078, + 0x2ef1, 0x0078, 0x2ec8, 0xd09c, 0x0040, 0x2ec8, 0x1078, 0x2ed6, + 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, + 0x2ed3, 0xc19d, 0x612a, 0x017f, 0x0078, 0x2ec8, 0x6043, 0x0040, + 0x6043, 0x0000, 0x706f, 0x0000, 0x7087, 0x0001, 0x70a7, 0x0000, + 0x70bf, 0x0000, 0x2009, 0x7cc0, 0x200b, 0x0000, 0x707f, 0x0000, + 0x7073, 0x000f, 0x2009, 0x000f, 0x2011, 0x3533, 0x1078, 0x45f6, + 0x007c, 0x7070, 0xa005, 0x00c0, 0x2f0d, 0x2011, 0x3533, 0x1078, + 0x4566, 0x6043, 0x0020, 0x6043, 0x0000, 0x6044, 0xd08c, 0x00c0, + 0x2f09, 0x7083, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, + 0x2f0d, 0x7077, 0x0000, 0x0078, 0x2f0d, 0x007c, 0x7074, 0xa08a, + 0x0003, 0x00c8, 0x2f17, 0x1079, 0x2f1a, 0x0078, 0x2f19, 0x1078, + 0x12cd, 0x007c, 0x2f1d, 0x2f6c, 0x2ff6, 0x0f7e, 0x7077, 0x0001, + 0x20e1, 0xa000, 0x20e1, 0x8700, 0x1078, 0x1de4, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2079, 0x7b00, 0x207b, 0x2200, 0x7807, 0x00ef, + 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, + 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, + 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0x7b0c, 0x207b, 0x1101, + 0x7807, 0x0000, 0x2099, 0x7605, 0x20a1, 0x7b0e, 0x20a9, 0x0004, + 0x53a3, 0x2079, 0x7b12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, + 0x7b00, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, + 0x600f, 0x0000, 0x1078, 0x355a, 0x0f7f, 0x707b, 0x0000, 0x6043, + 0x0008, 0x6043, 0x0000, 0x007c, 0x0d7e, 0x7078, 0x707b, 0x0000, + 0xa025, 0x0040, 0x2fe0, 0x6020, 0xd0b4, 0x00c0, 0x2fde, 0x7184, + 0x81ff, 0x0040, 0x2fc7, 0xa486, 0x000c, 0x00c0, 0x2fd2, 0xa480, + 0x0018, 0x8004, 0x20a8, 0x2011, 0x7b80, 0x2019, 0x7b00, 0x220c, + 0x2304, 0xa106, 0x00c0, 0x2f9e, 0x8210, 0x8318, 0x00f0, 0x2f87, + 0x6043, 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, + 0x7077, 0x0002, 0x7083, 0x0002, 0x0078, 0x2fde, 0x2069, 0x7b80, + 0x6930, 0xa18e, 0x1101, 0x00c0, 0x2fd2, 0x6834, 0xa005, 0x00c0, + 0x2fd2, 0x6900, 0xa18c, 0x00ff, 0x00c0, 0x2fb2, 0x6804, 0xa005, + 0x0040, 0x2fc7, 0x2011, 0x7b8e, 0x2019, 0x7605, 0x20a9, 0x0004, + 0x220c, 0x2304, 0xa102, 0x0048, 0x2fc5, 0x00c0, 0x2fd2, 0x8210, + 0x8318, 0x00f0, 0x2fb8, 0x0078, 0x2fd2, 0x7087, 0x0000, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, + 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, + 0x00c0, 0x2fde, 0x60c3, 0x000c, 0x1078, 0x355a, 0x0d7f, 0x007c, + 0x6020, 0xd0b4, 0x00c0, 0x2fde, 0x60c3, 0x000c, 0x2011, 0x7840, + 0x2013, 0x0000, 0x707b, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, + 0x60a7, 0x9575, 0x1078, 0x5571, 0x0078, 0x2fde, 0x007c, 0x7080, + 0xa08a, 0x001d, 0x00c8, 0x3000, 0x1079, 0x3003, 0x0078, 0x3002, + 0x1078, 0x12cd, 0x007c, 0x3027, 0x3036, 0x3067, 0x307c, 0x30ac, + 0x30d4, 0x3104, 0x312e, 0x315e, 0x3184, 0x31cd, 0x31ef, 0x3213, + 0x3229, 0x3251, 0x3264, 0x326d, 0x3286, 0x32b4, 0x32dc, 0x330a, + 0x3334, 0x337c, 0x33ad, 0x33cf, 0x340d, 0x3433, 0x344c, 0x3459, + 0x7003, 0x0007, 0x6004, 0xa084, 0xfff9, 0x6006, 0x007c, 0x608b, + 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, 0x7083, 0x0001, 0x2009, + 0x07d0, 0x2011, 0x353a, 0x1078, 0x4559, 0x007c, 0x0f7e, 0x7078, + 0xa086, 0x0014, 0x00c0, 0x3065, 0x6043, 0x0000, 0x6020, 0xd0b4, + 0x00c0, 0x3065, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, + 0x3063, 0x7834, 0xa005, 0x00c0, 0x3063, 0x7a38, 0xd2fc, 0x0040, + 0x3059, 0x70a4, 0xa005, 0x00c0, 0x3059, 0x1078, 0x35f3, 0x70a7, + 0x0001, 0x2011, 0x353a, 0x1078, 0x4566, 0x7083, 0x0010, 0x1078, + 0x326d, 0x0078, 0x3065, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, + 0x0003, 0x6043, 0x0004, 0x1078, 0x35c4, 0x20a3, 0x1102, 0x20a3, + 0x0000, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x3073, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x30aa, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x30a6, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x30a6, + 0x7834, 0xa005, 0x00c0, 0x30a6, 0x7a38, 0xd2fc, 0x0040, 0x30a0, + 0x70a4, 0xa005, 0x00c0, 0x30a0, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0004, 0x1078, 0x30ac, 0x0078, 0x30aa, 0x7083, 0x0002, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0005, 0x1078, 0x35c4, + 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x30c6, 0x714c, 0xa186, 0xffff, 0x0040, 0x30c6, + 0x1078, 0x34fe, 0x0040, 0x30c6, 0x1078, 0x35f3, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x3102, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x30fe, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x30fe, + 0x7834, 0xa005, 0x00c0, 0x30fe, 0x7a38, 0xd2fc, 0x0040, 0x30f8, + 0x70a4, 0xa005, 0x00c0, 0x30f8, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0006, 0x1078, 0x3104, 0x0078, 0x3102, 0x7083, 0x0002, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0007, 0x1078, 0x35c4, + 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x3120, 0x7150, 0xa186, 0xffff, 0x0040, 0x3120, + 0xa180, 0x2329, 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x34fe, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, + 0xa005, 0x0040, 0x315c, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, + 0x0014, 0x00c0, 0x3158, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, + 0x00c0, 0x3158, 0x7834, 0xa005, 0x00c0, 0x3158, 0x7a38, 0xd2fc, + 0x0040, 0x3152, 0x70a4, 0xa005, 0x00c0, 0x3152, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x0008, 0x1078, 0x315e, 0x0078, 0x315c, + 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0009, + 0x1078, 0x35c4, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x706c, + 0xa005, 0x00c0, 0x3171, 0x1078, 0x3468, 0x0040, 0x3181, 0x0078, + 0x317b, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, 0x0078, + 0x3183, 0x1078, 0x3020, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x31cb, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x31c7, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1105, 0x00c0, 0x31c7, + 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x31b0, 0x7a38, 0xd2fc, + 0x0040, 0x31aa, 0x70a4, 0xa005, 0x00c0, 0x31aa, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x000a, 0x1078, 0x31cd, 0x0078, 0x31cb, + 0xa005, 0x00c0, 0x31c7, 0x7a38, 0xd2fc, 0x0040, 0x31bf, 0x70a4, + 0xa005, 0x00c0, 0x31bf, 0x1078, 0x35f3, 0x70a7, 0x0001, 0x707f, + 0x0000, 0x7083, 0x000e, 0x1078, 0x3251, 0x0078, 0x31cb, 0x7083, + 0x0002, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000b, 0x2011, + 0x7b0e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, + 0x0002, 0x2009, 0x0000, 0x41a4, 0x1078, 0x35c4, 0x20a3, 0x1106, + 0x20a3, 0x0000, 0x6030, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, + 0x0042, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x355a, 0x007c, 0x0f7e, + 0x7078, 0xa005, 0x0040, 0x3211, 0x2011, 0x353a, 0x1078, 0x4566, + 0xa086, 0x0084, 0x00c0, 0x320d, 0x2079, 0x7b80, 0x7a30, 0xa296, + 0x1106, 0x00c0, 0x320d, 0x7834, 0xa005, 0x00c0, 0x320d, 0x7083, + 0x000c, 0x1078, 0x3213, 0x0078, 0x3211, 0x7083, 0x0002, 0x707b, + 0x0000, 0x0f7f, 0x007c, 0x7083, 0x000d, 0x1078, 0x35c4, 0x20a3, + 0x1107, 0x20a3, 0x0000, 0x2099, 0x7b8e, 0x20a9, 0x0040, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x1078, 0x355a, + 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, 0x324f, 0x2011, 0x353a, + 0x1078, 0x4566, 0xa086, 0x0084, 0x00c0, 0x324b, 0x2079, 0x7b80, + 0x7a30, 0xa296, 0x1107, 0x00c0, 0x324b, 0x7834, 0xa005, 0x00c0, + 0x324b, 0x707f, 0x0001, 0x1078, 0x35b6, 0x7083, 0x000e, 0x1078, + 0x3251, 0x0078, 0x324f, 0x7083, 0x0002, 0x707b, 0x0000, 0x0f7f, + 0x007c, 0x7083, 0x000f, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, + 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, + 0x353a, 0x1078, 0x4559, 0x007c, 0x7078, 0xa005, 0x0040, 0x326c, + 0x2011, 0x353a, 0x1078, 0x4566, 0x007c, 0x7083, 0x0011, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, + 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, + 0x53a6, 0x60c3, 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, + 0xa005, 0x0040, 0x32b2, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, + 0x0014, 0x00c0, 0x32b0, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1103, + 0x00c0, 0x32b0, 0x7834, 0xa005, 0x00c0, 0x32b0, 0x7a38, 0xd2fc, + 0x0040, 0x32aa, 0x70a4, 0xa005, 0x00c0, 0x32aa, 0x1078, 0x35f3, + 0x70a7, 0x0001, 0x7083, 0x0012, 0x1078, 0x32b4, 0x0078, 0x32b2, + 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x0013, 0x1078, 0x35d0, + 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, + 0xa005, 0x00c0, 0x32ce, 0x714c, 0xa186, 0xffff, 0x0040, 0x32ce, + 0x1078, 0x34fe, 0x0040, 0x32ce, 0x1078, 0x35f3, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x3308, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x3306, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3306, + 0x7834, 0xa005, 0x00c0, 0x3306, 0x7a38, 0xd2fc, 0x0040, 0x3300, + 0x70a4, 0xa005, 0x00c0, 0x3300, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x7083, 0x0014, 0x1078, 0x330a, 0x0078, 0x3308, 0x707b, 0x0000, + 0x0f7f, 0x007c, 0x7083, 0x0015, 0x1078, 0x35d0, 0x20a3, 0x1104, + 0x20a3, 0x0000, 0x3430, 0x2011, 0x7b8e, 0x706c, 0xa006, 0x00c0, + 0x3326, 0x7150, 0xa186, 0xffff, 0x0040, 0x3326, 0xa180, 0x2329, + 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x34fe, 0x20a9, 0x0008, + 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0014, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, 0x0040, + 0x337a, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0014, 0x00c0, + 0x3378, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1105, 0x00c0, 0x3378, + 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x3361, 0x7a38, 0xd2f4, + 0x0040, 0x3354, 0x70bf, 0x0008, 0xd2fc, 0x0040, 0x335f, 0x70a4, + 0xa005, 0x00c0, 0x335f, 0x1078, 0x35f3, 0x70a7, 0x0001, 0x0078, + 0x3372, 0xa005, 0x00c0, 0x3378, 0x7a38, 0xd2fc, 0x0040, 0x3370, + 0x70a4, 0xa005, 0x00c0, 0x3370, 0x1078, 0x35f3, 0x70a7, 0x0001, + 0x707f, 0x0000, 0x7083, 0x0016, 0x1078, 0x337c, 0x0078, 0x337a, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, 0x3430, - 0x2011, 0x7b8e, 0x7083, 0x0017, 0x0078, 0x3398, 0x7083, 0x001b, - 0x706c, 0xa005, 0x00c0, 0x33a2, 0x1078, 0x3470, 0x0040, 0x33b2, - 0x0078, 0x33ac, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x3562, - 0x0078, 0x33b4, 0x1078, 0x302d, 0x007c, 0x0f7e, 0x7078, 0xa005, - 0x0040, 0x33d5, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, - 0x00c0, 0x33d3, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, - 0x33d3, 0x7834, 0xa005, 0x00c0, 0x33d3, 0x7083, 0x0018, 0x1078, - 0x33d7, 0x0078, 0x33d5, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, - 0x0019, 0x1078, 0x35d8, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, + 0x2011, 0x7b8e, 0x7083, 0x0017, 0x0078, 0x3390, 0x7083, 0x001b, + 0x706c, 0xa005, 0x00c0, 0x339a, 0x1078, 0x3468, 0x0040, 0x33aa, + 0x0078, 0x33a4, 0x20a9, 0x0008, 0x2099, 0x7b8e, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x355a, + 0x0078, 0x33ac, 0x1078, 0x3020, 0x007c, 0x0f7e, 0x7078, 0xa005, + 0x0040, 0x33cd, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0084, + 0x00c0, 0x33cb, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1106, 0x00c0, + 0x33cb, 0x7834, 0xa005, 0x00c0, 0x33cb, 0x7083, 0x0018, 0x1078, + 0x33cf, 0x0078, 0x33cd, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, + 0x0019, 0x1078, 0x35d0, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, 0x7b8e, 0x2039, 0x7b0e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x6030, 0x2310, 0x8214, 0xa2a0, - 0x7b0e, 0x2414, 0xa38c, 0x0001, 0x0040, 0x3402, 0xa294, 0xff00, - 0x0078, 0x3405, 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, + 0x7b0e, 0x2414, 0xa38c, 0x0001, 0x0040, 0x33fa, 0xa294, 0xff00, + 0x0078, 0x33fd, 0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0084, 0x1078, 0x3562, 0x007c, 0x0f7e, 0x7078, 0xa005, - 0x0040, 0x3439, 0x2011, 0x3542, 0x1078, 0x456e, 0xa086, 0x0084, - 0x00c0, 0x3437, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, 0x00c0, - 0x3437, 0x7834, 0xa005, 0x00c0, 0x3437, 0x707f, 0x0001, 0x1078, - 0x35be, 0x7083, 0x001a, 0x1078, 0x343b, 0x0078, 0x3439, 0x707b, + 0x60c3, 0x0084, 0x1078, 0x355a, 0x007c, 0x0f7e, 0x7078, 0xa005, + 0x0040, 0x3431, 0x2011, 0x353a, 0x1078, 0x4566, 0xa086, 0x0084, + 0x00c0, 0x342f, 0x2079, 0x7b80, 0x7a30, 0xa296, 0x1107, 0x00c0, + 0x342f, 0x7834, 0xa005, 0x00c0, 0x342f, 0x707f, 0x0001, 0x1078, + 0x35b6, 0x7083, 0x001a, 0x1078, 0x3433, 0x0078, 0x3431, 0x707b, 0x0000, 0x0f7f, 0x007c, 0x7083, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x7478, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x3562, 0x007c, 0x7078, 0xa005, 0x0040, 0x3460, - 0x2011, 0x3542, 0x1078, 0x456e, 0x7083, 0x001c, 0x1078, 0x3461, + 0x0084, 0x1078, 0x355a, 0x007c, 0x7078, 0xa005, 0x0040, 0x3458, + 0x2011, 0x353a, 0x1078, 0x4566, 0x7083, 0x001c, 0x1078, 0x3459, 0x007c, 0x707b, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043, - 0x0001, 0x2009, 0x07d0, 0x2011, 0x3542, 0x1078, 0x4561, 0x007c, + 0x0001, 0x2009, 0x07d0, 0x2011, 0x353a, 0x1078, 0x4559, 0x007c, 0x087e, 0x097e, 0x2029, 0x7652, 0x252c, 0x20a9, 0x0008, 0x2041, 0x7b0e, 0x28a0, 0x2099, 0x7b8e, 0x53a3, 0x20a9, 0x0008, 0x2011, - 0x0007, 0xd5d4, 0x0040, 0x3486, 0x2011, 0x0000, 0x2800, 0xa200, - 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x3498, 0xd5d4, 0x0040, 0x3493, - 0x8210, 0x0078, 0x3494, 0x8211, 0x00f0, 0x3486, 0x0078, 0x34fd, - 0x82ff, 0x00c0, 0x34aa, 0xd5d4, 0x0040, 0x34a4, 0xa1a6, 0x3fff, - 0x0040, 0x3490, 0x0078, 0x34a8, 0xa1a6, 0x3fff, 0x0040, 0x34fd, + 0x0007, 0xd5d4, 0x0040, 0x347e, 0x2011, 0x0000, 0x2800, 0xa200, + 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x3490, 0xd5d4, 0x0040, 0x348b, + 0x8210, 0x0078, 0x348c, 0x8211, 0x00f0, 0x347e, 0x0078, 0x34f5, + 0x82ff, 0x00c0, 0x34a2, 0xd5d4, 0x0040, 0x349c, 0xa1a6, 0x3fff, + 0x0040, 0x3488, 0x0078, 0x34a0, 0xa1a6, 0x3fff, 0x0040, 0x34f5, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, 0x0040, - 0x34b3, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x34ba, 0x8423, - 0x0078, 0x34bb, 0x8424, 0x00c8, 0x34c8, 0xd5d4, 0x0040, 0x34c3, - 0x8319, 0x0078, 0x34c4, 0x8318, 0x00f0, 0x34b4, 0x0078, 0x34fd, - 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x34cc, 0x2328, - 0x8529, 0xa2be, 0x0007, 0x0040, 0x34e0, 0x007e, 0x2039, 0x0007, - 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, 0x34dc, - 0x754e, 0xa5c8, 0x232f, 0x292c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, + 0x34ab, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x34b2, 0x8423, + 0x0078, 0x34b3, 0x8424, 0x00c8, 0x34c0, 0xd5d4, 0x0040, 0x34bb, + 0x8319, 0x0078, 0x34bc, 0x8318, 0x00f0, 0x34ac, 0x0078, 0x34f5, + 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x34c4, 0x2328, + 0x8529, 0xa2be, 0x0007, 0x0040, 0x34d8, 0x007e, 0x2039, 0x0007, + 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, 0x34d4, + 0x754e, 0xa5c8, 0x2329, 0x292c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405, 0x201a, 0x706f, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0xa085, 0x0001, 0x0078, 0x3503, 0xa006, 0x0078, 0x3503, - 0xa006, 0x1078, 0x12d5, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, - 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x3513, 0x8420, - 0x8001, 0x0078, 0x350b, 0x2118, 0x84ff, 0x0040, 0x351c, 0xa39a, - 0x0010, 0x8421, 0x00c0, 0x3517, 0x2021, 0x0001, 0x83ff, 0x0040, - 0x3525, 0x8423, 0x8319, 0x00c0, 0x3521, 0xa238, 0x2704, 0xa42c, - 0x00c0, 0x353a, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x232f, 0x242c, + 0x0000, 0xa085, 0x0001, 0x0078, 0x34fb, 0xa006, 0x0078, 0x34fb, + 0xa006, 0x1078, 0x12cd, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, + 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x350b, 0x8420, + 0x8001, 0x0078, 0x3503, 0x2118, 0x84ff, 0x0040, 0x3514, 0xa39a, + 0x0010, 0x8421, 0x00c0, 0x350f, 0x2021, 0x0001, 0x83ff, 0x0040, + 0x351d, 0x8423, 0x8319, 0x00c0, 0x3519, 0xa238, 0x2704, 0xa42c, + 0x00c0, 0x3532, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x2329, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0001, 0xa084, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7073, 0x0000, 0x0e7f, 0x007c, 0x0e7e, 0x0f7e, 0x2079, 0x0100, 0x2071, 0x0140, - 0x1078, 0x5582, 0x7004, 0xa084, 0x4000, 0x0040, 0x3553, 0x7003, + 0x1078, 0x557a, 0x7004, 0xa084, 0x4000, 0x0040, 0x354b, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, 0x2091, 0x8000, 0x2071, 0x7620, 0x2073, 0x0000, 0x7843, 0x0090, 0x7843, 0x0010, 0x127f, 0x0f7f, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0x7840, 0x2013, 0x0000, 0x707b, 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, - 0x60a7, 0x9575, 0x1078, 0x5579, 0x2009, 0x07d0, 0x2011, 0x3542, - 0x1078, 0x45fe, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x2009, 0x00f7, 0x1078, 0x35e4, 0x2061, 0x7849, 0x601b, + 0x60a7, 0x9575, 0x1078, 0x5571, 0x2009, 0x07d0, 0x2011, 0x353a, + 0x1078, 0x45f6, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, + 0x8000, 0x2009, 0x00f7, 0x1078, 0x35dc, 0x2061, 0x7849, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x7600, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, - 0x35a0, 0x1078, 0x4561, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, + 0x3598, 0x1078, 0x4559, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x0100, 0x1078, - 0x5582, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0040, 0x35b4, - 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x202b, - 0x1078, 0x357b, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, + 0x557a, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, 0x0040, 0x35ac, + 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, 0x1078, 0x2025, + 0x1078, 0x3573, 0x127f, 0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, 0x20a1, 0x7cc0, 0x2099, 0x7b8e, 0x3304, 0x8007, 0x20a2, 0x9398, - 0x94a0, 0x00f0, 0x35c4, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x94a0, 0x00f0, 0x35bc, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b00, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x7b80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e, 0x2061, 0x0100, - 0x810f, 0x2001, 0x762c, 0x2004, 0xa005, 0x00c0, 0x35f5, 0x6030, - 0xa084, 0x00ff, 0xa105, 0x0078, 0x35f7, 0xa185, 0x00f7, 0x604a, + 0x810f, 0x2001, 0x762c, 0x2004, 0xa005, 0x00c0, 0x35ed, 0x6030, + 0xa084, 0x00ff, 0xa105, 0x0078, 0x35ef, 0xa185, 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, 0x017e, 0x047e, 0x2001, 0x7652, 0x2004, - 0xd0a4, 0x0040, 0x360e, 0xa006, 0x2020, 0x2009, 0x002a, 0x1078, - 0x7541, 0x2001, 0x760c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, - 0x1078, 0x2299, 0x047f, 0x017f, 0x007c, 0x157e, 0x20a9, 0x00ff, - 0x2009, 0x7720, 0xa006, 0x200a, 0x8108, 0x00f0, 0x361b, 0x157f, + 0xd0a4, 0x0040, 0x3606, 0xa006, 0x2020, 0x2009, 0x002a, 0x1078, + 0x7536, 0x2001, 0x760c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, + 0x1078, 0x2293, 0x047f, 0x017f, 0x007c, 0x157e, 0x20a9, 0x00ff, + 0x2009, 0x7720, 0xa006, 0x200a, 0x8108, 0x00f0, 0x3613, 0x157f, 0x007c, 0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0x7651, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, - 0x232f, 0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, + 0x2329, 0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, @@ -1256,500 +1237,500 @@ 0x61a2, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x6944, 0xa1b4, 0x00ff, 0xa682, 0x0010, - 0x00c8, 0x3715, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, - 0x371b, 0x2001, 0x760c, 0x2004, 0xa084, 0x0003, 0x00c0, 0x36fe, - 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x36ec, 0x6004, 0xa084, - 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x36f2, 0x6078, 0xa00d, 0x0040, - 0x3697, 0xa680, 0x75d5, 0x2004, 0xa10c, 0x00c0, 0x36e6, 0x607c, - 0xa00d, 0x0040, 0x36b3, 0xa680, 0x75d5, 0x2004, 0xa10c, 0x0040, - 0x36b3, 0x694c, 0xd1fc, 0x00c0, 0x36a9, 0x1078, 0x37ae, 0x0078, - 0x36e1, 0x1078, 0x377f, 0x694c, 0xd1ec, 0x00c0, 0x36e1, 0x1078, - 0x38c7, 0x0078, 0x36e1, 0x694c, 0xa184, 0xa000, 0x0040, 0x36d1, - 0xd1ec, 0x0040, 0x36ca, 0xd1fc, 0x0040, 0x36c2, 0x1078, 0x38de, - 0x0078, 0x36cd, 0xa680, 0x75d5, 0x200c, 0x607c, 0xa105, 0x607e, - 0x0078, 0x36d1, 0xd1fc, 0x0040, 0x36d1, 0x1078, 0x377f, 0x0078, - 0x36e1, 0x6050, 0xa00d, 0x0040, 0x36dc, 0x2d00, 0x200a, 0x6803, - 0x0000, 0x6052, 0x0078, 0x36e1, 0x2d00, 0x6052, 0x604e, 0x6803, - 0x0000, 0x1078, 0x4844, 0xa006, 0x127f, 0x007c, 0x2001, 0x0005, - 0x2009, 0x0000, 0x0078, 0x371f, 0x2001, 0x0028, 0x2009, 0x0000, - 0x0078, 0x371f, 0xa082, 0x0006, 0x00c8, 0x36fe, 0x60a0, 0xd0bc, - 0x0040, 0x368d, 0x2001, 0x0028, 0x0078, 0x3711, 0x2009, 0x760c, - 0x210c, 0xd18c, 0x0040, 0x3708, 0x2001, 0x0004, 0x0078, 0x3711, - 0xd184, 0x0040, 0x370f, 0x2001, 0x0004, 0x0078, 0x3711, 0x2001, - 0x0029, 0x2009, 0x0000, 0x0078, 0x371f, 0x2001, 0x0029, 0x2009, - 0x0000, 0x0078, 0x371f, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, + 0x00c8, 0x370d, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, + 0x3713, 0x2001, 0x760c, 0x2004, 0xa084, 0x0003, 0x00c0, 0x36f6, + 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x36e4, 0x6004, 0xa084, + 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x36ea, 0x6078, 0xa00d, 0x0040, + 0x368f, 0xa680, 0x75ca, 0x2004, 0xa10c, 0x00c0, 0x36de, 0x607c, + 0xa00d, 0x0040, 0x36ab, 0xa680, 0x75ca, 0x2004, 0xa10c, 0x0040, + 0x36ab, 0x694c, 0xd1fc, 0x00c0, 0x36a1, 0x1078, 0x37a6, 0x0078, + 0x36d9, 0x1078, 0x3777, 0x694c, 0xd1ec, 0x00c0, 0x36d9, 0x1078, + 0x38bf, 0x0078, 0x36d9, 0x694c, 0xa184, 0xa000, 0x0040, 0x36c9, + 0xd1ec, 0x0040, 0x36c2, 0xd1fc, 0x0040, 0x36ba, 0x1078, 0x38d6, + 0x0078, 0x36c5, 0xa680, 0x75ca, 0x200c, 0x607c, 0xa105, 0x607e, + 0x0078, 0x36c9, 0xd1fc, 0x0040, 0x36c9, 0x1078, 0x3777, 0x0078, + 0x36d9, 0x6050, 0xa00d, 0x0040, 0x36d4, 0x2d00, 0x200a, 0x6803, + 0x0000, 0x6052, 0x0078, 0x36d9, 0x2d00, 0x6052, 0x604e, 0x6803, + 0x0000, 0x1078, 0x483c, 0xa006, 0x127f, 0x007c, 0x2001, 0x0005, + 0x2009, 0x0000, 0x0078, 0x3717, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x3717, 0xa082, 0x0006, 0x00c8, 0x36f6, 0x60a0, 0xd0bc, + 0x0040, 0x3685, 0x2001, 0x0028, 0x0078, 0x3709, 0x2009, 0x760c, + 0x210c, 0xd18c, 0x0040, 0x3700, 0x2001, 0x0004, 0x0078, 0x3709, + 0xd184, 0x0040, 0x3707, 0x2001, 0x0004, 0x0078, 0x3709, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0078, 0x3717, 0x2001, 0x0029, 0x2009, + 0x0000, 0x0078, 0x3717, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0xa1b4, 0x00ff, 0xa682, 0x0010, 0x00c8, - 0x3764, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x3754, - 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x3754, 0x6004, 0xa084, - 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x375a, 0x684c, 0xd0ec, 0x0040, - 0x3747, 0x1078, 0x38de, 0x1078, 0x377f, 0x0078, 0x374f, 0x1078, - 0x377f, 0x684c, 0xd0fc, 0x0040, 0x374f, 0x1078, 0x38c7, 0x1078, - 0x38f2, 0xa006, 0x0078, 0x3768, 0x2001, 0x0028, 0x2009, 0x0000, - 0x0078, 0x3768, 0xa082, 0x0006, 0x0048, 0x373d, 0x2001, 0x0029, - 0x2009, 0x0000, 0x0078, 0x3768, 0x2001, 0x0029, 0x2009, 0x0000, + 0x375c, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x374c, + 0xa188, 0x7720, 0x2104, 0xa065, 0x0040, 0x374c, 0x6004, 0xa084, + 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x3752, 0x684c, 0xd0ec, 0x0040, + 0x373f, 0x1078, 0x38d6, 0x1078, 0x3777, 0x0078, 0x3747, 0x1078, + 0x3777, 0x684c, 0xd0fc, 0x0040, 0x3747, 0x1078, 0x38bf, 0x1078, + 0x38ea, 0xa006, 0x0078, 0x3760, 0x2001, 0x0028, 0x2009, 0x0000, + 0x0078, 0x3760, 0xa082, 0x0006, 0x0048, 0x3735, 0x2001, 0x0029, + 0x2009, 0x0000, 0x0078, 0x3760, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0040, - 0x3778, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, - 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x3776, 0x127e, - 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x378b, 0x6802, 0x2d00, + 0x3770, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, + 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x376e, 0x127e, + 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x3783, 0x6802, 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, - 0x0078, 0x3789, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, - 0x37a0, 0x6800, 0xa005, 0x00c0, 0x379e, 0x6052, 0x604e, 0xad05, - 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x37ad, 0x6800, 0xa005, - 0x00c0, 0x37ab, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, - 0x6084, 0xa00d, 0x0040, 0x37b8, 0x2d00, 0x200a, 0x6086, 0x007c, - 0x2d00, 0x6086, 0x6082, 0x0078, 0x37b7, 0x127e, 0x0c7e, 0x027e, - 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x37cb, - 0xc285, 0x0078, 0x37cc, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, + 0x0078, 0x3781, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, + 0x3798, 0x6800, 0xa005, 0x00c0, 0x3796, 0x6052, 0x604e, 0xad05, + 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x37a5, 0x6800, 0xa005, + 0x00c0, 0x37a3, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, + 0x6084, 0xa00d, 0x0040, 0x37b0, 0x2d00, 0x200a, 0x6086, 0x007c, + 0x2d00, 0x6086, 0x6082, 0x0078, 0x37af, 0x127e, 0x0c7e, 0x027e, + 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x37c3, + 0xc285, 0x0078, 0x37c4, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0xa294, 0xff00, 0xa215, 0x6206, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f, 0x007c, 0x027e, 0xa182, - 0x00ff, 0x0048, 0x37f7, 0xa085, 0x0001, 0x0078, 0x380b, 0xa190, - 0x7720, 0x2204, 0xa065, 0x00c0, 0x380a, 0x017e, 0x0d7e, 0x1078, - 0x1314, 0x2d60, 0x0d7f, 0x017f, 0x0040, 0x37f3, 0x2c00, 0x2012, - 0x1078, 0x3621, 0xa006, 0x027f, 0x007c, 0x027e, 0xa182, 0x00ff, - 0x0048, 0x3816, 0xa085, 0x0001, 0x0078, 0x3823, 0x0d7e, 0xa190, - 0x7720, 0x2204, 0xa06d, 0x0040, 0x3821, 0x2013, 0x0000, 0x1078, - 0x1348, 0x0d7f, 0xa006, 0x027f, 0x007c, 0x017e, 0xa182, 0x00ff, - 0x0048, 0x382e, 0xa085, 0x0001, 0x0078, 0x3835, 0xa188, 0x7720, - 0x2104, 0xa065, 0x0040, 0x382a, 0xa006, 0x017f, 0x007c, 0x0d7e, + 0x00ff, 0x0048, 0x37ef, 0xa085, 0x0001, 0x0078, 0x3803, 0xa190, + 0x7720, 0x2204, 0xa065, 0x00c0, 0x3802, 0x017e, 0x0d7e, 0x1078, + 0x130c, 0x2d60, 0x0d7f, 0x017f, 0x0040, 0x37eb, 0x2c00, 0x2012, + 0x1078, 0x3619, 0xa006, 0x027f, 0x007c, 0x027e, 0xa182, 0x00ff, + 0x0048, 0x380e, 0xa085, 0x0001, 0x0078, 0x381b, 0x0d7e, 0xa190, + 0x7720, 0x2204, 0xa06d, 0x0040, 0x3819, 0x2013, 0x0000, 0x1078, + 0x1340, 0x0d7f, 0xa006, 0x027f, 0x007c, 0x017e, 0xa182, 0x00ff, + 0x0048, 0x3826, 0xa085, 0x0001, 0x0078, 0x382d, 0xa188, 0x7720, + 0x2104, 0xa065, 0x0040, 0x3822, 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0x7b8e, 0x6808, 0x605e, 0x6810, 0x6062, - 0x6138, 0xa10a, 0x0048, 0x384d, 0x603a, 0x6814, 0x6066, 0x2099, + 0x6138, 0xa10a, 0x0048, 0x3845, 0x603a, 0x6814, 0x6066, 0x2099, 0x7b96, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0x7b9a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0x7bae, 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, - 0x6076, 0xa182, 0x0211, 0x00c8, 0x3871, 0x2009, 0x0008, 0x0078, - 0x389b, 0xa182, 0x0259, 0x00c8, 0x3879, 0x2009, 0x0007, 0x0078, - 0x389b, 0xa182, 0x02c1, 0x00c8, 0x3881, 0x2009, 0x0006, 0x0078, - 0x389b, 0xa182, 0x0349, 0x00c8, 0x3889, 0x2009, 0x0005, 0x0078, - 0x389b, 0xa182, 0x0421, 0x00c8, 0x3891, 0x2009, 0x0004, 0x0078, - 0x389b, 0xa182, 0x0581, 0x00c8, 0x3899, 0x2009, 0x0003, 0x0078, - 0x389b, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f, + 0x6076, 0xa182, 0x0211, 0x00c8, 0x3869, 0x2009, 0x0008, 0x0078, + 0x3893, 0xa182, 0x0259, 0x00c8, 0x3871, 0x2009, 0x0007, 0x0078, + 0x3893, 0xa182, 0x02c1, 0x00c8, 0x3879, 0x2009, 0x0006, 0x0078, + 0x3893, 0xa182, 0x0349, 0x00c8, 0x3881, 0x2009, 0x0005, 0x0078, + 0x3893, 0xa182, 0x0421, 0x00c8, 0x3889, 0x2009, 0x0004, 0x0078, + 0x3893, 0xa182, 0x0581, 0x00c8, 0x3891, 0x2009, 0x0003, 0x0078, + 0x3893, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x0e7e, 0x2071, 0x7b8d, 0x2e04, 0x6896, 0x2071, 0x7b8e, - 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75d5, + 0x7004, 0x689a, 0x701c, 0x689e, 0x0e7f, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10d, 0x617a, - 0x127f, 0x007c, 0x2001, 0x75d5, 0xa600, 0x2004, 0x8002, 0x127e, + 0x127f, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x6178, 0xa10c, 0x617a, 0x127f, 0x007c, 0x2001, - 0x75d5, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x617c, - 0xa10c, 0x617e, 0x127f, 0x0078, 0x38d7, 0x1078, 0x376a, 0x1078, - 0x3938, 0x00c0, 0x38d5, 0x1078, 0x38f2, 0x007c, 0x2001, 0x75d5, + 0x75ca, 0xa600, 0x2004, 0x8002, 0x127e, 0x2091, 0x8000, 0x617c, + 0xa10c, 0x617e, 0x127f, 0x0078, 0x38cf, 0x1078, 0x3762, 0x1078, + 0x3930, 0x00c0, 0x38cd, 0x1078, 0x38ea, 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x127e, 0x2091, 0x8000, 0x617c, 0xa10d, 0x617e, - 0x127f, 0x0078, 0x38ed, 0x1078, 0x37ae, 0x1078, 0x38fc, 0x00c0, - 0x38eb, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4844, 0x127f, - 0x007c, 0xa01e, 0x0078, 0x38fe, 0x2019, 0x0001, 0xa00e, 0x127e, - 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, 0x391e, - 0x8dff, 0x0040, 0x3933, 0x83ff, 0x0040, 0x3916, 0x6844, 0xa084, - 0x00ff, 0xa606, 0x0040, 0x3923, 0x0078, 0x391e, 0x683c, 0xa406, - 0x00c0, 0x391e, 0x6840, 0xa506, 0x0040, 0x3923, 0x2d08, 0x6800, - 0x2068, 0x0078, 0x3908, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x392b, - 0x624e, 0x0078, 0x392e, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, - 0x3933, 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x393a, - 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x3968, - 0x83ff, 0x0040, 0x394b, 0x6844, 0xa084, 0x00ff, 0xa606, 0x0040, - 0x3958, 0x0078, 0x3953, 0x683c, 0xa406, 0x00c0, 0x3953, 0x6840, - 0xa506, 0x0040, 0x3958, 0x2d08, 0x6800, 0x2068, 0x0078, 0x393d, - 0x6a00, 0x6080, 0xad06, 0x00c0, 0x3960, 0x6282, 0x0078, 0x3963, - 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x3968, 0x6186, 0x8dff, - 0x007c, 0x2001, 0x75d5, 0xa600, 0x2004, 0x6178, 0xa10c, 0x0040, - 0x3973, 0x2011, 0x0001, 0x617c, 0xa10c, 0x0040, 0x3979, 0xa295, - 0x0002, 0x007c, 0x1078, 0x39c5, 0x0040, 0x3982, 0x1078, 0x6a16, - 0x0078, 0x3984, 0xa085, 0x0001, 0x007c, 0x1078, 0x39c5, 0x0040, - 0x398d, 0x1078, 0x69a5, 0x0078, 0x398f, 0xa085, 0x0001, 0x007c, - 0x1078, 0x39c5, 0x0040, 0x3998, 0x1078, 0x69eb, 0x0078, 0x399a, - 0xa085, 0x0001, 0x007c, 0x1078, 0x39c5, 0x0040, 0x39a3, 0x1078, - 0x69c1, 0x0078, 0x39a5, 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, - 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, 0x0040, 0x39bd, 0x6800, - 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x007f, 0x0078, 0x39ac, 0x6083, 0x0000, 0x6087, + 0x127f, 0x0078, 0x38e5, 0x1078, 0x37a6, 0x1078, 0x38f4, 0x00c0, + 0x38e3, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x483c, 0x127f, + 0x007c, 0xa01e, 0x0078, 0x38f6, 0x2019, 0x0001, 0xa00e, 0x127e, + 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, 0x3916, + 0x8dff, 0x0040, 0x392b, 0x83ff, 0x0040, 0x390e, 0x6844, 0xa084, + 0x00ff, 0xa606, 0x0040, 0x391b, 0x0078, 0x3916, 0x683c, 0xa406, + 0x00c0, 0x3916, 0x6840, 0xa506, 0x0040, 0x391b, 0x2d08, 0x6800, + 0x2068, 0x0078, 0x3900, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x3923, + 0x624e, 0x0078, 0x3926, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, + 0x392b, 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x3932, + 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x3960, + 0x83ff, 0x0040, 0x3943, 0x6844, 0xa084, 0x00ff, 0xa606, 0x0040, + 0x3950, 0x0078, 0x394b, 0x683c, 0xa406, 0x00c0, 0x394b, 0x6840, + 0xa506, 0x0040, 0x3950, 0x2d08, 0x6800, 0x2068, 0x0078, 0x3935, + 0x6a00, 0x6080, 0xad06, 0x00c0, 0x3958, 0x6282, 0x0078, 0x395b, + 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x3960, 0x6186, 0x8dff, + 0x007c, 0x2001, 0x75ca, 0xa600, 0x2004, 0x6178, 0xa10c, 0x0040, + 0x396b, 0x2011, 0x0001, 0x617c, 0xa10c, 0x0040, 0x3971, 0xa295, + 0x0002, 0x007c, 0x1078, 0x39bd, 0x0040, 0x397a, 0x1078, 0x6a0b, + 0x0078, 0x397c, 0xa085, 0x0001, 0x007c, 0x1078, 0x39bd, 0x0040, + 0x3985, 0x1078, 0x699a, 0x0078, 0x3987, 0xa085, 0x0001, 0x007c, + 0x1078, 0x39bd, 0x0040, 0x3990, 0x1078, 0x69e0, 0x0078, 0x3992, + 0xa085, 0x0001, 0x007c, 0x1078, 0x39bd, 0x0040, 0x399b, 0x1078, + 0x69b6, 0x0078, 0x399d, 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, + 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d, 0x0040, 0x39b5, 0x6800, + 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x007f, 0x0078, 0x39a4, 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, - 0x0f7e, 0x2079, 0x7651, 0x7804, 0xd0a4, 0x0040, 0x39f1, 0x157e, - 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3825, - 0x00c0, 0x39e5, 0x6004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, - 0x00c0, 0x39e5, 0x6000, 0xc0ed, 0x6002, 0x017f, 0x8108, 0x00f0, - 0x39d5, 0x0c7f, 0x157f, 0x2009, 0x07d0, 0x2011, 0x39f3, 0x1078, - 0x45fe, 0x0f7f, 0x007c, 0x2011, 0x39f3, 0x1078, 0x456e, 0x157e, - 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x3825, - 0x00c0, 0x3a1f, 0x6000, 0xd0ec, 0x0040, 0x3a1f, 0x047e, 0x62a0, - 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x7541, - 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x2019, 0x0029, 0x1078, 0x4962, - 0x1078, 0x48a5, 0x2009, 0x0000, 0x1078, 0x737b, 0x047f, 0x017f, - 0x8108, 0x00f0, 0x39fd, 0x0c7f, 0x157f, 0x007c, 0x0c7e, 0x6018, + 0x0f7e, 0x2079, 0x7651, 0x7804, 0xd0a4, 0x0040, 0x39e9, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, + 0x00c0, 0x39dd, 0x6004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, + 0x00c0, 0x39dd, 0x6000, 0xc0ed, 0x6002, 0x017f, 0x8108, 0x00f0, + 0x39cd, 0x0c7f, 0x157f, 0x2009, 0x07d0, 0x2011, 0x39eb, 0x1078, + 0x45f6, 0x0f7f, 0x007c, 0x2011, 0x39eb, 0x1078, 0x4566, 0x157e, + 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x381d, + 0x00c0, 0x3a17, 0x6000, 0xd0ec, 0x0040, 0x3a17, 0x047e, 0x62a0, + 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x7536, + 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x2019, 0x0029, 0x1078, 0x495a, + 0x1078, 0x489d, 0x2009, 0x0000, 0x1078, 0x7370, 0x047f, 0x017f, + 0x8108, 0x00f0, 0x39f5, 0x0c7f, 0x157f, 0x007c, 0x0c7e, 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x2071, 0x76ff, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0x76ff, 0x684c, 0xa005, 0x00c0, 0x3a55, 0x7028, 0xc085, - 0x702a, 0xa085, 0x0001, 0x0078, 0x3a78, 0x6a60, 0x7236, 0x6b64, + 0x2071, 0x76ff, 0x684c, 0xa005, 0x00c0, 0x3a4d, 0x7028, 0xc085, + 0x702a, 0xa085, 0x0001, 0x0078, 0x3a70, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, - 0x0e7f, 0x007c, 0x0e7e, 0x6838, 0xd0fc, 0x00c0, 0x3acb, 0x6804, - 0xa00d, 0x0040, 0x3a99, 0x0d7e, 0x0e7e, 0x2071, 0x7600, 0x027e, + 0x0e7f, 0x007c, 0x0e7e, 0x6838, 0xd0fc, 0x00c0, 0x3ac3, 0x6804, + 0xa00d, 0x0040, 0x3a91, 0x0d7e, 0x0e7e, 0x2071, 0x7600, 0x027e, 0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, - 0x00c0, 0x3a8a, 0x702e, 0x70a0, 0xa200, 0x70a2, 0x027f, 0x0e7f, - 0x0d7f, 0x2071, 0x76ff, 0x701c, 0xa005, 0x00c0, 0x3adc, 0x0068, - 0x3ada, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3ada, 0x6934, - 0xa186, 0x0103, 0x00c0, 0x3aed, 0x6948, 0x6844, 0xa105, 0x00c0, - 0x3acd, 0x2009, 0x8020, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, - 0x3ada, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, + 0x00c0, 0x3a82, 0x702e, 0x70a0, 0xa200, 0x70a2, 0x027f, 0x0e7f, + 0x0d7f, 0x2071, 0x76ff, 0x701c, 0xa005, 0x00c0, 0x3ad4, 0x0068, + 0x3ad2, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3ad2, 0x6934, + 0xa186, 0x0103, 0x00c0, 0x3ae5, 0x6948, 0x6844, 0xa105, 0x00c0, + 0x3ac5, 0x2009, 0x8020, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, + 0x3ad2, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x2071, 0x7600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a0, 0x8000, 0x70a2, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, - 0x00c0, 0x3ada, 0x6868, 0xa005, 0x00c0, 0x3ada, 0x2009, 0x8020, - 0x0078, 0x3ab3, 0x2071, 0x76ff, 0x2d08, 0x206b, 0x0000, 0x7010, - 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x3aea, 0x6902, - 0x0078, 0x3aeb, 0x711e, 0x0078, 0x3acb, 0xa18c, 0x00ff, 0xa186, - 0x0017, 0x0040, 0x3afb, 0xa186, 0x001e, 0x0040, 0x3afb, 0xa18e, - 0x001f, 0x00c0, 0x3ada, 0x684c, 0xd0cc, 0x0040, 0x3ada, 0x6850, - 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x3ada, 0x2009, 0x8021, - 0x0078, 0x3ab3, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, + 0x00c0, 0x3ad2, 0x6868, 0xa005, 0x00c0, 0x3ad2, 0x2009, 0x8020, + 0x0078, 0x3aab, 0x2071, 0x76ff, 0x2d08, 0x206b, 0x0000, 0x7010, + 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x3ae2, 0x6902, + 0x0078, 0x3ae3, 0x711e, 0x0078, 0x3ac3, 0xa18c, 0x00ff, 0xa186, + 0x0017, 0x0040, 0x3af3, 0xa186, 0x001e, 0x0040, 0x3af3, 0xa18e, + 0x001f, 0x00c0, 0x3ad2, 0x684c, 0xd0cc, 0x0040, 0x3ad2, 0x6850, + 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x3ad2, 0x2009, 0x8021, + 0x0078, 0x3aab, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0x684a, 0x6952, - 0x007c, 0x2071, 0x76ff, 0x7004, 0x0079, 0x3b1e, 0x3b26, 0x3b35, - 0x3bc5, 0x3bc6, 0x3bd6, 0x3bdc, 0x3b27, 0x3bb3, 0x007c, 0x127e, - 0x2091, 0x8000, 0x0068, 0x3b34, 0x2009, 0x000d, 0x7030, 0x200a, + 0x007c, 0x2071, 0x76ff, 0x7004, 0x0079, 0x3b16, 0x3b1e, 0x3b2d, + 0x3bbd, 0x3bbe, 0x3bce, 0x3bd4, 0x3b1f, 0x3bab, 0x007c, 0x127e, + 0x2091, 0x8000, 0x0068, 0x3b2c, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x127f, 0x701c, 0xa06d, 0x0040, - 0x3bb2, 0x0e7e, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3b94, - 0x6934, 0xa186, 0x0103, 0x00c0, 0x3b6a, 0x6948, 0x6844, 0xa105, - 0x00c0, 0x3b87, 0x2009, 0x8020, 0x127e, 0x2091, 0x8000, 0x0068, - 0x3b66, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x3b66, 0x7122, + 0x3baa, 0x0e7e, 0x2071, 0x7651, 0x7004, 0xd09c, 0x0040, 0x3b8c, + 0x6934, 0xa186, 0x0103, 0x00c0, 0x3b62, 0x6948, 0x6844, 0xa105, + 0x00c0, 0x3b7f, 0x2009, 0x8020, 0x127e, 0x2091, 0x8000, 0x0068, + 0x3b5e, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x3b5e, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, - 0x127f, 0x0e7f, 0x1078, 0x3c0f, 0x0078, 0x3bb2, 0x127f, 0x0e7f, - 0x0078, 0x3bb2, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, 0x3b78, - 0xa186, 0x001e, 0x0040, 0x3b78, 0xa18e, 0x001f, 0x00c0, 0x3b94, - 0x684c, 0xd0cc, 0x0040, 0x3b94, 0x6850, 0xa084, 0x00ff, 0xa086, - 0x0001, 0x00c0, 0x3b94, 0x2009, 0x8021, 0x0078, 0x3b4c, 0x6844, - 0xa086, 0x0100, 0x00c0, 0x3b94, 0x6868, 0xa005, 0x00c0, 0x3b94, - 0x2009, 0x8020, 0x0078, 0x3b4c, 0x0e7f, 0x1078, 0x3c23, 0x0040, - 0x3bb2, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, - 0x00c0, 0x3ba9, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x3ba9, - 0x710e, 0x7007, 0x0003, 0x1078, 0x3c43, 0x7050, 0xa086, 0x0100, - 0x0040, 0x3bc6, 0x007c, 0x701c, 0xa06d, 0x0040, 0x3bc4, 0x1078, - 0x3c23, 0x0040, 0x3bc4, 0x7007, 0x0003, 0x1078, 0x3c43, 0x7050, - 0xa086, 0x0100, 0x0040, 0x3bc6, 0x007c, 0x007c, 0x7050, 0xa09e, - 0x0100, 0x00c0, 0x3bcf, 0x7007, 0x0004, 0x0078, 0x3bd6, 0xa086, - 0x0200, 0x00c0, 0x3bd5, 0x7007, 0x0005, 0x007c, 0x1078, 0x3bdd, - 0x7006, 0x1078, 0x3c0f, 0x007c, 0x007c, 0x702c, 0x7130, 0x8108, - 0xa102, 0x0048, 0x3bea, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, - 0x0078, 0x3bf4, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x3bf4, + 0x127f, 0x0e7f, 0x1078, 0x3c07, 0x0078, 0x3baa, 0x127f, 0x0e7f, + 0x0078, 0x3baa, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, 0x3b70, + 0xa186, 0x001e, 0x0040, 0x3b70, 0xa18e, 0x001f, 0x00c0, 0x3b8c, + 0x684c, 0xd0cc, 0x0040, 0x3b8c, 0x6850, 0xa084, 0x00ff, 0xa086, + 0x0001, 0x00c0, 0x3b8c, 0x2009, 0x8021, 0x0078, 0x3b44, 0x6844, + 0xa086, 0x0100, 0x00c0, 0x3b8c, 0x6868, 0xa005, 0x00c0, 0x3b8c, + 0x2009, 0x8020, 0x0078, 0x3b44, 0x0e7f, 0x1078, 0x3c1b, 0x0040, + 0x3baa, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, + 0x00c0, 0x3ba1, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x3ba1, + 0x710e, 0x7007, 0x0003, 0x1078, 0x3c3b, 0x7050, 0xa086, 0x0100, + 0x0040, 0x3bbe, 0x007c, 0x701c, 0xa06d, 0x0040, 0x3bbc, 0x1078, + 0x3c1b, 0x0040, 0x3bbc, 0x7007, 0x0003, 0x1078, 0x3c3b, 0x7050, + 0xa086, 0x0100, 0x0040, 0x3bbe, 0x007c, 0x007c, 0x7050, 0xa09e, + 0x0100, 0x00c0, 0x3bc7, 0x7007, 0x0004, 0x0078, 0x3bce, 0xa086, + 0x0200, 0x00c0, 0x3bcd, 0x7007, 0x0005, 0x007c, 0x1078, 0x3bd5, + 0x7006, 0x1078, 0x3c07, 0x007c, 0x007c, 0x702c, 0x7130, 0x8108, + 0xa102, 0x0048, 0x3be2, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, + 0x0078, 0x3bec, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x3bec, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, - 0x00c0, 0x3c08, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c0b, 0x2001, + 0x00c0, 0x3c00, 0x127e, 0x2091, 0x8000, 0x0068, 0x3c03, 0x2001, 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, 0x127f, 0x007c, 0x701c, - 0xa06d, 0x0040, 0x3c22, 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, - 0x7012, 0x2d04, 0x701e, 0xa005, 0x00c0, 0x3c1f, 0x701a, 0x127f, - 0x1078, 0x1348, 0x007c, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, - 0x0040, 0x3c32, 0x2304, 0x230c, 0xa10e, 0x0040, 0x3c32, 0xa006, - 0x0078, 0x3c42, 0x732c, 0x8319, 0x7130, 0xa102, 0x00c0, 0x3c3c, - 0x2300, 0xa005, 0x0078, 0x3c42, 0x0048, 0x3c41, 0xa302, 0x0078, - 0x3c42, 0x8002, 0x007c, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, + 0xa06d, 0x0040, 0x3c1a, 0x127e, 0x2091, 0x8000, 0x7010, 0x8001, + 0x7012, 0x2d04, 0x701e, 0xa005, 0x00c0, 0x3c17, 0x701a, 0x127f, + 0x1078, 0x1340, 0x007c, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, + 0x0040, 0x3c2a, 0x2304, 0x230c, 0xa10e, 0x0040, 0x3c2a, 0xa006, + 0x0078, 0x3c3a, 0x732c, 0x8319, 0x7130, 0xa102, 0x00c0, 0x3c34, + 0x2300, 0xa005, 0x0078, 0x3c3a, 0x0048, 0x3c39, 0xa302, 0x0078, + 0x3c3a, 0x8002, 0x007c, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, - 0xc08d, 0x200a, 0x127f, 0x1078, 0x1399, 0x007c, 0x2071, 0x76cd, + 0xc08d, 0x200a, 0x127f, 0x1078, 0x1391, 0x007c, 0x2071, 0x76cd, 0x7003, 0x0000, 0x7007, 0x0000, 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, 0x708f, 0x0001, 0x70bf, 0x0000, - 0x007c, 0x0e7e, 0x2071, 0x76cd, 0x6848, 0xa005, 0x00c0, 0x3c7f, - 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0078, 0x3ca4, 0x6a50, + 0x007c, 0x0e7e, 0x2071, 0x76cd, 0x6848, 0xa005, 0x00c0, 0x3c77, + 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0078, 0x3c9c, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x0e7f, 0x007c, 0x2b78, 0x2071, - 0x76cd, 0x7004, 0x1079, 0x3d04, 0x700c, 0x0079, 0x3caf, 0x3cb4, - 0x3ca9, 0x3ca9, 0x3ca9, 0x3ca9, 0x007c, 0x700c, 0x0079, 0x3cb8, - 0x3cbd, 0x3d02, 0x3d02, 0x3d03, 0x3d03, 0x7830, 0x7930, 0xa106, - 0x0040, 0x3cc7, 0x7830, 0x7930, 0xa106, 0x00c0, 0x3ced, 0x7030, - 0xa10a, 0x0040, 0x3ced, 0x00c8, 0x3ccf, 0x712c, 0xa10a, 0xa18a, - 0x0002, 0x00c8, 0x3cee, 0x1078, 0x1314, 0x0040, 0x3ced, 0x2d00, + 0x76cd, 0x7004, 0x1079, 0x3cfc, 0x700c, 0x0079, 0x3ca7, 0x3cac, + 0x3ca1, 0x3ca1, 0x3ca1, 0x3ca1, 0x007c, 0x700c, 0x0079, 0x3cb0, + 0x3cb5, 0x3cfa, 0x3cfa, 0x3cfb, 0x3cfb, 0x7830, 0x7930, 0xa106, + 0x0040, 0x3cbf, 0x7830, 0x7930, 0xa106, 0x00c0, 0x3ce5, 0x7030, + 0xa10a, 0x0040, 0x3ce5, 0x00c8, 0x3cc7, 0x712c, 0xa10a, 0xa18a, + 0x0002, 0x00c8, 0x3ce6, 0x1078, 0x130c, 0x0040, 0x3ce5, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, 0x2009, 0x7859, 0x2104, 0xc085, 0x200a, - 0x007f, 0x700e, 0x127f, 0x1078, 0x1399, 0x007c, 0x1078, 0x1314, - 0x0040, 0x3ced, 0x2d00, 0x705a, 0x1078, 0x1314, 0x00c0, 0x3cfa, - 0x0078, 0x3cd9, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, - 0x0078, 0x3cdd, 0x007c, 0x007c, 0x3d15, 0x3d16, 0x3d4d, 0x3d4e, - 0x3d02, 0x3d84, 0x3d89, 0x3dc0, 0x3dc1, 0x3ddc, 0x3ddd, 0x3dde, - 0x3ddf, 0x3de0, 0x3de1, 0x3e4a, 0x3e74, 0x007c, 0x700c, 0x0079, - 0x3d19, 0x3d1e, 0x3d21, 0x3d31, 0x3d4c, 0x3d4c, 0x1078, 0x3cb5, - 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x4153, - 0x0040, 0x3d2e, 0x2091, 0x8000, 0x1078, 0x3cb5, 0x0d7f, 0x0078, - 0x3d3a, 0x127e, 0x8001, 0x700e, 0x1078, 0x4153, 0x7058, 0x2068, + 0x007f, 0x700e, 0x127f, 0x1078, 0x1391, 0x007c, 0x1078, 0x130c, + 0x0040, 0x3ce5, 0x2d00, 0x705a, 0x1078, 0x130c, 0x00c0, 0x3cf2, + 0x0078, 0x3cd1, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, + 0x0078, 0x3cd5, 0x007c, 0x007c, 0x3d0d, 0x3d0e, 0x3d45, 0x3d46, + 0x3cfa, 0x3d7c, 0x3d81, 0x3db8, 0x3db9, 0x3dd4, 0x3dd5, 0x3dd6, + 0x3dd7, 0x3dd8, 0x3dd9, 0x3e42, 0x3e6c, 0x007c, 0x700c, 0x0079, + 0x3d11, 0x3d16, 0x3d19, 0x3d29, 0x3d44, 0x3d44, 0x1078, 0x3cad, + 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x414b, + 0x0040, 0x3d26, 0x2091, 0x8000, 0x1078, 0x3cad, 0x0d7f, 0x0078, + 0x3d32, 0x127e, 0x8001, 0x700e, 0x1078, 0x414b, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, - 0x00ff, 0xa08a, 0x0020, 0x00c8, 0x3d49, 0x1079, 0x3d64, 0x127f, - 0x007c, 0x127f, 0x1078, 0x3de2, 0x007c, 0x007c, 0x007c, 0x0e7e, - 0x2071, 0x76cd, 0x700c, 0x0079, 0x3d55, 0x3d5a, 0x3d5a, 0x3d5a, - 0x3d5c, 0x3d60, 0x0e7f, 0x007c, 0x700f, 0x0001, 0x0078, 0x3d62, - 0x700f, 0x0002, 0x0e7f, 0x007c, 0x3de2, 0x3de2, 0x3dfe, 0x3de2, - 0x3ee9, 0x3de2, 0x3de2, 0x3de2, 0x3de2, 0x3de2, 0x3dfe, 0x3f2e, - 0x3f77, 0x3fcf, 0x3fe2, 0x3de2, 0x3de2, 0x3e1a, 0x3dfe, 0x3de2, - 0x3de2, 0x3e30, 0x4069, 0x4086, 0x3de2, 0x3e1a, 0x3de2, 0x3de2, - 0x3de2, 0x3de2, 0x3e30, 0x4086, 0x7020, 0x2068, 0x1078, 0x1348, - 0x007c, 0x700c, 0x0079, 0x3d8c, 0x3d91, 0x3d94, 0x3da4, 0x3dbf, - 0x3dbf, 0x1078, 0x3cb5, 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, - 0x007e, 0x1078, 0x4153, 0x0040, 0x3da1, 0x2091, 0x8000, 0x1078, - 0x3cb5, 0x0d7f, 0x0078, 0x3dad, 0x127e, 0x8001, 0x700e, 0x1078, - 0x4153, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, - 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x3dbc, - 0x1079, 0x3dc2, 0x127f, 0x007c, 0x127f, 0x1078, 0x3de2, 0x007c, - 0x007c, 0x007c, 0x3de2, 0x3dfe, 0x3ed3, 0x3de2, 0x3dfe, 0x3de2, - 0x3dfe, 0x3dfe, 0x3de2, 0x3dfe, 0x3ed3, 0x3dfe, 0x3dfe, 0x3dfe, - 0x3dfe, 0x3dfe, 0x3de2, 0x3dfe, 0x3ed3, 0x3de2, 0x3de2, 0x3dfe, - 0x3de2, 0x3de2, 0x3de2, 0x3dfe, 0x007c, 0x007c, 0x007c, 0x007c, + 0x00ff, 0xa08a, 0x0020, 0x00c8, 0x3d41, 0x1079, 0x3d5c, 0x127f, + 0x007c, 0x127f, 0x1078, 0x3dda, 0x007c, 0x007c, 0x007c, 0x0e7e, + 0x2071, 0x76cd, 0x700c, 0x0079, 0x3d4d, 0x3d52, 0x3d52, 0x3d52, + 0x3d54, 0x3d58, 0x0e7f, 0x007c, 0x700f, 0x0001, 0x0078, 0x3d5a, + 0x700f, 0x0002, 0x0e7f, 0x007c, 0x3dda, 0x3dda, 0x3df6, 0x3dda, + 0x3ee1, 0x3dda, 0x3dda, 0x3dda, 0x3dda, 0x3dda, 0x3df6, 0x3f26, + 0x3f6f, 0x3fc7, 0x3fda, 0x3dda, 0x3dda, 0x3e12, 0x3df6, 0x3dda, + 0x3dda, 0x3e28, 0x4061, 0x407e, 0x3dda, 0x3e12, 0x3dda, 0x3dda, + 0x3dda, 0x3dda, 0x3e28, 0x407e, 0x7020, 0x2068, 0x1078, 0x1340, + 0x007c, 0x700c, 0x0079, 0x3d84, 0x3d89, 0x3d8c, 0x3d9c, 0x3db7, + 0x3db7, 0x1078, 0x3cad, 0x007c, 0x127e, 0x8001, 0x700e, 0x7058, + 0x007e, 0x1078, 0x414b, 0x0040, 0x3d99, 0x2091, 0x8000, 0x1078, + 0x3cad, 0x0d7f, 0x0078, 0x3da5, 0x127e, 0x8001, 0x700e, 0x1078, + 0x414b, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, + 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x001a, 0x00c8, 0x3db4, + 0x1079, 0x3dba, 0x127f, 0x007c, 0x127f, 0x1078, 0x3dda, 0x007c, + 0x007c, 0x007c, 0x3dda, 0x3df6, 0x3ecb, 0x3dda, 0x3df6, 0x3dda, + 0x3df6, 0x3df6, 0x3dda, 0x3df6, 0x3ecb, 0x3df6, 0x3df6, 0x3df6, + 0x3df6, 0x3df6, 0x3dda, 0x3df6, 0x3ecb, 0x3dda, 0x3dda, 0x3df6, + 0x3dda, 0x3dda, 0x3dda, 0x3df6, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, - 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, + 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, - 0x2091, 0x8000, 0x1078, 0x3a7a, 0x127f, 0x007c, 0x7007, 0x0001, + 0x2091, 0x8000, 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x127e, 0x2091, 0x8000, - 0x1078, 0x3a7a, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, - 0x00ff, 0xc0dd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a7a, - 0x127f, 0x007c, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3df0, - 0x8001, 0x00c0, 0x3e27, 0x7007, 0x0001, 0x0078, 0x3eb0, 0x7007, - 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x3eb0, 0x007c, + 0x1078, 0x3a72, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0dd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x3a72, + 0x127f, 0x007c, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0040, 0x3de8, + 0x8001, 0x00c0, 0x3e1f, 0x7007, 0x0001, 0x0078, 0x3ea8, 0x7007, + 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x3ea8, 0x007c, 0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0x76f8, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, - 0x3e0c, 0x6884, 0xa08a, 0x0003, 0x00c8, 0x3e0c, 0xa080, 0x3ea1, - 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, 0x3e94, 0x1078, 0x1314, - 0x00c0, 0x3e55, 0x7007, 0x000f, 0x007c, 0x2d00, 0x7022, 0x70c4, + 0x3e04, 0x6884, 0xa08a, 0x0003, 0x00c8, 0x3e04, 0xa080, 0x3e99, + 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, 0x3e8c, 0x1078, 0x130c, + 0x00c0, 0x3e4d, 0x7007, 0x000f, 0x007c, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, 0xad00, 0x7096, 0x6008, 0xa20a, - 0x00c8, 0x3e64, 0xa00e, 0x2200, 0x7112, 0x620c, 0x8003, 0x800b, - 0xa296, 0x0004, 0x0040, 0x3e6d, 0xa108, 0x719a, 0x810b, 0x719e, - 0xae90, 0x0022, 0x1078, 0x137f, 0x7090, 0xa08e, 0x0100, 0x0040, - 0x3e88, 0xa086, 0x0200, 0x0040, 0x3e80, 0x7007, 0x0010, 0x007c, - 0x7020, 0x2068, 0x1078, 0x1348, 0x7014, 0x2068, 0x0078, 0x3e0c, + 0x00c8, 0x3e5c, 0xa00e, 0x2200, 0x7112, 0x620c, 0x8003, 0x800b, + 0xa296, 0x0004, 0x0040, 0x3e65, 0xa108, 0x719a, 0x810b, 0x719e, + 0xae90, 0x0022, 0x1078, 0x1377, 0x7090, 0xa08e, 0x0100, 0x0040, + 0x3e80, 0xa086, 0x0200, 0x0040, 0x3e78, 0x7007, 0x0010, 0x007c, + 0x7020, 0x2068, 0x1078, 0x1340, 0x7014, 0x2068, 0x0078, 0x3e04, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, 0x2068, - 0x6906, 0x711a, 0x0078, 0x3e4a, 0x7014, 0x2068, 0x7007, 0x0001, - 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x40a3, 0x0078, - 0x3eb0, 0x3ea4, 0x3ea8, 0x3eac, 0x0002, 0x0011, 0x0007, 0x0004, + 0x6906, 0x711a, 0x0078, 0x3e42, 0x7014, 0x2068, 0x7007, 0x0001, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x409b, 0x0078, + 0x3ea8, 0x3e9c, 0x3ea0, 0x3ea4, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, 0x0006, 0x0012, 0x000f, 0x0005, 0x0006, - 0x2009, 0x762c, 0x210c, 0x81ff, 0x00c0, 0x3ecd, 0x6838, 0xa084, - 0x00ff, 0x683a, 0x6853, 0x0000, 0x1078, 0x3668, 0x00c0, 0x3ec1, - 0x007c, 0x1078, 0x3b0a, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x127f, 0x0078, 0x3ec0, 0x2001, 0x0028, 0x2009, - 0x0000, 0x0078, 0x3ec1, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, - 0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x3ee2, 0x7007, 0x0006, - 0x0078, 0x3ee8, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, + 0x2009, 0x762c, 0x210c, 0x81ff, 0x00c0, 0x3ec5, 0x6838, 0xa084, + 0x00ff, 0x683a, 0x6853, 0x0000, 0x1078, 0x3660, 0x00c0, 0x3eb9, + 0x007c, 0x1078, 0x3b02, 0x127e, 0x2091, 0x8000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x127f, 0x0078, 0x3eb8, 0x2001, 0x0028, 0x2009, + 0x0000, 0x0078, 0x3eb9, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, + 0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x3eda, 0x7007, 0x0006, + 0x0078, 0x3ee0, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, - 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x3f14, - 0x2009, 0x0000, 0x20a9, 0x007e, 0xa096, 0x0002, 0x0040, 0x3f14, - 0xa005, 0x00c0, 0x3f2b, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, - 0x3825, 0x00c0, 0x3f2b, 0x067e, 0x6e44, 0xa6b4, 0x000f, 0x1078, - 0x38ba, 0x067f, 0x0078, 0x3f2b, 0x047e, 0x2011, 0x760c, 0x2224, - 0xc484, 0xc48c, 0x2412, 0x047f, 0x0c7e, 0x1078, 0x3825, 0x00c0, - 0x3f27, 0x2091, 0x8000, 0x607b, 0x0000, 0x2091, 0x8001, 0x8108, - 0x00f0, 0x3f1d, 0x0c7f, 0x1078, 0x1348, 0x007c, 0x127e, 0x2091, + 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x3f0c, + 0x2009, 0x0000, 0x20a9, 0x007e, 0xa096, 0x0002, 0x0040, 0x3f0c, + 0xa005, 0x00c0, 0x3f23, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, + 0x381d, 0x00c0, 0x3f23, 0x067e, 0x6e44, 0xa6b4, 0x000f, 0x1078, + 0x38b2, 0x067f, 0x0078, 0x3f23, 0x047e, 0x2011, 0x760c, 0x2224, + 0xc484, 0xc48c, 0x2412, 0x047f, 0x0c7e, 0x1078, 0x381d, 0x00c0, + 0x3f1f, 0x2091, 0x8000, 0x607b, 0x0000, 0x2091, 0x8001, 0x8108, + 0x00f0, 0x3f15, 0x0c7f, 0x1078, 0x1340, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x7652, 0x2004, 0xd0a4, 0x0040, - 0x3f6e, 0x6944, 0x1078, 0x416f, 0x6100, 0xd184, 0x0040, 0x3f53, - 0x6858, 0xa084, 0x00ff, 0x00c0, 0x3f71, 0x6000, 0xd084, 0x0040, - 0x3f6e, 0x6004, 0xa005, 0x00c0, 0x3f74, 0x6003, 0x0000, 0x600b, - 0x0000, 0x0078, 0x3f6b, 0x2011, 0x0001, 0x6860, 0xa005, 0x00c0, - 0x3f5b, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, - 0x0040, 0x3f6e, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0040, - 0x3f6e, 0x600a, 0x6202, 0x127f, 0x0078, 0x4142, 0x127f, 0x0078, - 0x413a, 0x127f, 0x0078, 0x4132, 0x127f, 0x0078, 0x4136, 0x127e, + 0x3f66, 0x6944, 0x1078, 0x4167, 0x6100, 0xd184, 0x0040, 0x3f4b, + 0x6858, 0xa084, 0x00ff, 0x00c0, 0x3f69, 0x6000, 0xd084, 0x0040, + 0x3f66, 0x6004, 0xa005, 0x00c0, 0x3f6c, 0x6003, 0x0000, 0x600b, + 0x0000, 0x0078, 0x3f63, 0x2011, 0x0001, 0x6860, 0xa005, 0x00c0, + 0x3f53, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, + 0x0040, 0x3f66, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0040, + 0x3f66, 0x600a, 0x6202, 0x127f, 0x0078, 0x413a, 0x127f, 0x0078, + 0x4132, 0x127f, 0x0078, 0x412a, 0x127f, 0x0078, 0x412e, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x7652, 0x2004, 0xd0a4, - 0x0040, 0x3fcc, 0x6944, 0x1078, 0x416f, 0x6000, 0xa084, 0x0001, - 0x0040, 0x3fcc, 0x6204, 0x6308, 0x6c48, 0xa484, 0x0003, 0x0040, - 0x3fa4, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x3f9d, 0x2100, - 0xa210, 0x0048, 0x3fc9, 0x0078, 0x3fa4, 0x8001, 0x00c0, 0x3fc9, - 0x2100, 0xa212, 0x0048, 0x3fc9, 0xa484, 0x000c, 0x0040, 0x3fbe, - 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, 0x3fb6, - 0x2100, 0xa318, 0x0048, 0x3fc9, 0x0078, 0x3fbe, 0xa082, 0x0004, - 0x00c0, 0x3fc9, 0x2100, 0xa31a, 0x0048, 0x3fc9, 0x6860, 0xa005, - 0x0040, 0x3fc4, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, 0x0078, - 0x4142, 0x127f, 0x0078, 0x413e, 0x127f, 0x0078, 0x413a, 0x127e, - 0x2091, 0x8000, 0x7007, 0x0001, 0x6944, 0x1078, 0x416f, 0x6308, - 0x8318, 0x0048, 0x3fdf, 0x630a, 0x127f, 0x0078, 0x4150, 0x127f, - 0x0078, 0x413e, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, - 0x684c, 0xd0ac, 0x0040, 0x3ff6, 0x027e, 0x2009, 0x0000, 0x2011, - 0xfcff, 0x1078, 0x46b4, 0x027f, 0x0078, 0x402c, 0x6858, 0xa005, - 0x0040, 0x4040, 0x685c, 0xa065, 0x0040, 0x403c, 0x2001, 0x762c, - 0x2004, 0xa005, 0x0040, 0x4008, 0x1078, 0x6aa1, 0x0078, 0x400e, - 0x6013, 0x0400, 0x2009, 0x0041, 0x1078, 0x5c29, 0x6958, 0xa18c, - 0xe600, 0xa186, 0x2000, 0x0040, 0x4024, 0xa186, 0x0400, 0x0040, - 0x4024, 0x6944, 0x0c7e, 0x1078, 0x460c, 0x6000, 0xa084, 0xfdff, - 0x6002, 0x0c7f, 0x0078, 0x402c, 0x027e, 0x2009, 0x0000, 0x2011, - 0xfdff, 0x1078, 0x46b4, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x4038, - 0x6944, 0x1078, 0x460c, 0x6008, 0x8000, 0x0048, 0x4038, 0x600a, - 0x0c7f, 0x127f, 0x0078, 0x4142, 0x0c7f, 0x127f, 0x0078, 0x413a, - 0x6954, 0xa186, 0x002a, 0x00c0, 0x404c, 0x2001, 0x760c, 0x200c, - 0xc194, 0x2102, 0x0078, 0x402c, 0xa186, 0x0020, 0x0040, 0x4061, - 0xa186, 0x0029, 0x00c0, 0x403c, 0x6944, 0xa18c, 0xff00, 0x810f, - 0x1078, 0x3825, 0x00c0, 0x402c, 0x6000, 0xc0e4, 0x6002, 0x0078, - 0x402c, 0x685c, 0xa065, 0x0040, 0x403c, 0x6017, 0x0014, 0x0078, - 0x402c, 0x6944, 0x1078, 0x416f, 0x6000, 0xa084, 0x0001, 0x0040, - 0x4082, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x407c, 0x6206, - 0x2091, 0x8001, 0x0078, 0x4150, 0x2091, 0x8001, 0x6853, 0x0016, - 0x0078, 0x4149, 0x6853, 0x0007, 0x0078, 0x4149, 0x6834, 0x8007, - 0xa084, 0x00ff, 0x00c0, 0x4090, 0x1078, 0x3df0, 0x0078, 0x40a2, - 0x2030, 0x8001, 0x00c0, 0x409a, 0x7007, 0x0001, 0x1078, 0x40a3, - 0x0078, 0x40a2, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, - 0x704b, 0x40a3, 0x007c, 0x0e7e, 0x2009, 0x762c, 0x210c, 0x81ff, - 0x00c0, 0x4124, 0x2009, 0x760c, 0x210c, 0xd194, 0x00c0, 0x412e, - 0x6848, 0x2070, 0xae82, 0x7d00, 0x0048, 0x4113, 0x2001, 0x7615, - 0x2004, 0xae02, 0x00c8, 0x4113, 0x6944, 0x1078, 0x416f, 0x6100, - 0xa184, 0x0001, 0x0040, 0x40f9, 0xa184, 0x0100, 0x00c0, 0x4117, - 0xa184, 0x0200, 0x00c0, 0x411b, 0x601c, 0xa005, 0x00c0, 0x411f, - 0x711c, 0xa186, 0x0006, 0x00c0, 0x40fe, 0x6853, 0x0000, 0x6803, + 0x0040, 0x3fc4, 0x6944, 0x1078, 0x4167, 0x6000, 0xa084, 0x0001, + 0x0040, 0x3fc4, 0x6204, 0x6308, 0x6c48, 0xa484, 0x0003, 0x0040, + 0x3f9c, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x3f95, 0x2100, + 0xa210, 0x0048, 0x3fc1, 0x0078, 0x3f9c, 0x8001, 0x00c0, 0x3fc1, + 0x2100, 0xa212, 0x0048, 0x3fc1, 0xa484, 0x000c, 0x0040, 0x3fb6, + 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, 0x3fae, + 0x2100, 0xa318, 0x0048, 0x3fc1, 0x0078, 0x3fb6, 0xa082, 0x0004, + 0x00c0, 0x3fc1, 0x2100, 0xa31a, 0x0048, 0x3fc1, 0x6860, 0xa005, + 0x0040, 0x3fbc, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, 0x0078, + 0x413a, 0x127f, 0x0078, 0x4136, 0x127f, 0x0078, 0x4132, 0x127e, + 0x2091, 0x8000, 0x7007, 0x0001, 0x6944, 0x1078, 0x4167, 0x6308, + 0x8318, 0x0048, 0x3fd7, 0x630a, 0x127f, 0x0078, 0x4148, 0x127f, + 0x0078, 0x4136, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, + 0x684c, 0xd0ac, 0x0040, 0x3fee, 0x027e, 0x2009, 0x0000, 0x2011, + 0xfcff, 0x1078, 0x46ac, 0x027f, 0x0078, 0x4024, 0x6858, 0xa005, + 0x0040, 0x4038, 0x685c, 0xa065, 0x0040, 0x4034, 0x2001, 0x762c, + 0x2004, 0xa005, 0x0040, 0x4000, 0x1078, 0x6a96, 0x0078, 0x4006, + 0x6013, 0x0400, 0x2009, 0x0041, 0x1078, 0x5c21, 0x6958, 0xa18c, + 0xe600, 0xa186, 0x2000, 0x0040, 0x401c, 0xa186, 0x0400, 0x0040, + 0x401c, 0x6944, 0x0c7e, 0x1078, 0x4604, 0x6000, 0xa084, 0xfdff, + 0x6002, 0x0c7f, 0x0078, 0x4024, 0x027e, 0x2009, 0x0000, 0x2011, + 0xfdff, 0x1078, 0x46ac, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x4030, + 0x6944, 0x1078, 0x4604, 0x6008, 0x8000, 0x0048, 0x4030, 0x600a, + 0x0c7f, 0x127f, 0x0078, 0x413a, 0x0c7f, 0x127f, 0x0078, 0x4132, + 0x6954, 0xa186, 0x002a, 0x00c0, 0x4044, 0x2001, 0x760c, 0x200c, + 0xc194, 0x2102, 0x0078, 0x4024, 0xa186, 0x0020, 0x0040, 0x4059, + 0xa186, 0x0029, 0x00c0, 0x4034, 0x6944, 0xa18c, 0xff00, 0x810f, + 0x1078, 0x381d, 0x00c0, 0x4024, 0x6000, 0xc0e4, 0x6002, 0x0078, + 0x4024, 0x685c, 0xa065, 0x0040, 0x4034, 0x6017, 0x0014, 0x0078, + 0x4024, 0x6944, 0x1078, 0x4167, 0x6000, 0xa084, 0x0001, 0x0040, + 0x407a, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x4074, 0x6206, + 0x2091, 0x8001, 0x0078, 0x4148, 0x2091, 0x8001, 0x6853, 0x0016, + 0x0078, 0x4141, 0x6853, 0x0007, 0x0078, 0x4141, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x00c0, 0x4088, 0x1078, 0x3de8, 0x0078, 0x409a, + 0x2030, 0x8001, 0x00c0, 0x4092, 0x7007, 0x0001, 0x1078, 0x409b, + 0x0078, 0x409a, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, + 0x704b, 0x409b, 0x007c, 0x0e7e, 0x2009, 0x762c, 0x210c, 0x81ff, + 0x00c0, 0x411c, 0x2009, 0x760c, 0x210c, 0xd194, 0x00c0, 0x4126, + 0x6848, 0x2070, 0xae82, 0x7d00, 0x0048, 0x410b, 0x2001, 0x7615, + 0x2004, 0xae02, 0x00c8, 0x410b, 0x6944, 0x1078, 0x4167, 0x6100, + 0xa184, 0x0001, 0x0040, 0x40f1, 0xa184, 0x0100, 0x00c0, 0x410f, + 0xa184, 0x0200, 0x00c0, 0x4113, 0x601c, 0xa005, 0x00c0, 0x4117, + 0x711c, 0xa186, 0x0006, 0x00c0, 0x40f6, 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x127e, 0x2091, 0x8000, 0x7010, 0xa005, 0x00c0, - 0x40f0, 0x7112, 0x7018, 0xa065, 0x0040, 0x4123, 0x6000, 0xd0e4, - 0x00c0, 0x4128, 0x2e60, 0x1078, 0x4615, 0x127f, 0x0e7f, 0x007c, - 0x2068, 0x6800, 0xa005, 0x00c0, 0x40f0, 0x6902, 0x127f, 0x0e7f, - 0x007c, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x4149, 0x6944, 0xa18c, - 0xff00, 0x810f, 0x1078, 0x3825, 0x00c0, 0x4129, 0x6000, 0xd0e4, - 0x00c0, 0x4129, 0x711c, 0xa186, 0x0007, 0x00c0, 0x4113, 0x6853, - 0x0002, 0x0078, 0x412b, 0x6853, 0x0008, 0x0078, 0x412b, 0x6853, - 0x000e, 0x0078, 0x412b, 0x6853, 0x0017, 0x0078, 0x412b, 0x6853, - 0x0035, 0x0078, 0x412b, 0x127f, 0x6853, 0x0028, 0x0078, 0x412b, - 0x127f, 0x6853, 0x0029, 0x0e7f, 0x0078, 0x4149, 0x6853, 0x002a, - 0x0078, 0x412b, 0x2009, 0x003e, 0x0078, 0x4144, 0x2009, 0x0004, - 0x0078, 0x4144, 0x2009, 0x0006, 0x0078, 0x4144, 0x2009, 0x0016, - 0x0078, 0x4144, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, - 0x6856, 0x2091, 0x8000, 0x1078, 0x3a7a, 0x2091, 0x8001, 0x007c, - 0x1078, 0x1348, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, - 0x4160, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, 0x416c, - 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x416c, 0x7074, 0xa081, + 0x40e8, 0x7112, 0x7018, 0xa065, 0x0040, 0x411b, 0x6000, 0xd0e4, + 0x00c0, 0x4120, 0x2e60, 0x1078, 0x460d, 0x127f, 0x0e7f, 0x007c, + 0x2068, 0x6800, 0xa005, 0x00c0, 0x40e8, 0x6902, 0x127f, 0x0e7f, + 0x007c, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x4141, 0x6944, 0xa18c, + 0xff00, 0x810f, 0x1078, 0x381d, 0x00c0, 0x4121, 0x6000, 0xd0e4, + 0x00c0, 0x4121, 0x711c, 0xa186, 0x0007, 0x00c0, 0x410b, 0x6853, + 0x0002, 0x0078, 0x4123, 0x6853, 0x0008, 0x0078, 0x4123, 0x6853, + 0x000e, 0x0078, 0x4123, 0x6853, 0x0017, 0x0078, 0x4123, 0x6853, + 0x0035, 0x0078, 0x4123, 0x127f, 0x6853, 0x0028, 0x0078, 0x4123, + 0x127f, 0x6853, 0x0029, 0x0e7f, 0x0078, 0x4141, 0x6853, 0x002a, + 0x0078, 0x4123, 0x2009, 0x003e, 0x0078, 0x413c, 0x2009, 0x0004, + 0x0078, 0x413c, 0x2009, 0x0006, 0x0078, 0x413c, 0x2009, 0x0016, + 0x0078, 0x413c, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, + 0x6856, 0x2091, 0x8000, 0x1078, 0x3a72, 0x2091, 0x8001, 0x007c, + 0x1078, 0x1340, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, + 0x4158, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078, 0x4164, + 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x4164, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, - 0x1078, 0x460c, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, + 0x1078, 0x4604, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, - 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x418b, 0xa086, - 0x1000, 0x00c0, 0x41a7, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, - 0x4192, 0x3e60, 0xac84, 0x0007, 0x00c0, 0x41a7, 0xac82, 0x7d00, - 0x0048, 0x41a7, 0x6854, 0xac02, 0x00c8, 0x41a7, 0x2009, 0x0047, - 0x1078, 0x5c29, 0x7a1c, 0xd284, 0x00c0, 0x417d, 0x007c, 0xa016, - 0x1078, 0x1572, 0x0078, 0x41a2, 0x157e, 0x137e, 0x147e, 0x20e1, - 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x00c0, 0x41d5, 0xa484, - 0x7000, 0xa086, 0x1000, 0x00c0, 0x41d5, 0x1078, 0x41e2, 0x0040, - 0x41d5, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078, 0x4200, 0x147f, - 0x137f, 0x157f, 0x2009, 0x783e, 0x2104, 0xa005, 0x00c0, 0x41d1, - 0x007c, 0x1078, 0x4c7a, 0x0078, 0x41d0, 0x1078, 0x7574, 0x1078, - 0x41e2, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, 0x137f, 0x157f, - 0x0078, 0x41d0, 0xa484, 0x01ff, 0x687a, 0xa005, 0x0040, 0x41f4, + 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x4183, 0xa086, + 0x1000, 0x00c0, 0x419f, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, + 0x418a, 0x3e60, 0xac84, 0x0007, 0x00c0, 0x419f, 0xac82, 0x7d00, + 0x0048, 0x419f, 0x6854, 0xac02, 0x00c8, 0x419f, 0x2009, 0x0047, + 0x1078, 0x5c21, 0x7a1c, 0xd284, 0x00c0, 0x4175, 0x007c, 0xa016, + 0x1078, 0x156a, 0x0078, 0x419a, 0x157e, 0x137e, 0x147e, 0x20e1, + 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x00c0, 0x41cd, 0xa484, + 0x7000, 0xa086, 0x1000, 0x00c0, 0x41cd, 0x1078, 0x41da, 0x0040, + 0x41cd, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078, 0x41f8, 0x147f, + 0x137f, 0x157f, 0x2009, 0x783e, 0x2104, 0xa005, 0x00c0, 0x41c9, + 0x007c, 0x1078, 0x4c72, 0x0078, 0x41c8, 0x1078, 0x7569, 0x1078, + 0x41da, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, 0x137f, 0x157f, + 0x0078, 0x41c8, 0xa484, 0x01ff, 0x687a, 0xa005, 0x0040, 0x41ec, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, 0x20e1, 0x1000, - 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41f3, + 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, 0x0078, 0x41eb, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, 0xa196, 0x0000, - 0x00c0, 0x420d, 0x0078, 0x4381, 0x007c, 0xa196, 0x2000, 0x00c0, - 0x421e, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x421a, 0x1078, 0x2eb2, - 0x0078, 0x420c, 0x1078, 0x4226, 0x0078, 0x420c, 0xa196, 0x8000, - 0x00c0, 0x420c, 0x1078, 0x4407, 0x0078, 0x420c, 0x0c7e, 0x7110, - 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, 0x4233, 0xa196, - 0x0023, 0x00c0, 0x4328, 0xa08e, 0x0023, 0x00c0, 0x4264, 0x1078, - 0x447e, 0x0040, 0x4328, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, - 0x00c0, 0x424c, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0015, - 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0210, 0x00c0, 0x4256, - 0x2009, 0x0015, 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0100, - 0x00c0, 0x4328, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0016, - 0x1078, 0x5c29, 0x0078, 0x4328, 0xa08e, 0x0022, 0x00c0, 0x4328, - 0x7030, 0xa08e, 0x0300, 0x00c0, 0x4275, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x0017, 0x0078, 0x42f4, 0xa08e, 0x0500, 0x00c0, - 0x4281, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x0018, 0x0078, - 0x42f4, 0xa08e, 0x2010, 0x00c0, 0x4289, 0x2009, 0x0019, 0x0078, - 0x42f4, 0xa08e, 0x2110, 0x00c0, 0x4291, 0x2009, 0x001a, 0x0078, - 0x42f4, 0xa08e, 0x5200, 0x00c0, 0x429d, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x001b, 0x0078, 0x42f4, 0xa08e, 0x5000, 0x00c0, - 0x42a9, 0x7034, 0xa005, 0x00c0, 0x4328, 0x2009, 0x001c, 0x0078, - 0x42f4, 0xa08e, 0x1200, 0x00c0, 0x42b5, 0x7034, 0xa005, 0x00c0, - 0x4328, 0x2009, 0x0024, 0x0078, 0x42f4, 0xa08c, 0xff00, 0xa18e, - 0x2400, 0x00c0, 0x42bf, 0x2009, 0x002d, 0x0078, 0x42f4, 0xa08c, - 0xff00, 0xa18e, 0x5300, 0x00c0, 0x42c9, 0x2009, 0x002a, 0x0078, - 0x42f4, 0xa08e, 0x0f00, 0x00c0, 0x42d1, 0x2009, 0x0020, 0x0078, - 0x42f4, 0xa08e, 0x5300, 0x00c0, 0x42d7, 0x0078, 0x42f2, 0xa08e, - 0x6104, 0x00c0, 0x42f2, 0x2011, 0x7b8d, 0x8208, 0x2204, 0xa082, + 0x00c0, 0x4205, 0x0078, 0x4379, 0x007c, 0xa196, 0x2000, 0x00c0, + 0x4216, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x4212, 0x1078, 0x2ea3, + 0x0078, 0x4204, 0x1078, 0x421e, 0x0078, 0x4204, 0xa196, 0x8000, + 0x00c0, 0x4204, 0x1078, 0x43ff, 0x0078, 0x4204, 0x0c7e, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, 0x422b, 0xa196, + 0x0023, 0x00c0, 0x4320, 0xa08e, 0x0023, 0x00c0, 0x425c, 0x1078, + 0x4476, 0x0040, 0x4320, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, + 0x00c0, 0x4244, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0015, + 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0210, 0x00c0, 0x424e, + 0x2009, 0x0015, 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0100, + 0x00c0, 0x4320, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0016, + 0x1078, 0x5c21, 0x0078, 0x4320, 0xa08e, 0x0022, 0x00c0, 0x4320, + 0x7030, 0xa08e, 0x0300, 0x00c0, 0x426d, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x0017, 0x0078, 0x42ec, 0xa08e, 0x0500, 0x00c0, + 0x4279, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x0018, 0x0078, + 0x42ec, 0xa08e, 0x2010, 0x00c0, 0x4281, 0x2009, 0x0019, 0x0078, + 0x42ec, 0xa08e, 0x2110, 0x00c0, 0x4289, 0x2009, 0x001a, 0x0078, + 0x42ec, 0xa08e, 0x5200, 0x00c0, 0x4295, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x001b, 0x0078, 0x42ec, 0xa08e, 0x5000, 0x00c0, + 0x42a1, 0x7034, 0xa005, 0x00c0, 0x4320, 0x2009, 0x001c, 0x0078, + 0x42ec, 0xa08e, 0x1200, 0x00c0, 0x42ad, 0x7034, 0xa005, 0x00c0, + 0x4320, 0x2009, 0x0024, 0x0078, 0x42ec, 0xa08c, 0xff00, 0xa18e, + 0x2400, 0x00c0, 0x42b7, 0x2009, 0x002d, 0x0078, 0x42ec, 0xa08c, + 0xff00, 0xa18e, 0x5300, 0x00c0, 0x42c1, 0x2009, 0x002a, 0x0078, + 0x42ec, 0xa08e, 0x0f00, 0x00c0, 0x42c9, 0x2009, 0x0020, 0x0078, + 0x42ec, 0xa08e, 0x5300, 0x00c0, 0x42cf, 0x0078, 0x42ea, 0xa08e, + 0x6104, 0x00c0, 0x42ea, 0x2011, 0x7b8d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, - 0x2124, 0x1078, 0x2d4a, 0x8108, 0x00f0, 0x42e4, 0x2009, 0x0023, - 0x0078, 0x42f4, 0x2009, 0x001d, 0x017e, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x432a, 0x1078, 0x37ee, - 0x00c0, 0x432a, 0x6612, 0x6516, 0x86ff, 0x0040, 0x431a, 0x017f, - 0x017e, 0xa186, 0x0017, 0x00c0, 0x431a, 0x6864, 0xa606, 0x00c0, - 0x431a, 0x6868, 0xa506, 0xa084, 0xff00, 0x00c0, 0x431a, 0x6000, - 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x5b9c, 0x0040, 0x432d, 0x017f, - 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x5c29, - 0x0c7f, 0x007c, 0x017f, 0x0078, 0x4328, 0x0c7f, 0x0078, 0x432a, - 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, 0x00c0, 0x4350, - 0xa596, 0xfffd, 0x00c0, 0x4340, 0x2009, 0x007f, 0x0078, 0x437d, - 0xa596, 0xfffe, 0x00c0, 0x4348, 0x2009, 0x007e, 0x0078, 0x437d, - 0xa596, 0xfffc, 0x00c0, 0x4350, 0x2009, 0x0080, 0x0078, 0x437d, + 0x2124, 0x1078, 0x2d3b, 0x8108, 0x00f0, 0x42dc, 0x2009, 0x0023, + 0x0078, 0x42ec, 0x2009, 0x001d, 0x017e, 0x2011, 0x7b83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x207f, 0x00c0, 0x4322, 0x1078, 0x37e6, + 0x00c0, 0x4322, 0x6612, 0x6516, 0x86ff, 0x0040, 0x4312, 0x017f, + 0x017e, 0xa186, 0x0017, 0x00c0, 0x4312, 0x6864, 0xa606, 0x00c0, + 0x4312, 0x6868, 0xa506, 0xa084, 0xff00, 0x00c0, 0x4312, 0x6000, + 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x5b94, 0x0040, 0x4325, 0x017f, + 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x5c21, + 0x0c7f, 0x007c, 0x017f, 0x0078, 0x4320, 0x0c7f, 0x0078, 0x4322, + 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff, 0x00c0, 0x4348, + 0xa596, 0xfffd, 0x00c0, 0x4338, 0x2009, 0x007f, 0x0078, 0x4375, + 0xa596, 0xfffe, 0x00c0, 0x4340, 0x2009, 0x007e, 0x0078, 0x4375, + 0xa596, 0xfffc, 0x00c0, 0x4348, 0x2009, 0x0080, 0x0078, 0x4375, 0x2011, 0x0000, 0x2021, 0x007e, 0x20a9, 0x0082, 0x2071, 0x779e, - 0x2e1c, 0x83ff, 0x00c0, 0x4362, 0x82ff, 0x00c0, 0x4371, 0x2410, - 0x0078, 0x4371, 0x2368, 0x6b10, 0x007e, 0x2100, 0xa31e, 0x007f, - 0x00c0, 0x4371, 0x6b14, 0xa31e, 0x00c0, 0x4371, 0x2408, 0x0078, - 0x437d, 0x8420, 0x8e70, 0x00f0, 0x4358, 0x82ff, 0x00c0, 0x437c, - 0xa085, 0x0001, 0x0078, 0x437e, 0x2208, 0xa006, 0x0d7f, 0x0e7f, - 0x007c, 0xa084, 0x0007, 0x0079, 0x4386, 0x007c, 0x438e, 0x438e, - 0x438e, 0x438e, 0x438e, 0x438f, 0x43a8, 0x43f0, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x43a7, 0x7120, 0x2160, 0xac8c, 0x0007, 0x00c0, - 0x43a7, 0xac8a, 0x7d00, 0x0048, 0x43a7, 0x6854, 0xac02, 0x00c8, - 0x43a7, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x5c29, 0x007c, - 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x43ee, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x43ee, 0x1078, 0x3825, - 0x00c0, 0x43ee, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, - 0x00c0, 0x43d3, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x43ee, + 0x2e1c, 0x83ff, 0x00c0, 0x435a, 0x82ff, 0x00c0, 0x4369, 0x2410, + 0x0078, 0x4369, 0x2368, 0x6b10, 0x007e, 0x2100, 0xa31e, 0x007f, + 0x00c0, 0x4369, 0x6b14, 0xa31e, 0x00c0, 0x4369, 0x2408, 0x0078, + 0x4375, 0x8420, 0x8e70, 0x00f0, 0x4350, 0x82ff, 0x00c0, 0x4374, + 0xa085, 0x0001, 0x0078, 0x4376, 0x2208, 0xa006, 0x0d7f, 0x0e7f, + 0x007c, 0xa084, 0x0007, 0x0079, 0x437e, 0x007c, 0x4386, 0x4386, + 0x4386, 0x4386, 0x4386, 0x4387, 0x43a0, 0x43e8, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x439f, 0x7120, 0x2160, 0xac8c, 0x0007, 0x00c0, + 0x439f, 0xac8a, 0x7d00, 0x0048, 0x439f, 0x6854, 0xac02, 0x00c8, + 0x439f, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x5c21, 0x007c, + 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x43e6, 0x2011, 0x7b83, 0x2204, + 0x8211, 0x220c, 0x1078, 0x207f, 0x00c0, 0x43e6, 0x1078, 0x381d, + 0x00c0, 0x43e6, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, + 0x00c0, 0x43cb, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x43e6, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x2009, 0x0044, 0x1078, - 0x5c29, 0x0078, 0x43ee, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, - 0x43ee, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, - 0x00c0, 0x43e6, 0x6007, 0x0005, 0x0078, 0x43e8, 0x6007, 0x0001, - 0x6003, 0x0001, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0c7f, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x4406, 0x7020, 0x2060, 0xac84, 0x0007, - 0x00c0, 0x4406, 0xac82, 0x7d00, 0x0048, 0x4406, 0x6854, 0xac02, - 0x00c8, 0x4406, 0x2009, 0x0045, 0x1078, 0x5c29, 0x007c, 0x7110, - 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x4417, 0xa084, - 0x000f, 0xa08a, 0x0006, 0x10c8, 0x12d5, 0x1079, 0x4418, 0x007c, - 0x441e, 0x441f, 0x441e, 0x441e, 0x4460, 0x446f, 0x007c, 0x7110, - 0xd1bc, 0x00c0, 0x445f, 0x700c, 0x7108, 0x1078, 0x2085, 0x00c0, - 0x445f, 0x1078, 0x37ee, 0x00c0, 0x445f, 0x6612, 0x6516, 0x6204, - 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x00c0, 0x4448, 0x0c7e, - 0x1078, 0x5b9c, 0x017f, 0x0040, 0x445f, 0x611a, 0x601f, 0x0005, - 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x5c29, 0x0078, 0x445f, - 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x445f, 0x611a, 0x601f, - 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x445b, 0x2009, - 0x0005, 0x0078, 0x445d, 0x2009, 0x0001, 0x1078, 0x5c29, 0x007c, - 0x7110, 0xd1bc, 0x0040, 0x446e, 0x1078, 0x447e, 0x0040, 0x446e, - 0x7124, 0x610a, 0x2009, 0x0089, 0x1078, 0x5c29, 0x007c, 0x7110, - 0xd1bc, 0x0040, 0x447d, 0x1078, 0x447e, 0x0040, 0x447d, 0x7124, - 0x610a, 0x2009, 0x008a, 0x1078, 0x5c29, 0x007c, 0x7020, 0x2060, - 0xac84, 0x0007, 0x00c0, 0x4491, 0xac82, 0x7d00, 0x0048, 0x4491, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x4491, 0xa085, 0x0001, - 0x007c, 0xa006, 0x0078, 0x4490, 0x2071, 0x7849, 0x7003, 0x0003, + 0x5c21, 0x0078, 0x43e6, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, + 0x43e6, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, + 0x00c0, 0x43de, 0x6007, 0x0005, 0x0078, 0x43e0, 0x6007, 0x0001, + 0x6003, 0x0001, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0c7f, 0x007c, + 0x7110, 0xd1bc, 0x0040, 0x43fe, 0x7020, 0x2060, 0xac84, 0x0007, + 0x00c0, 0x43fe, 0xac82, 0x7d00, 0x0048, 0x43fe, 0x6854, 0xac02, + 0x00c8, 0x43fe, 0x2009, 0x0045, 0x1078, 0x5c21, 0x007c, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x440f, 0xa084, + 0x000f, 0xa08a, 0x0006, 0x10c8, 0x12cd, 0x1079, 0x4410, 0x007c, + 0x4416, 0x4417, 0x4416, 0x4416, 0x4458, 0x4467, 0x007c, 0x7110, + 0xd1bc, 0x00c0, 0x4457, 0x700c, 0x7108, 0x1078, 0x207f, 0x00c0, + 0x4457, 0x1078, 0x37e6, 0x00c0, 0x4457, 0x6612, 0x6516, 0x6204, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x00c0, 0x4440, 0x0c7e, + 0x1078, 0x5b94, 0x017f, 0x0040, 0x4457, 0x611a, 0x601f, 0x0005, + 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x5c21, 0x0078, 0x4457, + 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x4457, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x4453, 0x2009, + 0x0005, 0x0078, 0x4455, 0x2009, 0x0001, 0x1078, 0x5c21, 0x007c, + 0x7110, 0xd1bc, 0x0040, 0x4466, 0x1078, 0x4476, 0x0040, 0x4466, + 0x7124, 0x610a, 0x2009, 0x0089, 0x1078, 0x5c21, 0x007c, 0x7110, + 0xd1bc, 0x0040, 0x4475, 0x1078, 0x4476, 0x0040, 0x4475, 0x7124, + 0x610a, 0x2009, 0x008a, 0x1078, 0x5c21, 0x007c, 0x7020, 0x2060, + 0xac84, 0x0007, 0x00c0, 0x4489, 0xac82, 0x7d00, 0x0048, 0x4489, + 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x4489, 0xa085, 0x0001, + 0x007c, 0xa006, 0x0078, 0x4488, 0x2071, 0x7849, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, 0x7017, 0x7d00, 0x7007, - 0x0000, 0x7026, 0x702b, 0x558f, 0x7032, 0x7037, 0x55d0, 0x703b, - 0x0002, 0x703f, 0x0000, 0x007c, 0x2071, 0x7849, 0x00e0, 0x455b, - 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x4524, 0x700f, + 0x0000, 0x7026, 0x702b, 0x5587, 0x7032, 0x7037, 0x55c8, 0x703b, + 0x0002, 0x703f, 0x0000, 0x007c, 0x2071, 0x7849, 0x00e0, 0x4553, + 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x451c, 0x700f, 0x0361, 0x7007, 0x0001, 0x127e, 0x2091, 0x8000, 0x7138, 0x8109, - 0x713a, 0x00c0, 0x4522, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, - 0xa082, 0x0003, 0x00c8, 0x4522, 0x703c, 0xa086, 0x0001, 0x00c0, - 0x44ff, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, - 0x44dd, 0x6803, 0x1000, 0x0078, 0x44e4, 0x6804, 0xa084, 0x1000, - 0x0040, 0x44e4, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, - 0x2069, 0x7836, 0x6804, 0xa082, 0x0006, 0x00c0, 0x44f1, 0x6807, - 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x44f8, 0x6833, 0x0000, - 0x1078, 0x4c7a, 0x1078, 0x4d3a, 0x0d7f, 0x0078, 0x4522, 0x0d7e, - 0x2069, 0x7600, 0x6944, 0x6860, 0xa102, 0x00c8, 0x4521, 0x2069, - 0x7836, 0x6804, 0xa086, 0x0000, 0x00c0, 0x4521, 0x6830, 0xa086, - 0x0000, 0x00c0, 0x4521, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, + 0x713a, 0x00c0, 0x451a, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, + 0xa082, 0x0003, 0x00c8, 0x451a, 0x703c, 0xa086, 0x0001, 0x00c0, + 0x44f7, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, + 0x44d5, 0x6803, 0x1000, 0x0078, 0x44dc, 0x6804, 0xa084, 0x1000, + 0x0040, 0x44dc, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, + 0x2069, 0x7836, 0x6804, 0xa082, 0x0006, 0x00c0, 0x44e9, 0x6807, + 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x44f0, 0x6833, 0x0000, + 0x1078, 0x4c72, 0x1078, 0x4d32, 0x0d7f, 0x0078, 0x451a, 0x0d7e, + 0x2069, 0x7600, 0x6944, 0x6860, 0xa102, 0x00c8, 0x4519, 0x2069, + 0x7836, 0x6804, 0xa086, 0x0000, 0x00c0, 0x4519, 0x6830, 0xa086, + 0x0000, 0x00c0, 0x4519, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, 0x0003, 0x2069, 0x0100, 0x6830, 0x689e, 0x2069, 0x0140, 0x6803, - 0x0600, 0x0d7f, 0x0078, 0x4527, 0x127e, 0x2091, 0x8000, 0x7024, - 0xa00d, 0x0040, 0x4538, 0x7020, 0x8001, 0x7022, 0x00c0, 0x4538, - 0x7023, 0x0009, 0x8109, 0x7126, 0x00c0, 0x4538, 0x7028, 0x107a, - 0x7030, 0xa00d, 0x0040, 0x4549, 0x702c, 0x8001, 0x702e, 0x00c0, - 0x4549, 0x702f, 0x0009, 0x8109, 0x7132, 0x00c0, 0x4549, 0x7034, - 0x107a, 0x7018, 0xa00d, 0x0040, 0x455a, 0x7008, 0x8001, 0x700a, - 0x00c0, 0x455a, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x455a, - 0x701c, 0x107a, 0x127f, 0x7004, 0x0079, 0x455e, 0x4585, 0x4586, - 0x45a2, 0x0e7e, 0x2071, 0x7849, 0x7018, 0xa005, 0x00c0, 0x456c, + 0x0600, 0x0d7f, 0x0078, 0x451f, 0x127e, 0x2091, 0x8000, 0x7024, + 0xa00d, 0x0040, 0x4530, 0x7020, 0x8001, 0x7022, 0x00c0, 0x4530, + 0x7023, 0x0009, 0x8109, 0x7126, 0x00c0, 0x4530, 0x7028, 0x107a, + 0x7030, 0xa00d, 0x0040, 0x4541, 0x702c, 0x8001, 0x702e, 0x00c0, + 0x4541, 0x702f, 0x0009, 0x8109, 0x7132, 0x00c0, 0x4541, 0x7034, + 0x107a, 0x7018, 0xa00d, 0x0040, 0x4552, 0x7008, 0x8001, 0x700a, + 0x00c0, 0x4552, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x4552, + 0x701c, 0x107a, 0x127f, 0x7004, 0x0079, 0x4556, 0x457d, 0x457e, + 0x459a, 0x0e7e, 0x2071, 0x7849, 0x7018, 0xa005, 0x00c0, 0x4564, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, - 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4578, 0x701a, 0x701e, + 0x2071, 0x7849, 0x701c, 0xa206, 0x00c0, 0x4570, 0x701a, 0x701e, 0x007f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x6088, 0xa102, - 0x0048, 0x4583, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, - 0x3825, 0x00c0, 0x4598, 0x6088, 0x8001, 0x0048, 0x4598, 0x608a, - 0x00c0, 0x4598, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, - 0x8108, 0xa182, 0x00ff, 0x0048, 0x45a0, 0xa00e, 0x7007, 0x0002, + 0x0048, 0x457b, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, + 0x381d, 0x00c0, 0x4590, 0x6088, 0x8001, 0x0048, 0x4590, 0x608a, + 0x00c0, 0x4590, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, + 0x8108, 0xa182, 0x00ff, 0x0048, 0x4598, 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c, 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x6014, - 0xa005, 0x0040, 0x45d1, 0x8001, 0x6016, 0x00c0, 0x45d1, 0x611c, - 0xa186, 0x0003, 0x0040, 0x45b8, 0xa186, 0x0006, 0x00c0, 0x45cf, - 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x45cf, 0xa082, - 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x45c8, 0x2001, 0x1999, - 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x45d1, 0x1078, - 0x67c9, 0x127f, 0xac88, 0x0008, 0x7116, 0x2001, 0x7616, 0x2004, - 0xa102, 0x0048, 0x45df, 0x7017, 0x7d00, 0x7007, 0x0000, 0x007c, + 0xa005, 0x0040, 0x45c9, 0x8001, 0x6016, 0x00c0, 0x45c9, 0x611c, + 0xa186, 0x0003, 0x0040, 0x45b0, 0xa186, 0x0006, 0x00c0, 0x45c7, + 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x45c7, 0xa082, + 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x45c0, 0x2001, 0x1999, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x45c9, 0x1078, + 0x67c3, 0x127f, 0xac88, 0x0008, 0x7116, 0x2001, 0x7616, 0x2004, + 0xa102, 0x0048, 0x45d7, 0x7017, 0x7d00, 0x7007, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, 0x0002, 0x0e7f, 0x007c, 0x2001, 0x7852, 0x2003, 0x0000, 0x007c, 0x0e7e, 0x2071, 0x7849, 0x7033, 0x07d0, 0x702f, 0x0009, 0x0e7f, @@ -1757,1536 +1738,5694 @@ 0x7849, 0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0c7e, 0x2061, 0x78da, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x78da, 0x2060, 0x007c, 0x6854, 0xa08a, 0x199a, - 0x0048, 0x461c, 0x2001, 0x1999, 0xa005, 0x00c0, 0x462c, 0x6944, - 0x0c7e, 0x1078, 0x460c, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x4631, - 0x2001, 0x001e, 0x0078, 0x4631, 0xa08e, 0xffff, 0x00c0, 0x4631, + 0x0048, 0x4614, 0x2001, 0x1999, 0xa005, 0x00c0, 0x4624, 0x6944, + 0x0c7e, 0x1078, 0x4604, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x4629, + 0x2001, 0x001e, 0x0078, 0x4629, 0xa08e, 0xffff, 0x00c0, 0x4629, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, - 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x466c, 0xd0b4, 0x00c0, 0x4648, - 0xd0bc, 0x00c0, 0x465a, 0x2009, 0x0006, 0x1078, 0x468f, 0x007c, - 0xd0fc, 0x0040, 0x4655, 0xa084, 0x0003, 0xa08e, 0x0003, 0x0040, - 0x4688, 0xa08e, 0x0000, 0x00c0, 0x4688, 0x2009, 0x0043, 0x1078, - 0x5c29, 0x007c, 0xd0fc, 0x0040, 0x4667, 0xa084, 0x0003, 0xa08e, - 0x0003, 0x0040, 0x4688, 0xa08e, 0x0000, 0x00c0, 0x4688, 0x2009, - 0x0042, 0x1078, 0x5c29, 0x007c, 0xd0fc, 0x0040, 0x467e, 0xa084, - 0x0003, 0xa08e, 0x0003, 0x0040, 0x4688, 0xa08e, 0x0002, 0x0040, - 0x4682, 0x2009, 0x0041, 0x1078, 0x5c29, 0x007c, 0x1078, 0x468d, - 0x0078, 0x467d, 0x2009, 0x0043, 0x1078, 0x5c29, 0x0078, 0x467d, - 0x2009, 0x0004, 0x1078, 0x468f, 0x007c, 0x2009, 0x0001, 0x6010, - 0xa0ec, 0xf000, 0x0040, 0x46b3, 0x2068, 0x6952, 0x6800, 0x6012, - 0xa186, 0x0001, 0x00c0, 0x46ad, 0x694c, 0xa18c, 0x8100, 0xa18e, - 0x8100, 0x00c0, 0x46ad, 0x0c7e, 0x6944, 0x1078, 0x460c, 0x6204, - 0x8210, 0x0048, 0x46ac, 0x6206, 0x0c7f, 0x1078, 0x3a7a, 0x6010, - 0xa06d, 0x10c0, 0x4615, 0x007c, 0x157e, 0x0c7e, 0x20a9, 0x0010, - 0x2061, 0x78da, 0x6000, 0x81ff, 0x0040, 0x46c1, 0xa205, 0x0078, - 0x46c2, 0xa204, 0x6002, 0xace0, 0x0008, 0x00f0, 0x46ba, 0x0c7f, - 0x157f, 0x007c, 0x6808, 0xa005, 0x0040, 0x46d2, 0x8001, 0x680a, + 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x4664, 0xd0b4, 0x00c0, 0x4640, + 0xd0bc, 0x00c0, 0x4652, 0x2009, 0x0006, 0x1078, 0x4687, 0x007c, + 0xd0fc, 0x0040, 0x464d, 0xa084, 0x0003, 0xa08e, 0x0003, 0x0040, + 0x4680, 0xa08e, 0x0000, 0x00c0, 0x4680, 0x2009, 0x0043, 0x1078, + 0x5c21, 0x007c, 0xd0fc, 0x0040, 0x465f, 0xa084, 0x0003, 0xa08e, + 0x0003, 0x0040, 0x4680, 0xa08e, 0x0000, 0x00c0, 0x4680, 0x2009, + 0x0042, 0x1078, 0x5c21, 0x007c, 0xd0fc, 0x0040, 0x4676, 0xa084, + 0x0003, 0xa08e, 0x0003, 0x0040, 0x4680, 0xa08e, 0x0002, 0x0040, + 0x467a, 0x2009, 0x0041, 0x1078, 0x5c21, 0x007c, 0x1078, 0x4685, + 0x0078, 0x4675, 0x2009, 0x0043, 0x1078, 0x5c21, 0x0078, 0x4675, + 0x2009, 0x0004, 0x1078, 0x4687, 0x007c, 0x2009, 0x0001, 0x6010, + 0xa0ec, 0xf000, 0x0040, 0x46ab, 0x2068, 0x6952, 0x6800, 0x6012, + 0xa186, 0x0001, 0x00c0, 0x46a5, 0x694c, 0xa18c, 0x8100, 0xa18e, + 0x8100, 0x00c0, 0x46a5, 0x0c7e, 0x6944, 0x1078, 0x4604, 0x6204, + 0x8210, 0x0048, 0x46a4, 0x6206, 0x0c7f, 0x1078, 0x3a72, 0x6010, + 0xa06d, 0x10c0, 0x460d, 0x007c, 0x157e, 0x0c7e, 0x20a9, 0x0010, + 0x2061, 0x78da, 0x6000, 0x81ff, 0x0040, 0x46b9, 0xa205, 0x0078, + 0x46ba, 0xa204, 0x6002, 0xace0, 0x0008, 0x00f0, 0x46b2, 0x0c7f, + 0x157f, 0x007c, 0x6808, 0xa005, 0x0040, 0x46ca, 0x8001, 0x680a, 0xa085, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x2079, 0x7836, 0x127f, 0x0d7e, 0x2069, 0x7836, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, 0x0d7f, 0x007c, 0x0c7e, 0x6027, - 0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x46ee, 0x46f8, 0x471d, - 0x4778, 0x46fe, 0x471d, 0x46f6, 0x46f6, 0x46f6, 0x1078, 0x12d5, - 0x1078, 0x45eb, 0x1078, 0x4c7a, 0x0c7f, 0x007c, 0x62c0, 0x82ff, - 0x00c0, 0x4704, 0x0c7f, 0x007c, 0x2011, 0x3542, 0x1078, 0x456e, - 0x7828, 0xa092, 0x0002, 0x00c8, 0x4713, 0x8000, 0x782a, 0x1078, - 0x3572, 0x0078, 0x4702, 0x1078, 0x3542, 0x7807, 0x0003, 0x7827, - 0x0000, 0x782b, 0x0000, 0x0078, 0x4702, 0x1078, 0x45eb, 0x3c00, + 0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x46e6, 0x46f0, 0x4715, + 0x4770, 0x46f6, 0x4715, 0x46ee, 0x46ee, 0x46ee, 0x1078, 0x12cd, + 0x1078, 0x45e3, 0x1078, 0x4c72, 0x0c7f, 0x007c, 0x62c0, 0x82ff, + 0x00c0, 0x46fc, 0x0c7f, 0x007c, 0x2011, 0x353a, 0x1078, 0x4566, + 0x7828, 0xa092, 0x0002, 0x00c8, 0x470b, 0x8000, 0x782a, 0x1078, + 0x356a, 0x0078, 0x46fa, 0x1078, 0x353a, 0x7807, 0x0003, 0x7827, + 0x0000, 0x782b, 0x0000, 0x0078, 0x46fa, 0x1078, 0x45e3, 0x3c00, 0x007e, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x007f, 0x20e0, - 0x82ff, 0x0040, 0x473b, 0x62c0, 0x82ff, 0x00c0, 0x473b, 0x782b, - 0x0000, 0x7824, 0xa065, 0x1040, 0x12d5, 0x2009, 0x0013, 0x1078, - 0x5c29, 0x0c7f, 0x007c, 0x3900, 0xa082, 0x797a, 0x00c8, 0x4742, - 0x1078, 0x5b2c, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x12d5, 0x7804, - 0xa086, 0x0004, 0x0040, 0x47bd, 0x7828, 0xa092, 0x2710, 0x00c8, - 0x4758, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x5574, 0x0078, 0x4739, - 0x6104, 0xa186, 0x0003, 0x00c0, 0x476f, 0x0e7e, 0x2071, 0x7600, - 0x70c8, 0x0e7f, 0xd08c, 0x0040, 0x476f, 0x0c7e, 0x0e7e, 0x2061, - 0x0100, 0x2071, 0x7600, 0x1078, 0x357b, 0x0e7f, 0x0c7f, 0x1078, - 0x75c7, 0x2009, 0x0014, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x4739, - 0x2001, 0x7852, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x478c, - 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x12d5, 0x2009, 0x0013, - 0x1078, 0x5c77, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082, - 0x797a, 0x00c8, 0x4795, 0x1078, 0x5b2c, 0x7824, 0xa005, 0x1040, - 0x12d5, 0x781c, 0xa06d, 0x1040, 0x12d5, 0x6800, 0xc0dc, 0x6802, - 0x7924, 0x2160, 0x1078, 0x5c02, 0x693c, 0x81ff, 0x1040, 0x12d5, - 0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x47b1, 0x7a1e, 0x0078, - 0x47b3, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, - 0x0c7f, 0x1078, 0x4c7a, 0x0078, 0x478a, 0x6104, 0xa186, 0x0002, - 0x0040, 0x47c8, 0xa186, 0x0004, 0x0040, 0x47c8, 0x0078, 0x474c, - 0x7808, 0xac06, 0x0040, 0x474c, 0x1078, 0x4b81, 0x1078, 0x4872, - 0x0c7f, 0x1078, 0x4c7a, 0x0078, 0x4739, 0x0c7e, 0x6027, 0x0002, - 0x2011, 0x7855, 0x2013, 0x0000, 0x62c8, 0x82ff, 0x00c0, 0x47ef, - 0x62c4, 0x82ff, 0x00c0, 0x47ef, 0x793c, 0xa1e5, 0x0000, 0x0040, - 0x47ed, 0x2009, 0x0049, 0x1078, 0x5c29, 0x0c7f, 0x007c, 0x3908, - 0xa192, 0x797a, 0x00c8, 0x47f6, 0x1078, 0x5b2c, 0x6017, 0x0010, - 0x793c, 0x81ff, 0x0040, 0x47ed, 0x7944, 0xa192, 0x7530, 0x00c8, - 0x4815, 0x8108, 0x7946, 0x1078, 0x45f0, 0x793c, 0xa188, 0x0007, - 0x210c, 0xa18e, 0x0006, 0x00c0, 0x4811, 0x6017, 0x0012, 0x0078, - 0x47ed, 0x6017, 0x0016, 0x0078, 0x47ed, 0x037e, 0x2019, 0x0001, - 0x1078, 0x5768, 0x037f, 0x1078, 0x75c7, 0x793c, 0x2160, 0x2009, - 0x004a, 0x1078, 0x5c29, 0x0078, 0x47ed, 0x007e, 0x017e, 0x0c7e, + 0x82ff, 0x0040, 0x4733, 0x62c0, 0x82ff, 0x00c0, 0x4733, 0x782b, + 0x0000, 0x7824, 0xa065, 0x1040, 0x12cd, 0x2009, 0x0013, 0x1078, + 0x5c21, 0x0c7f, 0x007c, 0x3900, 0xa082, 0x797a, 0x00c8, 0x473a, + 0x1078, 0x5b24, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x12cd, 0x7804, + 0xa086, 0x0004, 0x0040, 0x47b5, 0x7828, 0xa092, 0x2710, 0x00c8, + 0x4750, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x556c, 0x0078, 0x4731, + 0x6104, 0xa186, 0x0003, 0x00c0, 0x4767, 0x0e7e, 0x2071, 0x7600, + 0x70c8, 0x0e7f, 0xd08c, 0x0040, 0x4767, 0x0c7e, 0x0e7e, 0x2061, + 0x0100, 0x2071, 0x7600, 0x1078, 0x3573, 0x0e7f, 0x0c7f, 0x1078, + 0x75bc, 0x2009, 0x0014, 0x1078, 0x5c21, 0x0c7f, 0x0078, 0x4731, + 0x2001, 0x7852, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x4784, + 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x12cd, 0x2009, 0x0013, + 0x1078, 0x5c6f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082, + 0x797a, 0x00c8, 0x478d, 0x1078, 0x5b24, 0x7824, 0xa005, 0x1040, + 0x12cd, 0x781c, 0xa06d, 0x1040, 0x12cd, 0x6800, 0xc0dc, 0x6802, + 0x7924, 0x2160, 0x1078, 0x5bfa, 0x693c, 0x81ff, 0x1040, 0x12cd, + 0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x47a9, 0x7a1e, 0x0078, + 0x47ab, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f, + 0x0c7f, 0x1078, 0x4c72, 0x0078, 0x4782, 0x6104, 0xa186, 0x0002, + 0x0040, 0x47c0, 0xa186, 0x0004, 0x0040, 0x47c0, 0x0078, 0x4744, + 0x7808, 0xac06, 0x0040, 0x4744, 0x1078, 0x4b79, 0x1078, 0x486a, + 0x0c7f, 0x1078, 0x4c72, 0x0078, 0x4731, 0x0c7e, 0x6027, 0x0002, + 0x2011, 0x7855, 0x2013, 0x0000, 0x62c8, 0x82ff, 0x00c0, 0x47e7, + 0x62c4, 0x82ff, 0x00c0, 0x47e7, 0x793c, 0xa1e5, 0x0000, 0x0040, + 0x47e5, 0x2009, 0x0049, 0x1078, 0x5c21, 0x0c7f, 0x007c, 0x3908, + 0xa192, 0x797a, 0x00c8, 0x47ee, 0x1078, 0x5b24, 0x6017, 0x0010, + 0x793c, 0x81ff, 0x0040, 0x47e5, 0x7944, 0xa192, 0x7530, 0x00c8, + 0x480d, 0x8108, 0x7946, 0x1078, 0x45e8, 0x793c, 0xa188, 0x0007, + 0x210c, 0xa18e, 0x0006, 0x00c0, 0x4809, 0x6017, 0x0012, 0x0078, + 0x47e5, 0x6017, 0x0016, 0x0078, 0x47e5, 0x037e, 0x2019, 0x0001, + 0x1078, 0x5760, 0x037f, 0x1078, 0x75bc, 0x793c, 0x2160, 0x2009, + 0x004a, 0x1078, 0x5c21, 0x0078, 0x47e5, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, - 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4840, 0xa080, + 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0040, 0x4838, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, - 0x6116, 0x6112, 0x0078, 0x483b, 0x0d7e, 0x2069, 0x7836, 0x6000, - 0xd0d4, 0x0040, 0x4859, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, - 0x00c0, 0x4854, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0079, - 0x4c82, 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0040, 0x486b, 0x6056, + 0x6116, 0x6112, 0x0078, 0x4833, 0x0d7e, 0x2069, 0x7836, 0x6000, + 0xd0d4, 0x0040, 0x4851, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, + 0x00c0, 0x484c, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0079, + 0x4c7a, 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0040, 0x4863, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, - 0x7836, 0x0078, 0x484b, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, - 0x0078, 0x484b, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, + 0x7836, 0x0078, 0x4843, 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, + 0x0078, 0x4843, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6020, 0x8000, 0x6022, - 0x6008, 0xa005, 0x0040, 0x488d, 0xa080, 0x0003, 0x2102, 0x610a, + 0x6008, 0xa005, 0x0040, 0x4885, 0xa080, 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, 0x610e, 0x610a, 0x0078, - 0x4888, 0x0c7e, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6034, - 0xa005, 0x0040, 0x48a1, 0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, - 0x007c, 0x613a, 0x6136, 0x0078, 0x489f, 0x0f7e, 0x0e7e, 0x0d7e, + 0x4880, 0x0c7e, 0x600f, 0x0000, 0x2c08, 0x2061, 0x7836, 0x6034, + 0xa005, 0x0040, 0x4899, 0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, + 0x007c, 0x613a, 0x6136, 0x0078, 0x4897, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2071, 0x7836, 0x7638, - 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x4907, 0x6018, - 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x4902, 0x703c, 0xac06, - 0x00c0, 0x48c7, 0x6003, 0x000a, 0x630a, 0x0078, 0x4902, 0x7038, - 0xac36, 0x00c0, 0x48cd, 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, - 0x48db, 0x2c00, 0xaf36, 0x0040, 0x48d9, 0x2f00, 0x7036, 0x0078, - 0x48db, 0x7037, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, - 0x48e4, 0x7e0e, 0x0078, 0x48e5, 0x2678, 0x600f, 0x0000, 0x1078, - 0x693e, 0x0040, 0x48fd, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, - 0x00c0, 0x4910, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x6b3f, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x0c7f, - 0x0078, 0x48b4, 0x2c78, 0x600c, 0x2060, 0x0078, 0x48b4, 0x127f, + 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x48ff, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x48fa, 0x703c, 0xac06, + 0x00c0, 0x48bf, 0x6003, 0x000a, 0x630a, 0x0078, 0x48fa, 0x7038, + 0xac36, 0x00c0, 0x48c5, 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, + 0x48d3, 0x2c00, 0xaf36, 0x0040, 0x48d1, 0x2f00, 0x7036, 0x0078, + 0x48d3, 0x7037, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, + 0x48dc, 0x7e0e, 0x0078, 0x48dd, 0x2678, 0x600f, 0x0000, 0x1078, + 0x6938, 0x0040, 0x48f5, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, + 0x00c0, 0x4908, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x6b34, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x0c7f, + 0x0078, 0x48ac, 0x2c78, 0x600c, 0x2060, 0x0078, 0x48ac, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, - 0x601c, 0xa086, 0x0006, 0x00c0, 0x48f2, 0x1078, 0x74fd, 0x0078, - 0x48fd, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x48ea, 0x1078, 0x74f2, 0x0078, + 0x48f5, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, 0x127e, 0x2091, 0x8000, 0x2079, 0x7836, 0x7838, 0xa065, 0x0040, - 0x4950, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, - 0x4937, 0x6003, 0x000a, 0x630a, 0x2c30, 0x0078, 0x494d, 0x1078, - 0x693e, 0x0040, 0x494b, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, - 0x00c0, 0x4959, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x007f, 0x0078, 0x4926, + 0x4948, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, + 0x492f, 0x6003, 0x000a, 0x630a, 0x2c30, 0x0078, 0x4945, 0x1078, + 0x6938, 0x0040, 0x4943, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, + 0x00c0, 0x4951, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x007f, 0x0078, 0x491e, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, 0x007f, - 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x4942, 0x1078, 0x74fd, - 0x0078, 0x494b, 0x027e, 0x1078, 0x4976, 0x1078, 0x4a0f, 0x027f, + 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x493a, 0x1078, 0x74f2, + 0x0078, 0x4943, 0x027e, 0x1078, 0x496e, 0x1078, 0x4a07, 0x027f, 0x007c, 0x0f7e, 0x127e, 0x2079, 0x7836, 0x2091, 0x8000, 0x1078, - 0x4aa6, 0x1078, 0x4b0e, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, + 0x4a9e, 0x1078, 0x4b06, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x7836, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x49fe, 0x6018, - 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x49f9, 0x7024, 0xac06, - 0x00c0, 0x49bc, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x49b7, - 0x1078, 0x5582, 0x68c3, 0x0000, 0x1078, 0x5a32, 0x7027, 0x0000, - 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x49ac, + 0x7836, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x49f6, 0x6018, + 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x49f1, 0x7024, 0xac06, + 0x00c0, 0x49b4, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x49af, + 0x1078, 0x557a, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, + 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x49a4, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, - 0x0040, 0x49b4, 0x6827, 0x0001, 0x037f, 0x0078, 0x49bc, 0x6003, - 0x0009, 0x630a, 0x0078, 0x49f9, 0x7014, 0xac36, 0x00c0, 0x49c2, - 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x49d0, 0x2c00, 0xaf36, - 0x0040, 0x49ce, 0x2f00, 0x7012, 0x0078, 0x49d0, 0x7013, 0x0000, - 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x49d9, 0x7e0e, 0x0078, - 0x49da, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x49f2, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4a06, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, 0x1078, 0x3a7a, - 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, - 0x4984, 0x2c78, 0x600c, 0x2060, 0x0078, 0x4984, 0x127f, 0x007f, + 0x0040, 0x49ac, 0x6827, 0x0001, 0x037f, 0x0078, 0x49b4, 0x6003, + 0x0009, 0x630a, 0x0078, 0x49f1, 0x7014, 0xac36, 0x00c0, 0x49ba, + 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x49c8, 0x2c00, 0xaf36, + 0x0040, 0x49c6, 0x2f00, 0x7012, 0x0078, 0x49c8, 0x7013, 0x0000, + 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x49d1, 0x7e0e, 0x0078, + 0x49d2, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x49ea, 0x601c, 0xa086, 0x0003, 0x00c0, 0x49fe, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, 0x1078, 0x3a72, + 0x1078, 0x6a89, 0x1078, 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, + 0x497c, 0x2c78, 0x600c, 0x2060, 0x0078, 0x497c, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, - 0x0006, 0x00c0, 0x49e7, 0x1078, 0x74fd, 0x0078, 0x49f2, 0x0c7e, + 0x0006, 0x00c0, 0x49df, 0x1078, 0x74f2, 0x0078, 0x49ea, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0x7720, 0x2004, 0xa065, - 0x0040, 0x4aa2, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, 0x2071, 0x7836, - 0x6654, 0x7018, 0xac06, 0x00c0, 0x4a26, 0x761a, 0x701c, 0xac06, - 0x00c0, 0x4a32, 0x86ff, 0x00c0, 0x4a31, 0x7018, 0x701e, 0x0078, - 0x4a32, 0x761e, 0x6058, 0xa07d, 0x0040, 0x4a37, 0x7e56, 0xa6ed, - 0x0000, 0x0040, 0x4a3d, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, - 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x37a2, 0x0040, - 0x4a9e, 0x7624, 0x86ff, 0x0040, 0x4a8e, 0xa680, 0x0004, 0x2004, - 0xad06, 0x00c0, 0x4a8e, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x4a85, 0x1078, 0x5582, 0x68c3, 0x0000, 0x1078, 0x5a32, + 0x0040, 0x4a9a, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, 0x2071, 0x7836, + 0x6654, 0x7018, 0xac06, 0x00c0, 0x4a1e, 0x761a, 0x701c, 0xac06, + 0x00c0, 0x4a2a, 0x86ff, 0x00c0, 0x4a29, 0x7018, 0x701e, 0x0078, + 0x4a2a, 0x761e, 0x6058, 0xa07d, 0x0040, 0x4a2f, 0x7e56, 0xa6ed, + 0x0000, 0x0040, 0x4a35, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, + 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x379a, 0x0040, + 0x4a96, 0x7624, 0x86ff, 0x0040, 0x4a86, 0xa680, 0x0004, 0x2004, + 0xad06, 0x00c0, 0x4a86, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x4a7d, 0x1078, 0x557a, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x4a6e, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x4a76, 0x6827, 0x0001, 0x037f, 0x0d7f, - 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4a7f, 0x8001, 0x603e, 0x2660, - 0x1078, 0x6aa1, 0x0c7f, 0x0078, 0x4a8e, 0x0d7f, 0x0c7e, 0x2660, - 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x4a45, 0x8dff, 0x0040, - 0x4a9a, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b3f, - 0x1078, 0x3a7a, 0x1078, 0x5902, 0x0078, 0x4a45, 0x067f, 0x0d7f, + 0x0040, 0x4a66, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x4a6e, 0x6827, 0x0001, 0x037f, 0x0d7f, + 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4a77, 0x8001, 0x603e, 0x2660, + 0x1078, 0x6a96, 0x0c7f, 0x0078, 0x4a86, 0x0d7f, 0x0c7e, 0x2660, + 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x4a3d, 0x8dff, 0x0040, + 0x4a92, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x6b34, + 0x1078, 0x3a72, 0x1078, 0x58fa, 0x0078, 0x4a3d, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f, 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, - 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x4afe, - 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x4ae3, - 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x4add, 0x1078, 0x5582, - 0x68c3, 0x0000, 0x1078, 0x5a32, 0x7827, 0x0000, 0x037e, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x4ad2, 0x6803, 0x0100, - 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4ada, - 0x6827, 0x0001, 0x037f, 0x0078, 0x4ae3, 0x6003, 0x0009, 0x630a, - 0x2c30, 0x0078, 0x4afb, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, - 0x4af7, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4b05, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, - 0x6aa1, 0x1078, 0x5902, 0x007f, 0x0078, 0x4aad, 0x7e16, 0x7e12, + 0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x4af6, + 0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x4adb, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x4ad5, 0x1078, 0x557a, + 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7827, 0x0000, 0x037e, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x4aca, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4ad2, + 0x6827, 0x0001, 0x037f, 0x0078, 0x4adb, 0x6003, 0x0009, 0x630a, + 0x2c30, 0x0078, 0x4af3, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, + 0x4aef, 0x601c, 0xa086, 0x0003, 0x00c0, 0x4afd, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x1078, + 0x6a96, 0x1078, 0x58fa, 0x007f, 0x0078, 0x4aa5, 0x7e16, 0x7e12, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, - 0x00c0, 0x4aee, 0x1078, 0x74fd, 0x0078, 0x4af7, 0x007e, 0x067e, - 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b7a, 0x6054, 0x007e, + 0x00c0, 0x4ae6, 0x1078, 0x74f2, 0x0078, 0x4aef, 0x007e, 0x067e, + 0x0c7e, 0x0d7e, 0x7818, 0xa065, 0x0040, 0x4b72, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, - 0x1078, 0x37a2, 0x0040, 0x4b77, 0x7e24, 0x86ff, 0x0040, 0x4b69, - 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x4b69, 0x0d7e, 0x2069, - 0x0100, 0x68c0, 0xa005, 0x0040, 0x4b60, 0x1078, 0x5582, 0x68c3, - 0x0000, 0x1078, 0x5a32, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, - 0x6b04, 0xa384, 0x1000, 0x0040, 0x4b49, 0x6803, 0x0100, 0x6803, - 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4b51, 0x6827, - 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4b5a, - 0x8001, 0x603e, 0x2660, 0x1078, 0x6aa1, 0x0c7f, 0x0078, 0x4b69, + 0x1078, 0x379a, 0x0040, 0x4b6f, 0x7e24, 0x86ff, 0x0040, 0x4b61, + 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x4b61, 0x0d7e, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x0040, 0x4b58, 0x1078, 0x557a, 0x68c3, + 0x0000, 0x1078, 0x5a2a, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, + 0x6b04, 0xa384, 0x1000, 0x0040, 0x4b41, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x4b49, 0x6827, + 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x4b52, + 0x8001, 0x603e, 0x2660, 0x1078, 0x6a96, 0x0c7f, 0x0078, 0x4b61, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, - 0x4b20, 0x8dff, 0x0040, 0x4b73, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x5902, 0x0078, 0x4b20, 0x007f, - 0x0078, 0x4b13, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, + 0x4b18, 0x8dff, 0x0040, 0x4b6b, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x3a72, 0x1078, 0x58fa, 0x0078, 0x4b18, 0x007f, + 0x0078, 0x4b0b, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x0e7e, 0x0c7e, 0x2071, 0x7836, 0x7004, 0xa084, 0x0007, - 0x0079, 0x4b8a, 0x4b94, 0x4b97, 0x4bb0, 0x4bcc, 0x4c11, 0x4b94, - 0x4b94, 0x4b92, 0x1078, 0x12d5, 0x0c7f, 0x0e7f, 0x007c, 0x7024, - 0xa065, 0x0040, 0x4ba5, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, - 0x0040, 0x4bac, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, - 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x4ba5, - 0x6018, 0x2060, 0x1078, 0x37a2, 0x6000, 0xc0dc, 0x6002, 0x7020, - 0x8001, 0x7022, 0x0040, 0x4bc1, 0x6054, 0xa015, 0x0040, 0x4bc8, + 0x0079, 0x4b82, 0x4b8c, 0x4b8f, 0x4ba8, 0x4bc4, 0x4c09, 0x4b8c, + 0x4b8c, 0x4b8a, 0x1078, 0x12cd, 0x0c7f, 0x0e7f, 0x007c, 0x7024, + 0xa065, 0x0040, 0x4b9d, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, + 0x0040, 0x4ba4, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, + 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x4b9d, + 0x6018, 0x2060, 0x1078, 0x379a, 0x6000, 0xc0dc, 0x6002, 0x7020, + 0x8001, 0x7022, 0x0040, 0x4bb9, 0x6054, 0xa015, 0x0040, 0x4bc0, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, - 0x7218, 0x721e, 0x0078, 0x4bc1, 0x7024, 0xa065, 0x0040, 0x4c0e, - 0x700c, 0xac06, 0x00c0, 0x4be3, 0x1078, 0x5902, 0x600c, 0xa015, - 0x0040, 0x4bdf, 0x720e, 0x600f, 0x0000, 0x0078, 0x4c0c, 0x720e, - 0x720a, 0x0078, 0x4c0c, 0x7014, 0xac06, 0x00c0, 0x4bf6, 0x1078, - 0x5902, 0x600c, 0xa015, 0x0040, 0x4bf2, 0x7216, 0x600f, 0x0000, - 0x0078, 0x4c0c, 0x7216, 0x7212, 0x0078, 0x4c0c, 0x6018, 0x2060, - 0x1078, 0x37a2, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x5902, 0x701c, - 0xa065, 0x0040, 0x4c0c, 0x6054, 0xa015, 0x0040, 0x4c0a, 0x721e, - 0x0078, 0x4c0c, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, - 0x007c, 0x7024, 0xa065, 0x0040, 0x4c1e, 0x1078, 0x5902, 0x600c, - 0xa015, 0x0040, 0x4c25, 0x720e, 0x600f, 0x0000, 0x1078, 0x5a32, + 0x7218, 0x721e, 0x0078, 0x4bb9, 0x7024, 0xa065, 0x0040, 0x4c06, + 0x700c, 0xac06, 0x00c0, 0x4bdb, 0x1078, 0x58fa, 0x600c, 0xa015, + 0x0040, 0x4bd7, 0x720e, 0x600f, 0x0000, 0x0078, 0x4c04, 0x720e, + 0x720a, 0x0078, 0x4c04, 0x7014, 0xac06, 0x00c0, 0x4bee, 0x1078, + 0x58fa, 0x600c, 0xa015, 0x0040, 0x4bea, 0x7216, 0x600f, 0x0000, + 0x0078, 0x4c04, 0x7216, 0x7212, 0x0078, 0x4c04, 0x6018, 0x2060, + 0x1078, 0x379a, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x58fa, 0x701c, + 0xa065, 0x0040, 0x4c04, 0x6054, 0xa015, 0x0040, 0x4c02, 0x721e, + 0x0078, 0x4c04, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, + 0x007c, 0x7024, 0xa065, 0x0040, 0x4c16, 0x1078, 0x58fa, 0x600c, + 0xa015, 0x0040, 0x4c1d, 0x720e, 0x600f, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, - 0x4c1e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa084, 0x0003, 0x0079, - 0x4c31, 0x4c37, 0x4c39, 0x4c5f, 0x4c37, 0x1078, 0x12d5, 0x0d7f, - 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x4c55, 0x683c, - 0xa065, 0x0040, 0x4c4a, 0x600c, 0xa015, 0x0040, 0x4c51, 0x6a3a, + 0x4c16, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa084, 0x0003, 0x0079, + 0x4c29, 0x4c2f, 0x4c31, 0x4c57, 0x4c2f, 0x1078, 0x12cd, 0x0d7f, + 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x4c4d, 0x683c, + 0xa065, 0x0040, 0x4c42, 0x600c, 0xa015, 0x0040, 0x4c49, 0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, - 0x007c, 0x683a, 0x6836, 0x0078, 0x4c4a, 0x6843, 0x0000, 0x6838, - 0xa065, 0x0040, 0x4c4a, 0x6003, 0x0003, 0x0078, 0x4c4a, 0x0c7e, - 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x4c77, - 0x600c, 0xa015, 0x0040, 0x4c73, 0x6a3a, 0x600f, 0x0000, 0x683f, - 0x0000, 0x0078, 0x4c77, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, + 0x007c, 0x683a, 0x6836, 0x0078, 0x4c42, 0x6843, 0x0000, 0x6838, + 0xa065, 0x0040, 0x4c42, 0x6003, 0x0003, 0x0078, 0x4c42, 0x0c7e, + 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x4c6f, + 0x600c, 0xa015, 0x0040, 0x4c6b, 0x6a3a, 0x600f, 0x0000, 0x683f, + 0x0000, 0x0078, 0x4c6f, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f, 0x007c, 0x0d7e, 0x2069, 0x7836, 0x6804, 0xa084, 0x0007, - 0x0079, 0x4c82, 0x4c8c, 0x4d29, 0x4d29, 0x4d29, 0x4d29, 0x4d2b, - 0x4d29, 0x4c8a, 0x1078, 0x12d5, 0x6820, 0xa005, 0x00c0, 0x4c92, - 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4ca1, 0x6807, - 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, 0x0d7f, - 0x007c, 0x6814, 0xa065, 0x0040, 0x4caf, 0x6807, 0x0001, 0x6826, - 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, - 0x037e, 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x4d24, 0x704c, 0xa00d, - 0x0040, 0x4cbe, 0x7088, 0xa005, 0x0040, 0x4cd6, 0x7054, 0xa075, - 0x0040, 0x4cc7, 0xa20e, 0x0040, 0x4d24, 0x0078, 0x4ccc, 0x6818, - 0xa20e, 0x0040, 0x4d24, 0x2070, 0x704c, 0xa00d, 0x0040, 0x4cbe, - 0x7088, 0xa005, 0x00c0, 0x4cbe, 0x2e00, 0x681e, 0x733c, 0x7038, - 0xa302, 0x00c8, 0x4cbe, 0x1078, 0x5bd1, 0x0040, 0x4d24, 0x8318, + 0x0079, 0x4c7a, 0x4c84, 0x4d21, 0x4d21, 0x4d21, 0x4d21, 0x4d23, + 0x4d21, 0x4c82, 0x1078, 0x12cd, 0x6820, 0xa005, 0x00c0, 0x4c8a, + 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4c99, 0x6807, + 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, + 0x007c, 0x6814, 0xa065, 0x0040, 0x4ca7, 0x6807, 0x0001, 0x6826, + 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, + 0x037e, 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x4d1c, 0x704c, 0xa00d, + 0x0040, 0x4cb6, 0x7088, 0xa005, 0x0040, 0x4cce, 0x7054, 0xa075, + 0x0040, 0x4cbf, 0xa20e, 0x0040, 0x4d1c, 0x0078, 0x4cc4, 0x6818, + 0xa20e, 0x0040, 0x4d1c, 0x2070, 0x704c, 0xa00d, 0x0040, 0x4cb6, + 0x7088, 0xa005, 0x00c0, 0x4cb6, 0x2e00, 0x681e, 0x733c, 0x7038, + 0xa302, 0x00c8, 0x4cb6, 0x1078, 0x5bc9, 0x0040, 0x4d1c, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, 0x0015, 0x2004, 0xa08a, - 0x199a, 0x0048, 0x4ced, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, + 0x199a, 0x0048, 0x4ce5, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, 0x0040, - 0x4d06, 0x7100, 0xd1f4, 0x0040, 0x4d02, 0x7114, 0xa18c, 0x00ff, - 0x0078, 0x4d0b, 0x2009, 0x0000, 0x0078, 0x4d0b, 0xa1e0, 0x232f, - 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x51c2, + 0x4cfe, 0x7100, 0xd1f4, 0x0040, 0x4cfa, 0x7114, 0xa18c, 0x00ff, + 0x0078, 0x4d03, 0x2009, 0x0000, 0x0078, 0x4d03, 0xa1e0, 0x2329, + 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, 0x51ba, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, 0x0078, - 0x4d22, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4d37, - 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d71, 0x0c7f, + 0x4d1a, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x4d2f, + 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x4d69, 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0x7836, 0x6830, 0xa086, - 0x0000, 0x00c0, 0x4d58, 0x6838, 0xa07d, 0x0040, 0x4d58, 0x6833, + 0x0000, 0x00c0, 0x4d50, 0x6838, 0xa07d, 0x0040, 0x4d50, 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, 0x2200, - 0x027f, 0x1078, 0x1a4c, 0x00c0, 0x4d5b, 0x127f, 0x1078, 0x5457, + 0x027f, 0x1078, 0x1a44, 0x00c0, 0x4d53, 0x127f, 0x1078, 0x544f, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803, 0x0002, - 0x780c, 0xa015, 0x0040, 0x4d6d, 0x6a3a, 0x780f, 0x0000, 0x6833, - 0x0000, 0x683f, 0x0000, 0x0078, 0x4d58, 0x683a, 0x6836, 0x0078, - 0x4d67, 0x601c, 0xa084, 0x000f, 0x1079, 0x4d77, 0x007c, 0x4d80, - 0x4d85, 0x508c, 0x5182, 0x4d85, 0x508c, 0x5182, 0x4d80, 0x4d85, - 0x1078, 0x4b81, 0x1078, 0x4c7a, 0x007c, 0x157e, 0x137e, 0x147e, - 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, 0x6118, - 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x4da2, 0x7900, 0xd1f4, 0x0040, - 0x4d9e, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x4da7, 0x2009, 0x0000, - 0x0078, 0x4da7, 0xa1f8, 0x232f, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, - 0x2061, 0x0100, 0x619a, 0x1079, 0x4db3, 0x0f7f, 0x0c7f, 0x147f, - 0x137f, 0x157f, 0x007c, 0x4de5, 0x4e1d, 0x4e35, 0x4eb4, 0x4ee1, - 0x4ee9, 0x4f0a, 0x4f1b, 0x4f2c, 0x4f34, 0x4f45, 0x4f34, 0x4f8d, - 0x4f1b, 0x4fae, 0x4fb6, 0x4f2c, 0x4fb6, 0x4fc7, 0x4de3, 0x4de3, - 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, 0x4de3, - 0x4de3, 0x4de3, 0x5640, 0x5655, 0x5678, 0x569c, 0x4f0a, 0x4de3, - 0x4f0a, 0x4f34, 0x4de3, 0x4e35, 0x4eb4, 0x4de3, 0x5b4c, 0x4f34, - 0x4de3, 0x5b6f, 0x4f34, 0x1078, 0x12d5, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x0d7e, 0x2069, 0x7651, - 0x6804, 0xd084, 0x0040, 0x4dff, 0x6828, 0x20a3, 0x0000, 0x017e, - 0x1078, 0x209a, 0x21a2, 0x017f, 0x0d7f, 0x0078, 0x4e04, 0x0d7f, + 0x780c, 0xa015, 0x0040, 0x4d65, 0x6a3a, 0x780f, 0x0000, 0x6833, + 0x0000, 0x683f, 0x0000, 0x0078, 0x4d50, 0x683a, 0x6836, 0x0078, + 0x4d5f, 0x601c, 0xa084, 0x000f, 0x1079, 0x4d6f, 0x007c, 0x4d78, + 0x4d7d, 0x5084, 0x517a, 0x4d7d, 0x5084, 0x517a, 0x4d78, 0x4d7d, + 0x1078, 0x4b79, 0x1078, 0x4c72, 0x007c, 0x157e, 0x137e, 0x147e, + 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x6118, + 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x4d9a, 0x7900, 0xd1f4, 0x0040, + 0x4d96, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x4d9f, 0x2009, 0x0000, + 0x0078, 0x4d9f, 0xa1f8, 0x2329, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, + 0x2061, 0x0100, 0x619a, 0x1079, 0x4dab, 0x0f7f, 0x0c7f, 0x147f, + 0x137f, 0x157f, 0x007c, 0x4ddd, 0x4e15, 0x4e2d, 0x4eac, 0x4ed9, + 0x4ee1, 0x4f02, 0x4f13, 0x4f24, 0x4f2c, 0x4f3d, 0x4f2c, 0x4f85, + 0x4f13, 0x4fa6, 0x4fae, 0x4f24, 0x4fae, 0x4fbf, 0x4ddb, 0x4ddb, + 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, 0x4ddb, + 0x4ddb, 0x4ddb, 0x5638, 0x564d, 0x5670, 0x5694, 0x4f02, 0x4ddb, + 0x4f02, 0x4f2c, 0x4ddb, 0x4e2d, 0x4eac, 0x4ddb, 0x5b44, 0x4f2c, + 0x4ddb, 0x5b67, 0x4f2c, 0x1078, 0x12cd, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x0d7e, 0x2069, 0x7651, + 0x6804, 0xd084, 0x0040, 0x4df7, 0x6828, 0x20a3, 0x0000, 0x017e, + 0x1078, 0x2094, 0x21a2, 0x017f, 0x0d7f, 0x0078, 0x4dfc, 0x0d7f, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x7601, 0x53a6, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x001c, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6030, + 0x60c3, 0x001c, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, - 0x60c3, 0x0010, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x4fdc, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, - 0x4e48, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0078, 0x4e4a, + 0x60c3, 0x0010, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x4fd4, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, + 0x4e40, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0078, 0x4e42, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, - 0xa086, 0x007e, 0x00c0, 0x4e83, 0x2099, 0x7820, 0x33a6, 0x9398, + 0xa086, 0x007e, 0x00c0, 0x4e7b, 0x2099, 0x7820, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0x7601, 0x53a6, 0x20a9, 0x0010, 0x20a3, 0x0000, 0x00f0, 0x4e74, + 0x7601, 0x53a6, 0x20a9, 0x0010, 0x20a3, 0x0000, 0x00f0, 0x4e6c, 0x2099, 0x7828, 0x33a6, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, - 0x4e7d, 0x0078, 0x4ea3, 0x2099, 0x7820, 0x20a9, 0x0008, 0x53a6, + 0x4e75, 0x0078, 0x4e9b, 0x2099, 0x7820, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x7605, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0x7601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e94, - 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e9a, 0x2099, 0x7828, + 0x7601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e8c, + 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x4e92, 0x2099, 0x7828, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, - 0x4ea5, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4eab, 0x60c3, - 0x0074, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, + 0x4e9d, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x4ea3, 0x60c3, + 0x0074, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, - 0x7651, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x4ed0, 0xa085, 0x0020, - 0xd1a4, 0x0040, 0x4ed5, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x556e, - 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x5000, 0x0078, - 0x4e4a, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x2110, 0x20a3, + 0x7651, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x4ec8, 0xa085, 0x0020, + 0xd1a4, 0x0040, 0x4ecd, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x5566, + 0x007c, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x5000, 0x0078, + 0x4e42, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, - 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, 0x0200, + 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, - 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, + 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, - 0x0008, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x1078, 0x5053, - 0x20a3, 0x0200, 0x0078, 0x4e4a, 0x20a1, 0x020b, 0x1078, 0x5053, + 0x0008, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x1078, 0x504b, + 0x20a3, 0x0200, 0x0078, 0x4e42, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x7810, 0x20a2, - 0x60c3, 0x0008, 0x1078, 0x556e, 0x007c, 0x0d7e, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, - 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x4f6b, 0x6998, - 0xa184, 0xc000, 0x00c0, 0x4f67, 0xd1ec, 0x0040, 0x4f63, 0x20a3, - 0x2100, 0x0078, 0x4f6d, 0x20a3, 0x0100, 0x0078, 0x4f6d, 0x20a3, - 0x0400, 0x0078, 0x4f6d, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, + 0x60c3, 0x0008, 0x1078, 0x5566, 0x007c, 0x0d7e, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, + 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x4f63, 0x6998, + 0xa184, 0xc000, 0x00c0, 0x4f5f, 0xd1ec, 0x0040, 0x4f5b, 0x20a3, + 0x2100, 0x0078, 0x4f65, 0x20a3, 0x0100, 0x0078, 0x4f65, 0x20a3, + 0x0400, 0x0078, 0x4f65, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0x7651, 0x7904, 0x0f7f, - 0xd1ac, 0x00c0, 0x4f7d, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f82, + 0xd1ac, 0x00c0, 0x4f75, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x4f7a, 0xa085, 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, 0x60c3, - 0x0014, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, + 0x0014, 0x1078, 0x5566, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, + 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0014, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0200, 0x0078, 0x4deb, 0x20a1, 0x020b, - 0x1078, 0x5053, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, - 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x556e, 0x007c, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, 0x5053, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0200, 0x0078, 0x4de3, 0x20a1, 0x020b, + 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, + 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x5566, 0x007c, 0x20e1, + 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, 0x504b, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, - 0x0008, 0x1078, 0x556e, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, + 0x0008, 0x1078, 0x5566, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, - 0x4fef, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x0078, 0x501d, 0xa286, - 0x007f, 0x00c0, 0x4ffa, 0x0d7e, 0x20a3, 0x22ff, 0x20a3, 0xfffd, - 0x0078, 0x5011, 0xd2bc, 0x0040, 0x5019, 0xa286, 0x0080, 0x0d7e, - 0x00c0, 0x5008, 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0078, 0x5011, + 0x4fe7, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x0078, 0x5015, 0xa286, + 0x007f, 0x00c0, 0x4ff2, 0x0d7e, 0x20a3, 0x22ff, 0x20a3, 0xfffd, + 0x0078, 0x5009, 0xd2bc, 0x0040, 0x5011, 0xa286, 0x0080, 0x0d7e, + 0x00c0, 0x5000, 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0078, 0x5009, 0xa2e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x2200, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, - 0x5021, 0x20a3, 0x2200, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, - 0x22a2, 0x20a3, 0x0129, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, + 0x5019, 0x20a3, 0x2200, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, + 0x22a2, 0x20a3, 0x0129, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2, 0x0d7e, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x20a3, 0x2029, 0x20a3, 0x0000, - 0x0078, 0x5025, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, + 0x0078, 0x501d, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5072, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x506a, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x2300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x507a, 0x20a3, 0x2300, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0198, 0x20a3, 0x0000, 0x1078, 0x555d, + 0x0078, 0x5072, 0x20a3, 0x2300, 0x6298, 0x22a2, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0198, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, - 0x0085, 0x1048, 0x12d5, 0xa08a, 0x008c, 0x10c8, 0x12d5, 0x6118, - 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x50aa, 0x7900, 0xd1f4, 0x0040, - 0x50a6, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x50af, 0x2009, 0x0000, - 0x0078, 0x50af, 0xa1f8, 0x232f, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, - 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x1079, 0x50ba, 0x0f7f, - 0x0c7f, 0x007c, 0x50c3, 0x50ce, 0x50e8, 0x50c1, 0x50c1, 0x50c1, - 0x50c3, 0x1078, 0x12d5, 0x147e, 0x20a1, 0x020b, 0x1078, 0x50fb, - 0x60c3, 0x0000, 0x1078, 0x556e, 0x147f, 0x007c, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5128, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, + 0x0085, 0x1048, 0x12cd, 0xa08a, 0x008c, 0x10c8, 0x12cd, 0x6118, + 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x50a2, 0x7900, 0xd1f4, 0x0040, + 0x509e, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x50a7, 0x2009, 0x0000, + 0x0078, 0x50a7, 0xa1f8, 0x2329, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, + 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x1079, 0x50b2, 0x0f7f, + 0x0c7f, 0x007c, 0x50bb, 0x50c6, 0x50e0, 0x50b9, 0x50b9, 0x50b9, + 0x50bb, 0x1078, 0x12cd, 0x147e, 0x20a1, 0x020b, 0x1078, 0x50f3, + 0x60c3, 0x0000, 0x1078, 0x5566, 0x147f, 0x007c, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x5120, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x007c, - 0x147e, 0x20a1, 0x020b, 0x1078, 0x5155, 0x20a3, 0x0003, 0x20a3, + 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x5566, 0x147f, 0x007c, + 0x147e, 0x20a1, 0x020b, 0x1078, 0x514d, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x1078, - 0x556e, 0x147f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x511a, + 0x5566, 0x147f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x5112, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x5122, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0078, 0x5025, + 0x0078, 0x511a, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, + 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0078, 0x501d, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xa092, 0x007e, 0x0048, 0x5147, 0x0d7e, 0xa0e8, 0x7720, + 0x2004, 0xa092, 0x007e, 0x0048, 0x513f, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, - 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x514f, 0x20a3, + 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5147, 0x20a3, 0x8400, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, - 0x00d1, 0x20a3, 0x0000, 0x0078, 0x507e, 0x027e, 0x20e1, 0x9080, + 0x00d1, 0x20a3, 0x0000, 0x0078, 0x5076, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, - 0x0048, 0x5174, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0048, 0x516c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x517c, 0x20a3, 0x8500, 0x6298, 0x22a2, + 0x2da6, 0x0d7f, 0x0078, 0x5174, 0x20a3, 0x8500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x00d1, 0x20a3, 0x0000, - 0x0078, 0x507e, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, - 0x1048, 0x12d5, 0xa08a, 0x0050, 0x10c8, 0x12d5, 0x7918, 0x2160, - 0x61a0, 0xd1bc, 0x0040, 0x51a1, 0x6100, 0xd1f4, 0x0040, 0x519d, - 0x6114, 0xa18c, 0x00ff, 0x0078, 0x51a6, 0x2009, 0x0000, 0x0078, - 0x51a6, 0xa1e0, 0x232f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, - 0x619a, 0xa082, 0x0040, 0x1079, 0x51b0, 0x0f7f, 0x0c7f, 0x007c, - 0x51c2, 0x52aa, 0x5252, 0x53d2, 0x51c0, 0x51c0, 0x51c0, 0x51c0, - 0x51c0, 0x51c0, 0x51c0, 0x581b, 0x582c, 0x583d, 0x584e, 0x51c0, - 0x1078, 0x12d5, 0x0d7e, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x5215, 0x7910, 0x2168, 0x6944, 0xa18c, 0x00ff, 0x21a2, 0xa016, + 0x0078, 0x5076, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, + 0x1048, 0x12cd, 0xa08a, 0x0050, 0x10c8, 0x12cd, 0x7918, 0x2160, + 0x61a0, 0xd1bc, 0x0040, 0x5199, 0x6100, 0xd1f4, 0x0040, 0x5195, + 0x6114, 0xa18c, 0x00ff, 0x0078, 0x519e, 0x2009, 0x0000, 0x0078, + 0x519e, 0xa1e0, 0x2329, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, + 0x619a, 0xa082, 0x0040, 0x1079, 0x51a8, 0x0f7f, 0x0c7f, 0x007c, + 0x51ba, 0x52a2, 0x524a, 0x53ca, 0x51b8, 0x51b8, 0x51b8, 0x51b8, + 0x51b8, 0x51b8, 0x51b8, 0x5813, 0x5824, 0x5835, 0x5846, 0x51b8, + 0x1078, 0x12cd, 0x0d7e, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, + 0x520d, 0x7910, 0x2168, 0x6944, 0xa18c, 0x00ff, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x0006, 0x8004, 0x20a2, - 0xd1ac, 0x0040, 0x51df, 0x20a3, 0x0002, 0x0078, 0x51eb, 0xd1b4, - 0x0040, 0x51e6, 0x20a3, 0x0001, 0x0078, 0x51eb, 0x20a3, 0x0000, - 0x2230, 0x0078, 0x51ed, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0xad80, - 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x51f1, 0x22a2, + 0xd1ac, 0x0040, 0x51d7, 0x20a3, 0x0002, 0x0078, 0x51e3, 0xd1b4, + 0x0040, 0x51de, 0x20a3, 0x0001, 0x0078, 0x51e3, 0x20a3, 0x0000, + 0x2230, 0x0078, 0x51e5, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0xad80, + 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x51e9, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0x7852, 0x2003, 0x07d0, 0x2001, 0x7851, 0x2003, 0x0009, 0x2001, 0x7857, 0x2003, 0x0002, 0x1078, - 0x1504, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x20e1, + 0x14fc, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, - 0x523b, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, + 0x5233, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, - 0x0d7f, 0x0078, 0x5243, 0x20a3, 0x0600, 0x6198, 0x21a2, 0x20a3, + 0x0d7f, 0x0078, 0x523b, 0x20a3, 0x0600, 0x6198, 0x21a2, 0x20a3, 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x5272, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, + 0x1078, 0x526a, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x60c3, 0x000c, 0x1078, 0x556e, 0x147f, 0x137f, 0x157f, + 0x20a2, 0x60c3, 0x000c, 0x1078, 0x5566, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5290, 0x0d7e, 0xa0e8, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x5288, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5298, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x5290, 0x20a3, 0x0500, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, - 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, 0x20a3, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x539a, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x00c0, 0x52c7, 0x7810, - 0xa084, 0x0700, 0x8007, 0x1079, 0x52cf, 0x0078, 0x52ca, 0xa006, - 0x1079, 0x52cf, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x52d9, - 0x533b, 0x533f, 0x5362, 0x536f, 0x5381, 0x5385, 0x52d7, 0x1078, - 0x12d5, 0x017e, 0x037e, 0x694c, 0xa18c, 0x0003, 0xa186, 0x0000, - 0x00c0, 0x52ec, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, - 0x037f, 0x017f, 0x0078, 0x5366, 0xa186, 0x0001, 0x00c0, 0x5336, + 0x1078, 0x5392, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x00c0, 0x52bf, 0x7810, + 0xa084, 0x0700, 0x8007, 0x1079, 0x52c7, 0x0078, 0x52c2, 0xa006, + 0x1079, 0x52c7, 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x52d1, + 0x5333, 0x5337, 0x535a, 0x5367, 0x5379, 0x537d, 0x52cf, 0x1078, + 0x12cd, 0x017e, 0x037e, 0x694c, 0xa18c, 0x0003, 0xa186, 0x0000, + 0x00c0, 0x52e4, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, + 0x037f, 0x017f, 0x0078, 0x535e, 0xa186, 0x0001, 0x00c0, 0x532e, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, - 0x0040, 0x5335, 0xd3c4, 0x0040, 0x5307, 0x687c, 0xa108, 0xd3cc, - 0x0040, 0x530c, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, - 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x5311, 0x157f, - 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x5335, 0x20a1, + 0x0040, 0x532d, 0xd3c4, 0x0040, 0x52ff, 0x687c, 0xa108, 0xd3cc, + 0x0040, 0x5304, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, + 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x5309, 0x157f, + 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x532d, 0x20a1, 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0898, 0x20a2, - 0x1078, 0x555d, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, 0x017f, - 0x1078, 0x556e, 0x007c, 0x20a3, 0x0008, 0x0078, 0x5364, 0x20a3, + 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f, 0x017f, + 0x1078, 0x5566, 0x007c, 0x20a3, 0x0008, 0x0078, 0x535c, 0x20a3, 0x0302, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x1078, - 0x556e, 0x007c, 0x20a3, 0x0028, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x556e, 0x007c, 0x20a3, + 0x5566, 0x007c, 0x20a3, 0x0028, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x5566, 0x007c, 0x20a3, 0x0100, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x556e, - 0x007c, 0x20a3, 0x0008, 0x0078, 0x5364, 0x037e, 0x7b10, 0xa384, - 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x5393, 0x22a2, - 0x037f, 0x0078, 0x5364, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x037f, - 0x0078, 0x5366, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x53b8, 0x0d7e, 0xa0e8, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x5566, + 0x007c, 0x20a3, 0x0008, 0x0078, 0x535c, 0x037e, 0x7b10, 0xa384, + 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x538b, 0x22a2, + 0x037f, 0x0078, 0x535c, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x037f, + 0x0078, 0x535e, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, + 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x53b0, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53c0, + 0x2069, 0x7619, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x53b8, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, - 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x555d, 0x22a2, 0x20a3, + 0x20a3, 0x0898, 0x20a3, 0x0000, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, - 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x53e5, 0x037f, 0x017f, - 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x53ed, 0x53ed, 0x53ef, - 0x53ed, 0x53ed, 0x53ed, 0x5414, 0x53ed, 0x1078, 0x12d5, 0x7910, + 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x53dd, 0x037f, 0x017f, + 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x53e5, 0x53e5, 0x53e7, + 0x53e5, 0x53e5, 0x53e5, 0x540c, 0x53e5, 0x1078, 0x12cd, 0x7910, 0xa18c, 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, - 0x0003, 0x1078, 0x541e, 0x0d7e, 0x2069, 0x7651, 0x6804, 0xd0bc, - 0x0040, 0x5409, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, - 0x540b, 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, - 0x0001, 0x1078, 0x556e, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, - 0x1078, 0x541e, 0x20a3, 0x7f00, 0x0078, 0x540c, 0x027e, 0x20e1, + 0x0003, 0x1078, 0x5416, 0x0d7e, 0x2069, 0x7651, 0x6804, 0xd0bc, + 0x0040, 0x5401, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, + 0x5403, 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, + 0x0001, 0x1078, 0x5566, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, + 0x1078, 0x5416, 0x20a3, 0x7f00, 0x0078, 0x5404, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, - 0x0040, 0x543c, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, + 0x0040, 0x5434, 0x0d7e, 0xa0e8, 0x7720, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x7619, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x5444, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x2da6, 0x0d7f, 0x0078, 0x543c, 0x20a3, 0x0100, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, - 0x21a2, 0x1078, 0x555d, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x21a2, 0x1078, 0x5555, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0x7600, 0x6130, 0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, - 0x5470, 0xa080, 0x232f, 0x2014, 0xa294, 0x00ff, 0x0078, 0x5474, + 0x5468, 0xa080, 0x2329, 0x2014, 0xa294, 0x00ff, 0x0078, 0x546c, 0x6910, 0x6a14, 0x7364, 0x7468, 0x781c, 0xa086, 0x0006, 0x0040, - 0x54c8, 0xd5bc, 0x0040, 0x5484, 0xa185, 0x0100, 0x6062, 0x6266, - 0x636a, 0x646e, 0x0078, 0x548a, 0x6063, 0x0100, 0x6266, 0x606b, + 0x54c0, 0xd5bc, 0x0040, 0x547c, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x5482, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, - 0x54bc, 0x6a00, 0xd2f4, 0x0040, 0x54ba, 0x6a14, 0xa294, 0x00ff, - 0x0078, 0x54bc, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, - 0x45f0, 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0x54b4, 0x6a00, 0xd2f4, 0x0040, 0x54b2, 0x6a14, 0xa294, 0x00ff, + 0x0078, 0x54b4, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, 0x1078, + 0x45e8, 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, - 0x5517, 0xd5bc, 0x0040, 0x54dc, 0xa185, 0x0100, 0x6062, 0x6266, - 0x636a, 0x646e, 0x0078, 0x54e2, 0x6063, 0x0100, 0x6266, 0x606b, + 0x550f, 0xd5bc, 0x0040, 0x54d4, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0078, 0x54da, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, - 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x5512, 0x6a00, - 0xd2f4, 0x0040, 0x5510, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5512, - 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x54bf, 0xd5bc, - 0x0040, 0x5522, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, - 0x0078, 0x5528, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, + 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x550a, 0x6a00, + 0xd2f4, 0x0040, 0x5508, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x550a, + 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x54b7, 0xd5bc, + 0x0040, 0x551a, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, + 0x0078, 0x5520, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, - 0x0000, 0xa582, 0x0080, 0x0048, 0x5558, 0x6a00, 0xd2f4, 0x0040, - 0x5556, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5558, 0x2011, 0x0000, - 0x629e, 0x6017, 0x0016, 0x0078, 0x54bf, 0x7a18, 0xa280, 0x0023, + 0x0000, 0xa582, 0x0080, 0x0048, 0x5550, 0x6a00, 0xd2f4, 0x0040, + 0x554e, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x5550, 0x2011, 0x0000, + 0x629e, 0x6017, 0x0016, 0x0078, 0x54b7, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, 0x7836, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, - 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5579, 0x1078, 0x45e0, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, 0x5571, 0x1078, 0x45d8, 0x007c, 0x007e, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, 0x007c, 0x007e, 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, - 0x0d7e, 0x017e, 0x027e, 0x1078, 0x45eb, 0x2061, 0x0100, 0x2069, - 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55cc, 0x1078, 0x5582, + 0x0d7e, 0x017e, 0x027e, 0x1078, 0x45e3, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55c4, 0x1078, 0x557a, 0x6803, 0x1000, 0x6803, 0x0000, 0x0c7e, 0x2061, 0x7836, 0x6128, - 0xa192, 0x0002, 0x00c8, 0x55b9, 0x8108, 0x612a, 0x6124, 0x0c7f, - 0x81ff, 0x0040, 0x55c7, 0x1078, 0x45e0, 0x1078, 0x5579, 0x0078, - 0x55c7, 0x6124, 0xa1e5, 0x0000, 0x0040, 0x55c4, 0x1078, 0x75c7, - 0x2009, 0x0014, 0x1078, 0x5c29, 0x0c7f, 0x0078, 0x55c7, 0x027f, - 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x1078, 0x357b, 0x0078, 0x55c7, - 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x45f9, 0x2071, - 0x7836, 0x713c, 0x81ff, 0x0040, 0x55fa, 0x2061, 0x0100, 0x2069, - 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x5600, 0x6803, 0x1000, - 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x5768, 0x037f, - 0x713c, 0x2160, 0x1078, 0x75c7, 0x2009, 0x004a, 0x1078, 0x5c29, - 0x0078, 0x55fa, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, - 0x7144, 0xa192, 0x0002, 0x00c8, 0x55ea, 0x8108, 0x7146, 0x1078, - 0x45f0, 0x0078, 0x55fa, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, + 0xa192, 0x0002, 0x00c8, 0x55b1, 0x8108, 0x612a, 0x6124, 0x0c7f, + 0x81ff, 0x0040, 0x55bf, 0x1078, 0x45d8, 0x1078, 0x5571, 0x0078, + 0x55bf, 0x6124, 0xa1e5, 0x0000, 0x0040, 0x55bc, 0x1078, 0x75bc, + 0x2009, 0x0014, 0x1078, 0x5c21, 0x0c7f, 0x0078, 0x55bf, 0x027f, + 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x1078, 0x3573, 0x0078, 0x55bf, + 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x45f1, 0x2071, + 0x7836, 0x713c, 0x81ff, 0x0040, 0x55f2, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x55f8, 0x6803, 0x1000, + 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x5760, 0x037f, + 0x713c, 0x2160, 0x1078, 0x75bc, 0x2009, 0x004a, 0x1078, 0x5c21, + 0x0078, 0x55f2, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, + 0x7144, 0xa192, 0x0002, 0x00c8, 0x55e2, 0x8108, 0x7146, 0x1078, + 0x45e8, 0x0078, 0x55f2, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, 0x047e, 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, - 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x5637, 0x68a0, - 0xa406, 0x0040, 0x5627, 0x6854, 0x2068, 0x0078, 0x561c, 0x6010, + 0x2071, 0x7836, 0x7018, 0x2068, 0x8dff, 0x0040, 0x562f, 0x68a0, + 0xa406, 0x0040, 0x561f, 0x6854, 0x2068, 0x0078, 0x5614, 0x6010, 0x2060, 0x643c, 0x6540, 0x6644, 0xa6b4, 0x000f, 0x2d60, 0x1078, - 0x38f9, 0x0040, 0x5637, 0x1078, 0x5902, 0xa085, 0x0001, 0x127f, + 0x38f1, 0x0040, 0x562f, 0x1078, 0x58fa, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, - 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fdc, 0x20a3, 0x0f00, + 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x4fd4, 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, - 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5053, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a9, + 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a9, 0x0006, 0x2011, 0x7640, 0x2019, 0x7641, 0x23a6, 0x22a6, 0xa398, - 0x0002, 0xa290, 0x0002, 0x00f0, 0x5665, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x001c, 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, - 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x5033, - 0x1078, 0x504a, 0x7810, 0x007e, 0xa080, 0x0015, 0x2098, 0x7808, + 0x0002, 0xa290, 0x0002, 0x00f0, 0x565d, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x001c, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, + 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x502b, + 0x1078, 0x5042, 0x7810, 0x007e, 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, - 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x556e, 0x027f, + 0x007f, 0xa080, 0x0001, 0x2004, 0x7812, 0x1078, 0x5566, 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x4fdc, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x556e, 0x147f, 0x157f, + 0x1078, 0x4fd4, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0x7836, 0x700c, 0x2060, 0x8cff, 0x0040, 0x56cd, 0x1078, 0x6ace, - 0x00c0, 0x56c4, 0x1078, 0x5e57, 0x600c, 0x007e, 0x1078, 0x5c02, - 0x1078, 0x5902, 0x0c7f, 0x0078, 0x56bb, 0x700f, 0x0000, 0x700b, + 0x7836, 0x700c, 0x2060, 0x8cff, 0x0040, 0x56c5, 0x1078, 0x6ac3, + 0x00c0, 0x56bc, 0x1078, 0x5e4d, 0x600c, 0x007e, 0x1078, 0x5bfa, + 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x56b3, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x7836, 0x7024, - 0x2060, 0x8cff, 0x0040, 0x5726, 0x1078, 0x5582, 0x68c3, 0x0000, - 0x1078, 0x45eb, 0x2009, 0x0013, 0x1078, 0x5c29, 0x20a9, 0x01f4, - 0x6824, 0xd094, 0x0040, 0x5709, 0x6827, 0x0004, 0x7804, 0xa084, - 0x4000, 0x0040, 0x571b, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, - 0x571b, 0xd084, 0x0040, 0x5710, 0x6827, 0x0001, 0x0078, 0x5712, - 0x00f0, 0x56f8, 0x7804, 0xa084, 0x1000, 0x0040, 0x571b, 0x7803, + 0x2060, 0x8cff, 0x0040, 0x571e, 0x1078, 0x557a, 0x68c3, 0x0000, + 0x1078, 0x45e3, 0x2009, 0x0013, 0x1078, 0x5c21, 0x20a9, 0x01f4, + 0x6824, 0xd094, 0x0040, 0x5701, 0x6827, 0x0004, 0x7804, 0xa084, + 0x4000, 0x0040, 0x5713, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, + 0x5713, 0xd084, 0x0040, 0x5708, 0x6827, 0x0001, 0x0078, 0x570a, + 0x00f0, 0x56f0, 0x7804, 0xa084, 0x1000, 0x0040, 0x5713, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x2001, 0x7600, - 0x2004, 0xa096, 0x0001, 0x0040, 0x575e, 0xa096, 0x0004, 0x0040, - 0x575e, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x3542, 0x1078, - 0x456e, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x574c, 0x6827, - 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x575e, 0x7803, 0x1000, - 0x7803, 0x0000, 0x0078, 0x575e, 0xd084, 0x0040, 0x5753, 0x6827, - 0x0001, 0x0078, 0x5755, 0x00f0, 0x573b, 0x7804, 0xa084, 0x1000, - 0x0040, 0x575e, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f, + 0x2004, 0xa096, 0x0001, 0x0040, 0x5756, 0xa096, 0x0004, 0x0040, + 0x5756, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x353a, 0x1078, + 0x4566, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x5744, 0x6827, + 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x5756, 0x7803, 0x1000, + 0x7803, 0x0000, 0x0078, 0x5756, 0xd084, 0x0040, 0x574b, 0x6827, + 0x0001, 0x0078, 0x574d, 0x00f0, 0x5733, 0x7804, 0xa084, 0x1000, + 0x0040, 0x5756, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, - 0x7836, 0x703c, 0x2060, 0x8cff, 0x0040, 0x57b6, 0x6817, 0x0010, - 0x68cb, 0x0000, 0x68c7, 0x0000, 0x1078, 0x45f9, 0x1078, 0x1c19, - 0xa39d, 0x0000, 0x00c0, 0x5790, 0x2009, 0x0049, 0x1078, 0x5c29, - 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x57a3, 0x6827, 0x0004, - 0x7804, 0xa084, 0x4000, 0x0040, 0x57b5, 0x7803, 0x1000, 0x7803, - 0x0000, 0x0078, 0x57b5, 0xd094, 0x0040, 0x57aa, 0x6827, 0x0002, - 0x0078, 0x57ac, 0x00f0, 0x5792, 0x7804, 0xa084, 0x1000, 0x0040, - 0x57b5, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, + 0x7836, 0x703c, 0x2060, 0x8cff, 0x0040, 0x57ae, 0x6817, 0x0010, + 0x68cb, 0x0000, 0x68c7, 0x0000, 0x1078, 0x45f1, 0x1078, 0x1c13, + 0xa39d, 0x0000, 0x00c0, 0x5788, 0x2009, 0x0049, 0x1078, 0x5c21, + 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x579b, 0x6827, 0x0004, + 0x7804, 0xa084, 0x4000, 0x0040, 0x57ad, 0x7803, 0x1000, 0x7803, + 0x0000, 0x0078, 0x57ad, 0xd094, 0x0040, 0x57a2, 0x6827, 0x0002, + 0x0078, 0x57a4, 0x00f0, 0x578a, 0x7804, 0xa084, 0x1000, 0x0040, + 0x57ad, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0x7836, 0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0x7836, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0x7836, 0x7614, 0x2660, 0x2678, 0x2091, - 0x8000, 0x8cff, 0x0040, 0x5814, 0x601c, 0xa206, 0x00c0, 0x580f, - 0x7014, 0xac36, 0x00c0, 0x57ee, 0x660c, 0x7616, 0x7010, 0xac36, - 0x00c0, 0x57fc, 0x2c00, 0xaf36, 0x0040, 0x57fa, 0x2f00, 0x7012, - 0x0078, 0x57fc, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, - 0x0040, 0x5805, 0x7e0e, 0x0078, 0x5806, 0x2678, 0x600f, 0x0000, - 0x1078, 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, 0x57e1, 0x2c78, - 0x600c, 0x2060, 0x0078, 0x57e1, 0x127f, 0x007f, 0x067f, 0x0c7f, + 0x8000, 0x8cff, 0x0040, 0x580c, 0x601c, 0xa206, 0x00c0, 0x5807, + 0x7014, 0xac36, 0x00c0, 0x57e6, 0x660c, 0x7616, 0x7010, 0xac36, + 0x00c0, 0x57f4, 0x2c00, 0xaf36, 0x0040, 0x57f2, 0x2f00, 0x7012, + 0x0078, 0x57f4, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, + 0x0040, 0x57fd, 0x7e0e, 0x0078, 0x57fe, 0x2678, 0x600f, 0x0000, + 0x1078, 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x57d9, 0x2c78, + 0x600c, 0x2060, 0x0078, 0x57d9, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, - 0x20a3, 0x4000, 0x0078, 0x585d, 0x157e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x20a3, 0x2000, 0x0078, 0x585d, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x585d, 0x157e, 0x147e, - 0x20a1, 0x020b, 0x1078, 0x5215, 0x7810, 0x20a2, 0xa006, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x590d, 0x60c3, - 0x0020, 0x1078, 0x556e, 0x147f, 0x157f, 0x007c, 0x127e, 0x0c7e, - 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0, 0x5875, - 0xd1bc, 0x00c0, 0x58bf, 0x0078, 0x58ff, 0x2009, 0x017f, 0x200b, + 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a3, 0x4000, 0x0078, 0x5855, 0x157e, 0x147e, 0x20a1, 0x020b, + 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x20a3, 0x2000, 0x0078, 0x5855, 0x157e, 0x147e, 0x20a1, + 0x020b, 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, + 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x5855, 0x157e, 0x147e, + 0x20a1, 0x020b, 0x1078, 0x520d, 0x7810, 0x20a2, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x5905, 0x60c3, + 0x0020, 0x1078, 0x5566, 0x147f, 0x157f, 0x007c, 0x127e, 0x0c7e, + 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0, 0x586d, + 0xd1bc, 0x00c0, 0x58b7, 0x0078, 0x58f7, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, - 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x58b6, 0x6020, - 0xd0b4, 0x0040, 0x58b6, 0x6024, 0xd094, 0x00c0, 0x58b6, 0x2104, - 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x58b6, 0x00f0, 0x5882, + 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x58ae, 0x6020, + 0xd0b4, 0x0040, 0x58ae, 0x6024, 0xd094, 0x00c0, 0x58ae, 0x2104, + 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x58ae, 0x00f0, 0x587a, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, 0xbc91, 0x6043, 0x0001, - 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0, 0x58b5, - 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58ac, 0x027f, 0x0d7f, 0x007f, - 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x58ff, 0x2009, + 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0, 0x58ad, + 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58a4, 0x027f, 0x0d7f, 0x007f, + 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x58f7, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, - 0x58f8, 0x6020, 0xd0bc, 0x0040, 0x58f8, 0x2104, 0xa084, 0x000f, - 0xa086, 0x0004, 0x00c0, 0x58f8, 0x00f0, 0x58cc, 0x027e, 0x6164, + 0x58f0, 0x6020, 0xd0bc, 0x0040, 0x58f0, 0x2104, 0xa084, 0x000f, + 0xa086, 0x0004, 0x00c0, 0x58f0, 0x00f0, 0x58c4, 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, 0x6043, 0x0000, - 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58f2, 0x027f, + 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x58ea, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0x7836, 0x7020, 0xa005, 0x0040, - 0x590b, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008, 0x20a2, - 0x00f0, 0x590f, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, + 0x5903, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008, 0x20a2, + 0x00f0, 0x5907, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, 0x0040, - 0x59a5, 0x8cff, 0x0040, 0x59a5, 0x601c, 0xa086, 0x0006, 0x00c0, - 0x59a0, 0x88ff, 0x0040, 0x593c, 0x2800, 0xac06, 0x00c0, 0x59a0, - 0x2039, 0x0000, 0x0078, 0x5940, 0x6018, 0xa206, 0x00c0, 0x59a0, - 0x7024, 0xac06, 0x00c0, 0x596e, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x5969, 0x6817, 0x0008, 0x68c3, 0x0000, 0x1078, 0x5a32, + 0x599d, 0x8cff, 0x0040, 0x599d, 0x601c, 0xa086, 0x0006, 0x00c0, + 0x5998, 0x88ff, 0x0040, 0x5934, 0x2800, 0xac06, 0x00c0, 0x5998, + 0x2039, 0x0000, 0x0078, 0x5938, 0x6018, 0xa206, 0x00c0, 0x5998, + 0x7024, 0xac06, 0x00c0, 0x5966, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x0040, 0x5961, 0x6817, 0x0008, 0x68c3, 0x0000, 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x595e, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x5966, 0x6827, 0x0001, 0x037f, 0x0078, - 0x596e, 0x6003, 0x0009, 0x630a, 0x0078, 0x59a0, 0x7014, 0xac36, - 0x00c0, 0x5974, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x5982, - 0x2c00, 0xaf36, 0x0040, 0x5980, 0x2f00, 0x7012, 0x0078, 0x5982, - 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x598b, - 0x7e0e, 0x0078, 0x598c, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x5996, 0x1078, 0x74fd, 0x1078, 0x6aa1, - 0x1078, 0x5902, 0x88ff, 0x00c0, 0x59af, 0x0c7f, 0x0078, 0x5926, - 0x2c78, 0x600c, 0x2060, 0x0078, 0x5926, 0xa006, 0x127f, 0x007f, + 0x0040, 0x5956, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0040, 0x595e, 0x6827, 0x0001, 0x037f, 0x0078, + 0x5966, 0x6003, 0x0009, 0x630a, 0x0078, 0x5998, 0x7014, 0xac36, + 0x00c0, 0x596c, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x597a, + 0x2c00, 0xaf36, 0x0040, 0x5978, 0x2f00, 0x7012, 0x0078, 0x597a, + 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5983, + 0x7e0e, 0x0078, 0x5984, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, + 0x1078, 0x6938, 0x0040, 0x598e, 0x1078, 0x74f2, 0x1078, 0x6a96, + 0x1078, 0x58fa, 0x88ff, 0x00c0, 0x59a7, 0x0c7f, 0x0078, 0x591e, + 0x2c78, 0x600c, 0x2060, 0x0078, 0x591e, 0xa006, 0x127f, 0x007f, 0x067f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, - 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x59a6, 0x0f7e, 0x0e7e, + 0x0000, 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x599e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, - 0x2071, 0x7836, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a21, - 0x601c, 0xa086, 0x0006, 0x00c0, 0x5a1c, 0x88ff, 0x0040, 0x59d6, - 0x2800, 0xac06, 0x00c0, 0x5a1c, 0x0078, 0x59da, 0x6018, 0xa206, - 0x00c0, 0x5a1c, 0x703c, 0xac06, 0x00c0, 0x59ec, 0x037e, 0x2019, - 0x0001, 0x1078, 0x5768, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, - 0x0000, 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x59f2, - 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x5a00, 0x2c00, 0xaf36, - 0x0040, 0x59fe, 0x2f00, 0x7036, 0x0078, 0x5a00, 0x7037, 0x0000, - 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5a09, 0x7e0e, 0x0078, - 0x5a0a, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x5a14, 0x1078, 0x74fd, 0x1078, 0x6aa1, 0x88ff, 0x00c0, - 0x5a2b, 0x0c7f, 0x0078, 0x59c5, 0x2c78, 0x600c, 0x2060, 0x0078, - 0x59c5, 0xa006, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, + 0x2071, 0x7836, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a19, + 0x601c, 0xa086, 0x0006, 0x00c0, 0x5a14, 0x88ff, 0x0040, 0x59ce, + 0x2800, 0xac06, 0x00c0, 0x5a14, 0x0078, 0x59d2, 0x6018, 0xa206, + 0x00c0, 0x5a14, 0x703c, 0xac06, 0x00c0, 0x59e4, 0x037e, 0x2019, + 0x0001, 0x1078, 0x5760, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, + 0x0000, 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x59ea, + 0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x59f8, 0x2c00, 0xaf36, + 0x0040, 0x59f6, 0x2f00, 0x7036, 0x0078, 0x59f8, 0x7037, 0x0000, + 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5a01, 0x7e0e, 0x0078, + 0x5a02, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x5a0c, 0x1078, 0x74f2, 0x1078, 0x6a96, 0x88ff, 0x00c0, + 0x5a23, 0x0c7f, 0x0078, 0x59bd, 0x2c78, 0x600c, 0x2060, 0x0078, + 0x59bd, 0xa006, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5, 0x0001, - 0x0078, 0x5a22, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, - 0xa086, 0x0002, 0x00c0, 0x5a40, 0x7007, 0x0005, 0x0078, 0x5a42, + 0x0078, 0x5a1a, 0x0e7e, 0x2071, 0x7836, 0x2001, 0x7600, 0x2004, + 0xa086, 0x0002, 0x00c0, 0x5a38, 0x7007, 0x0005, 0x0078, 0x5a3a, 0x7007, 0x0000, 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x2c10, - 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a82, 0x2200, 0xac06, - 0x00c0, 0x5a7d, 0x7038, 0xac36, 0x00c0, 0x5a60, 0x660c, 0x763a, - 0x7034, 0xac36, 0x00c0, 0x5a6e, 0x2c00, 0xaf36, 0x0040, 0x5a6c, - 0x2f00, 0x7036, 0x0078, 0x5a6e, 0x7037, 0x0000, 0x660c, 0x2c00, - 0xaf06, 0x0040, 0x5a76, 0x7e0e, 0x0078, 0x5a77, 0x2678, 0x600f, - 0x0000, 0xa085, 0x0001, 0x0078, 0x5a82, 0x2c78, 0x600c, 0x2060, - 0x0078, 0x5a53, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, + 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5a7a, 0x2200, 0xac06, + 0x00c0, 0x5a75, 0x7038, 0xac36, 0x00c0, 0x5a58, 0x660c, 0x763a, + 0x7034, 0xac36, 0x00c0, 0x5a66, 0x2c00, 0xaf36, 0x0040, 0x5a64, + 0x2f00, 0x7036, 0x0078, 0x5a66, 0x7037, 0x0000, 0x660c, 0x2c00, + 0xaf06, 0x0040, 0x5a6e, 0x7e0e, 0x0078, 0x5a6f, 0x2678, 0x600f, + 0x0000, 0xa085, 0x0001, 0x0078, 0x5a7a, 0x2c78, 0x600c, 0x2060, + 0x0078, 0x5a4b, 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0x7836, 0x760c, 0x2660, 0x2678, - 0x8cff, 0x0040, 0x5b1b, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, - 0x00c0, 0x5b16, 0x7024, 0xac06, 0x00c0, 0x5ac9, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x5ac9, 0x1078, 0x5582, 0x68c3, 0x0000, - 0x1078, 0x5a32, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, - 0xa384, 0x1000, 0x0040, 0x5ac0, 0x6803, 0x0100, 0x6803, 0x0000, - 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ac8, 0x6827, 0x0001, - 0x037f, 0x700c, 0xac36, 0x00c0, 0x5acf, 0x660c, 0x760e, 0x7008, - 0xac36, 0x00c0, 0x5add, 0x2c00, 0xaf36, 0x0040, 0x5adb, 0x2f00, - 0x700a, 0x0078, 0x5add, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, - 0xaf06, 0x0040, 0x5ae6, 0x7e0e, 0x0078, 0x5ae7, 0x2678, 0x600f, - 0x0000, 0x1078, 0x6aba, 0x00c0, 0x5af1, 0x1078, 0x22dd, 0x0078, - 0x5b0d, 0x1078, 0x6ace, 0x00c0, 0x5af9, 0x1078, 0x5e57, 0x0078, - 0x5b0d, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x5b0d, 0x601c, - 0xa086, 0x0003, 0x00c0, 0x5b23, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x6003, 0x0000, 0x1078, - 0x6aa1, 0x1078, 0x5902, 0x0c7f, 0x0078, 0x5a98, 0x2c78, 0x600c, - 0x2060, 0x0078, 0x5a98, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, - 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5b04, - 0x1078, 0x74fd, 0x0078, 0x5b0d, 0x037e, 0x157e, 0x137e, 0x147e, - 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x214f, 0x00c0, - 0x5b3d, 0x8210, 0x8000, 0x0078, 0x5b34, 0xa005, 0x0040, 0x5b47, + 0x8cff, 0x0040, 0x5b13, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, + 0x00c0, 0x5b0e, 0x7024, 0xac06, 0x00c0, 0x5ac1, 0x2069, 0x0100, + 0x68c0, 0xa005, 0x0040, 0x5ac1, 0x1078, 0x557a, 0x68c3, 0x0000, + 0x1078, 0x5a2a, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0040, 0x5ab8, 0x6803, 0x0100, 0x6803, 0x0000, + 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ac0, 0x6827, 0x0001, + 0x037f, 0x700c, 0xac36, 0x00c0, 0x5ac7, 0x660c, 0x760e, 0x7008, + 0xac36, 0x00c0, 0x5ad5, 0x2c00, 0xaf36, 0x0040, 0x5ad3, 0x2f00, + 0x700a, 0x0078, 0x5ad5, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, + 0xaf06, 0x0040, 0x5ade, 0x7e0e, 0x0078, 0x5adf, 0x2678, 0x600f, + 0x0000, 0x1078, 0x6aaf, 0x00c0, 0x5ae9, 0x1078, 0x22d7, 0x0078, + 0x5b05, 0x1078, 0x6ac3, 0x00c0, 0x5af1, 0x1078, 0x5e4d, 0x0078, + 0x5b05, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x5b05, 0x601c, + 0xa086, 0x0003, 0x00c0, 0x5b1b, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x6003, 0x0000, 0x1078, + 0x6a96, 0x1078, 0x58fa, 0x0c7f, 0x0078, 0x5a90, 0x2c78, 0x600c, + 0x2060, 0x0078, 0x5a90, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, + 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5afc, + 0x1078, 0x74f2, 0x0078, 0x5b05, 0x037e, 0x157e, 0x137e, 0x147e, + 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x2149, 0x00c0, + 0x5b35, 0x8210, 0x8000, 0x0078, 0x5b2c, 0xa005, 0x0040, 0x5b3f, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x147f, 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, - 0x5053, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, + 0x504b, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x514c, 0x20a3, 0x4f47, 0x20a3, 0x4943, 0x20a3, 0x2020, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x1078, 0x556e, 0x0d7f, 0x007c, 0x20a1, - 0x020b, 0x1078, 0x5053, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x1078, 0x5566, 0x0d7f, 0x007c, 0x20a1, + 0x020b, 0x1078, 0x504b, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0018, 0x1078, 0x556e, 0x007c, 0x2061, 0x7d00, 0x2a70, 0x7060, + 0x0018, 0x1078, 0x5566, 0x007c, 0x2061, 0x7d00, 0x2a70, 0x7060, 0x7046, 0x704b, 0x7d00, 0x007c, 0x0e7e, 0x127e, 0x2071, 0x7600, - 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0048, 0x5bce, 0x7048, - 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bba, 0xace0, 0x0008, - 0x7054, 0xac02, 0x00c8, 0x5bb6, 0x0078, 0x5ba9, 0x2061, 0x7d00, - 0x0078, 0x5ba9, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0008, - 0x7054, 0xa502, 0x00c8, 0x5bca, 0x754a, 0xa085, 0x0001, 0x127f, - 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bc5, 0xa006, 0x0078, - 0x5bc7, 0x0e7e, 0x2071, 0x7600, 0x7544, 0xa582, 0x0001, 0x0048, - 0x5bff, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bec, - 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x5be8, 0x0078, 0x5bdb, - 0x2061, 0x7d00, 0x0078, 0x5bdb, 0x6003, 0x0008, 0x8529, 0x7546, - 0xaca8, 0x0008, 0x7054, 0xa502, 0x00c8, 0x5bfb, 0x754a, 0xa085, - 0x0001, 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bf7, 0xa006, - 0x0078, 0x5bf9, 0xac82, 0x7d00, 0x1048, 0x12d5, 0x2001, 0x7615, - 0x2004, 0xac02, 0x10c8, 0x12d5, 0xa006, 0x6006, 0x600a, 0x600e, + 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0048, 0x5bc6, 0x7048, + 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5bb2, 0xace0, 0x0008, + 0x7054, 0xac02, 0x00c8, 0x5bae, 0x0078, 0x5ba1, 0x2061, 0x7d00, + 0x0078, 0x5ba1, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0008, + 0x7054, 0xa502, 0x00c8, 0x5bc2, 0x754a, 0xa085, 0x0001, 0x127f, + 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bbd, 0xa006, 0x0078, + 0x5bbf, 0x0e7e, 0x2071, 0x7600, 0x7544, 0xa582, 0x0001, 0x0048, + 0x5bf7, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, 0x5be4, + 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x5be0, 0x0078, 0x5bd3, + 0x2061, 0x7d00, 0x0078, 0x5bd3, 0x6003, 0x0008, 0x8529, 0x7546, + 0xaca8, 0x0008, 0x7054, 0xa502, 0x00c8, 0x5bf3, 0x754a, 0xa085, + 0x0001, 0x0e7f, 0x007c, 0x704b, 0x7d00, 0x0078, 0x5bef, 0xa006, + 0x0078, 0x5bf1, 0xac82, 0x7d00, 0x1048, 0x12cd, 0x2001, 0x7615, + 0x2004, 0xac02, 0x10c8, 0x12cd, 0xa006, 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x2061, - 0x7600, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0040, 0x5c21, - 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x0078, - 0x5c20, 0x601c, 0xa084, 0x000f, 0x0079, 0x5c2e, 0x5c37, 0x5c3f, - 0x5c5b, 0x5c77, 0x6b4b, 0x6b67, 0x6b83, 0x5c37, 0x5c3f, 0xa18e, - 0x0047, 0x00c0, 0x5c3e, 0xa016, 0x1078, 0x1572, 0x007c, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x5c49, 0x067f, - 0x007c, 0x5c59, 0x5d40, 0x5e72, 0x5c59, 0x5ec9, 0x5c59, 0x5c59, - 0x5c59, 0x5cef, 0x6182, 0x5c59, 0x5c59, 0x5c59, 0x5c59, 0x5c59, - 0x5c59, 0x1078, 0x12d5, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x5c65, 0x067f, 0x007c, 0x5c75, 0x5c75, 0x5c75, - 0x5c75, 0x5c75, 0x5c75, 0x5c75, 0x5c75, 0x65f2, 0x66b8, 0x5c75, - 0x660b, 0x6664, 0x660b, 0x6664, 0x5c75, 0x1078, 0x12d5, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x5c81, 0x067f, - 0x007c, 0x5c91, 0x61c0, 0x6266, 0x6328, 0x647c, 0x5c91, 0x5c91, - 0x5c91, 0x619e, 0x65a7, 0x65ab, 0x5c91, 0x5c91, 0x5c91, 0x5c91, - 0x65d1, 0x1078, 0x12d5, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, + 0x7600, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0040, 0x5c19, + 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x0078, + 0x5c18, 0x601c, 0xa084, 0x000f, 0x0079, 0x5c26, 0x5c2f, 0x5c37, + 0x5c53, 0x5c6f, 0x6b40, 0x6b5c, 0x6b78, 0x5c2f, 0x5c37, 0xa18e, + 0x0047, 0x00c0, 0x5c36, 0xa016, 0x1078, 0x156a, 0x007c, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x5c41, 0x067f, + 0x007c, 0x5c51, 0x5d38, 0x5e68, 0x5c51, 0x5ebf, 0x5c51, 0x5c51, + 0x5c51, 0x5ce7, 0x6178, 0x5c51, 0x5c51, 0x5c51, 0x5c51, 0x5c51, + 0x5c51, 0x1078, 0x12cd, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x5c5d, 0x067f, 0x007c, 0x5c6d, 0x5c6d, 0x5c6d, + 0x5c6d, 0x5c6d, 0x5c6d, 0x5c6d, 0x5c6d, 0x65ec, 0x66b2, 0x5c6d, + 0x6605, 0x665e, 0x6605, 0x665e, 0x5c6d, 0x1078, 0x12cd, 0x067e, + 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x5c79, 0x067f, + 0x007c, 0x5c89, 0x61b6, 0x625c, 0x631e, 0x6476, 0x5c89, 0x5c89, + 0x5c89, 0x6194, 0x65a1, 0x65a5, 0x5c89, 0x5c89, 0x5c89, 0x5c89, + 0x65cb, 0x1078, 0x12cd, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, 0xa5a8, 0x0002, 0xa398, - 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x5ca1, 0x0e7e, 0x1078, 0x693e, - 0x0040, 0x5cb8, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, - 0x0e7f, 0x1078, 0x5c02, 0x007c, 0x0d7e, 0x037e, 0x7330, 0xa386, - 0x0200, 0x00c0, 0x5cc9, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, - 0xfffd, 0x6010, 0xa005, 0x0040, 0x5cd3, 0x2068, 0x6807, 0x0000, - 0x6837, 0x0103, 0x6b32, 0x1078, 0x5c02, 0x037f, 0x0d7f, 0x007c, + 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x5c99, 0x0e7e, 0x1078, 0x6938, + 0x0040, 0x5cb0, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, + 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x0d7e, 0x037e, 0x7330, 0xa386, + 0x0200, 0x00c0, 0x5cc1, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, + 0xfffd, 0x6010, 0xa005, 0x0040, 0x5ccb, 0x2068, 0x6807, 0x0000, + 0x6837, 0x0103, 0x6b32, 0x1078, 0x5bfa, 0x037f, 0x0d7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0xa1b6, - 0x0015, 0x00c0, 0x5cec, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, - 0x680e, 0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x5cad, 0x2100, - 0xa1b2, 0x0030, 0x10c8, 0x12d5, 0x0079, 0x5cf6, 0x5d28, 0x5d34, - 0x5d28, 0x5d28, 0x5d28, 0x5d28, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d28, 0x5d26, 0x5d28, - 0x5d28, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d28, 0x5d26, - 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x5d26, 0x1078, 0x12d5, - 0x6003, 0x0001, 0x6106, 0x1078, 0x4872, 0x127e, 0x2091, 0x8000, - 0x1078, 0x4c7a, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4872, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12d5, 0xa1b6, 0x0013, 0x00c0, - 0x5d4c, 0x2008, 0x0079, 0x5dd5, 0xa1b6, 0x0027, 0x00c0, 0x5da2, - 0x1078, 0x4b81, 0x6004, 0x1078, 0x6aba, 0x0040, 0x5d65, 0x1078, - 0x6ace, 0x0040, 0x5d9a, 0xa08e, 0x0021, 0x0040, 0x5d9e, 0xa08e, - 0x0022, 0x0040, 0x5d9a, 0x0078, 0x5d95, 0x1078, 0x22dd, 0x2001, - 0x0007, 0x1078, 0x37d1, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, - 0x5e57, 0xa186, 0x007e, 0x00c0, 0x5d7b, 0x2001, 0x762f, 0x2014, - 0xa295, 0x0001, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, - 0x0028, 0x1078, 0x4962, 0x1078, 0x48a5, 0x0c7e, 0x6018, 0xa065, - 0x0040, 0x5d8c, 0x1078, 0x39a6, 0x0c7f, 0x2c08, 0x1078, 0x737b, - 0x037f, 0x027f, 0x017f, 0x1078, 0x380d, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5e57, 0x0078, 0x5d95, 0x1078, 0x5e66, - 0x0078, 0x5d95, 0xa186, 0x0014, 0x00c0, 0x5d99, 0x1078, 0x4b81, - 0x1078, 0x22bb, 0x1078, 0x6aba, 0x00c0, 0x5dc2, 0x1078, 0x22dd, - 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, 0x5e57, 0xa186, 0x007e, - 0x00c0, 0x5dc0, 0x2001, 0x762f, 0x200c, 0xa18d, 0x0001, 0x2102, - 0x0078, 0x5d95, 0x1078, 0x6ace, 0x00c0, 0x5dca, 0x1078, 0x5e57, - 0x0078, 0x5d95, 0x6004, 0xa08e, 0x0021, 0x0040, 0x5dc6, 0xa08e, - 0x0022, 0x1040, 0x5e66, 0x0078, 0x5d95, 0x5e07, 0x5e09, 0x5e0d, - 0x5e11, 0x5e15, 0x5e19, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e1d, 0x5e23, 0x5e05, 0x5e2d, 0x5e23, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e23, 0x5e23, 0x5e05, - 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x5e05, 0x1078, 0x12d5, 0x0078, - 0x5e23, 0x2001, 0x000b, 0x0078, 0x5e36, 0x2001, 0x0003, 0x0078, - 0x5e36, 0x2001, 0x0005, 0x0078, 0x5e36, 0x2001, 0x0001, 0x0078, - 0x5e36, 0x2001, 0x0009, 0x0078, 0x5e36, 0x1078, 0x12d5, 0x0078, - 0x5e35, 0x1078, 0x37d1, 0x1078, 0x4b81, 0x6003, 0x0002, 0x6017, - 0x0028, 0x1078, 0x4c7a, 0x0078, 0x5e35, 0x1078, 0x4b81, 0x6003, - 0x0004, 0x6017, 0x0028, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x37d1, - 0x1078, 0x4b81, 0x6003, 0x0002, 0x037e, 0x2019, 0x765c, 0x2304, - 0xa084, 0xff00, 0x00c0, 0x5e48, 0x2019, 0x0028, 0x0078, 0x5e51, - 0x8007, 0xa09a, 0x0004, 0x0048, 0x5e44, 0x8003, 0x801b, 0x831b, - 0xa318, 0x6316, 0x037f, 0x1078, 0x4c7a, 0x0078, 0x5e35, 0x0e7e, - 0x1078, 0x693e, 0x0040, 0x5e64, 0x6010, 0x2070, 0x7007, 0x0000, - 0x7037, 0x0103, 0x7033, 0x0100, 0x0e7f, 0x007c, 0x0e7e, 0xacf0, - 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, - 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, - 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x12d5, 0x6604, 0xa6b6, 0x0028, - 0x00c0, 0x5e86, 0x1078, 0x6b03, 0x0078, 0x5eb8, 0x6604, 0xa6b6, - 0x0029, 0x00c0, 0x5e8f, 0x1078, 0x6b1d, 0x0078, 0x5eb8, 0x6604, - 0xa6b6, 0x001f, 0x00c0, 0x5e98, 0x1078, 0x5c93, 0x0078, 0x5eb8, - 0x6604, 0xa6b6, 0x0000, 0x00c0, 0x5ea1, 0x1078, 0x5cd8, 0x0078, - 0x5eb8, 0x6604, 0xa6b6, 0x0022, 0x00c0, 0x5eaa, 0x1078, 0x5cbc, - 0x0078, 0x5eb8, 0xa1b6, 0x0015, 0x00c0, 0x5eb2, 0x1079, 0x5ebd, - 0x0078, 0x5eb8, 0xa1b6, 0x0016, 0x00c0, 0x5eb9, 0x1079, 0x5ffa, - 0x007c, 0x1078, 0x5c37, 0x0078, 0x5eb8, 0x5ee1, 0x5ee4, 0x5ee1, - 0x5f25, 0x5ee1, 0x5f96, 0x5ee1, 0x5ee1, 0x5ee1, 0x5fd2, 0x5ee1, - 0x5fe8, 0xa1b6, 0x0048, 0x0040, 0x5ed5, 0x20e1, 0x0005, 0x3d18, - 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, 0x0e7e, 0xacf0, 0x0004, - 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x5c02, - 0x007c, 0x0005, 0x0005, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, - 0xa086, 0x0074, 0x00c0, 0x5f0e, 0x1078, 0x734f, 0x00c0, 0x5f00, - 0x0d7e, 0x6018, 0x2068, 0x1078, 0x5f12, 0x0d7f, 0x2001, 0x0006, - 0x1078, 0x37d1, 0x1078, 0x22dd, 0x1078, 0x5c02, 0x0078, 0x5f10, - 0x2001, 0x000a, 0x1078, 0x37d1, 0x1078, 0x22dd, 0x6003, 0x0001, - 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x5f10, 0x1078, 0x5f86, - 0x0e7f, 0x007c, 0x6800, 0xd084, 0x0040, 0x5f24, 0x2001, 0x0000, - 0x1078, 0x37bd, 0x2069, 0x7651, 0x6804, 0xd0a4, 0x0040, 0x5f24, - 0x2001, 0x0006, 0x1078, 0x37df, 0x007c, 0x0d7e, 0x2011, 0x761e, - 0x2204, 0xa086, 0x0074, 0x00c0, 0x5f82, 0x1078, 0x60d4, 0x6018, - 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x0040, 0x5f4d, - 0xa286, 0x0080, 0x00c0, 0x5f76, 0x6813, 0x00ff, 0x6817, 0xfffc, - 0x6010, 0xa005, 0x0040, 0x5f6c, 0x2068, 0x6807, 0x0000, 0x6837, - 0x0103, 0x6833, 0x0200, 0x0078, 0x5f6c, 0x0e7e, 0x0f7e, 0x6813, - 0x00ff, 0x6817, 0xfffe, 0x2071, 0x762f, 0x2e04, 0xa085, 0x0003, - 0x2072, 0x2071, 0x7b80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, - 0x2069, 0x7619, 0x206a, 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x761a, - 0x206a, 0x78ea, 0x0f7f, 0x0e7f, 0x2001, 0x0006, 0x1078, 0x37d1, - 0x1078, 0x22dd, 0x1078, 0x5c02, 0x0078, 0x5f84, 0x2001, 0x0004, - 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x4872, - 0x0078, 0x5f84, 0x1078, 0x5f86, 0x0d7f, 0x007c, 0x2001, 0x7600, - 0x2004, 0xa086, 0x0003, 0x0040, 0x5f91, 0x2001, 0x0007, 0x1078, - 0x37d1, 0x1078, 0x22dd, 0x1078, 0x5c02, 0x007c, 0x0e7e, 0x2071, - 0x7600, 0x7078, 0xa086, 0x0014, 0x00c0, 0x5fcc, 0x7000, 0xa086, - 0x0003, 0x00c0, 0x5fa9, 0x6010, 0xa005, 0x00c0, 0x5fa9, 0x1078, - 0x2dc8, 0x0d7e, 0x6018, 0x2068, 0x1078, 0x38a1, 0x1078, 0x5f12, - 0x0d7f, 0x1078, 0x60de, 0x00c0, 0x5fcc, 0x2001, 0x0006, 0x1078, - 0x37d1, 0x0e7e, 0x6010, 0xa005, 0x0040, 0x5fc5, 0x2070, 0x7007, - 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x0e7f, 0x1078, 0x22dd, - 0x1078, 0x5c02, 0x0078, 0x5fd0, 0x1078, 0x5e57, 0x1078, 0x5f86, - 0x0e7f, 0x007c, 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, - 0x5fe5, 0x2001, 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, - 0x0001, 0x1078, 0x4872, 0x0078, 0x5fe7, 0x1078, 0x5f86, 0x007c, - 0x2011, 0x761e, 0x2204, 0xa086, 0x0004, 0x00c0, 0x5ff7, 0x2001, - 0x0007, 0x1078, 0x37d1, 0x1078, 0x5c02, 0x0078, 0x5ff9, 0x1078, - 0x5f86, 0x007c, 0x5ee1, 0x6006, 0x5ee1, 0x602c, 0x5ee1, 0x6087, - 0x5ee1, 0x5ee1, 0x5ee1, 0x609c, 0x5ee1, 0x60af, 0x0c7e, 0x1078, - 0x60c2, 0x00c0, 0x601b, 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, - 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, - 0x4872, 0x0078, 0x602a, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, - 0xa086, 0x1900, 0x00c0, 0x6028, 0x1078, 0x5c02, 0x0078, 0x602a, - 0x1078, 0x5f86, 0x0c7f, 0x007c, 0x1078, 0x60d1, 0x00c0, 0x6040, - 0x2001, 0x0000, 0x1078, 0x37bd, 0x2001, 0x0002, 0x1078, 0x37d1, - 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x4872, 0x0078, 0x6062, - 0x1078, 0x5e57, 0x2009, 0x7b8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, - 0x0005, 0x0040, 0x6063, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, - 0xa086, 0x1900, 0x00c0, 0x6060, 0xa686, 0x0009, 0x0040, 0x6063, - 0x2001, 0x0004, 0x1078, 0x37d1, 0x1078, 0x5c02, 0x0078, 0x6062, - 0x1078, 0x5f86, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x6071, 0x6838, 0xd0fc, 0x0040, 0x6071, 0x0d7f, 0x0078, - 0x6060, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, - 0x6082, 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f, - 0x0078, 0x6062, 0x1078, 0x22bb, 0x0d7f, 0x0078, 0x6060, 0x1078, - 0x60d1, 0x00c0, 0x6097, 0x2001, 0x0004, 0x1078, 0x37d1, 0x6003, - 0x0001, 0x6007, 0x0003, 0x1078, 0x4872, 0x0078, 0x609b, 0x1078, - 0x5e57, 0x1078, 0x5f86, 0x007c, 0x1078, 0x60d1, 0x00c0, 0x60ac, - 0x2001, 0x0008, 0x1078, 0x37d1, 0x6003, 0x0001, 0x6007, 0x0005, - 0x1078, 0x4872, 0x0078, 0x60ae, 0x1078, 0x5f86, 0x007c, 0x1078, - 0x60d1, 0x00c0, 0x60bf, 0x2001, 0x000a, 0x1078, 0x37d1, 0x6003, - 0x0001, 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x60c1, 0x1078, - 0x5f86, 0x007c, 0x2009, 0x7b8e, 0x2104, 0xa086, 0x0003, 0x00c0, - 0x60d0, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, - 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, - 0x2164, 0x1078, 0x3837, 0x017f, 0x0c7f, 0x007c, 0x0e7e, 0x2071, - 0x7b8c, 0x7004, 0xa086, 0x0014, 0x00c0, 0x6101, 0x7008, 0xa086, - 0x0800, 0x00c0, 0x6101, 0x700c, 0xd0ec, 0x0040, 0x60ff, 0xa084, - 0x0f00, 0xa086, 0x0100, 0x00c0, 0x60ff, 0x7024, 0xd0a4, 0x0040, - 0x60ff, 0xd08c, 0x0040, 0x60ff, 0xa006, 0x0078, 0x6101, 0xa085, - 0x0001, 0x0e7f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, - 0x047e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, - 0x252c, 0x2021, 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, - 0x7244, 0x7060, 0xa202, 0x00c8, 0x6158, 0x1078, 0x7559, 0x0040, - 0x6150, 0x671c, 0xa786, 0x0001, 0x0040, 0x6150, 0xa786, 0x0007, - 0x0040, 0x6150, 0x2500, 0xac06, 0x0040, 0x6150, 0x2400, 0xac06, - 0x0040, 0x6150, 0x0c7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x613a, - 0x1078, 0x1676, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x614d, - 0xa786, 0x0003, 0x00c0, 0x6162, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x1078, 0x6aa1, 0x0c7f, - 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x6158, 0x0078, 0x6118, - 0x127f, 0x007f, 0x027f, 0x047f, 0x057f, 0x077f, 0x0c7f, 0x0d7f, - 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, 0x6144, 0x1078, 0x74fd, - 0x0078, 0x614d, 0x220c, 0x2304, 0xa106, 0x00c0, 0x6175, 0x8210, - 0x8318, 0x00f0, 0x616a, 0xa006, 0x007c, 0x2304, 0xa102, 0x0048, - 0x617d, 0x2001, 0x0001, 0x0078, 0x617f, 0x2001, 0x0000, 0xa18d, - 0x0001, 0x007c, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, 0x1078, - 0x6aba, 0x0040, 0x6191, 0x1078, 0x6ace, 0x0040, 0x619a, 0x0078, - 0x6193, 0x1078, 0x22dd, 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5e57, 0x0078, 0x6193, 0xa182, 0x0040, - 0x0079, 0x61a2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, - 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b2, 0x61b4, 0x61b4, 0x61b4, - 0x61b4, 0x61b2, 0x1078, 0x12d5, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0xa186, 0x0013, 0x00c0, 0x61c9, 0x6004, 0xa082, 0x0040, 0x0079, - 0x623f, 0xa186, 0x0027, 0x00c0, 0x61e6, 0x1078, 0x4b81, 0x1078, - 0x22bb, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, 0x0040, 0x61e0, - 0x6837, 0x0103, 0x684b, 0x0029, 0x1078, 0x3a7a, 0x1078, 0x6a94, - 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0xa186, 0x0014, - 0x00c0, 0x61ef, 0x6004, 0xa082, 0x0040, 0x0079, 0x620f, 0xa186, - 0x0047, 0x10c0, 0x12d5, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, - 0x620c, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, - 0x46e6, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, - 0x00c0, 0x620c, 0x0078, 0x6266, 0x1078, 0x5c37, 0x007c, 0x6221, - 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, 0x621f, - 0x621f, 0x621f, 0x6238, 0x6238, 0x6238, 0x6238, 0x621f, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, - 0x0040, 0x6232, 0x6837, 0x0103, 0x684b, 0x0006, 0x1078, 0x3a7a, - 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x6251, - 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, 0x624f, - 0x624f, 0x624f, 0x625f, 0x625f, 0x625f, 0x625f, 0x624f, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x6003, 0x0002, 0x1078, 0x4c7a, 0x6010, - 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, - 0x4b81, 0x6003, 0x000f, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x0040, - 0x0079, 0x626a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627c, - 0x6305, 0x631d, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, 0x627a, - 0x627a, 0x627a, 0x1078, 0x12d5, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, - 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, 0x62e9, - 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x62ae, 0xa186, 0x0028, - 0x00c0, 0x6298, 0x1078, 0x6aa8, 0x684b, 0x001c, 0x0078, 0x62b0, - 0xd6dc, 0x0040, 0x62a3, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x62b0, 0xd6d4, 0x0040, 0x62ae, 0x684b, 0x0007, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x62b0, 0x684b, 0x0000, - 0x6837, 0x0103, 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x62c3, 0x7328, - 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, - 0x1078, 0x6727, 0x037f, 0xd6cc, 0x0040, 0x62f9, 0x7124, 0x695a, - 0xa192, 0x0021, 0x00c8, 0x62d7, 0x2071, 0x7b98, 0x831c, 0x2300, - 0xae18, 0xad90, 0x001d, 0x1078, 0x6727, 0x0078, 0x62f9, 0x6838, - 0xd0fc, 0x0040, 0x62e0, 0x2009, 0x0020, 0x695a, 0x0078, 0x62cc, - 0x0f7e, 0x2d78, 0x1078, 0x66bf, 0x0f7f, 0x1078, 0x6714, 0x0078, - 0x62fb, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, - 0x0040, 0x62f9, 0x6810, 0x6914, 0xa115, 0x0040, 0x62f9, 0x1078, - 0x646d, 0x1078, 0x3a7a, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, - 0x0d7f, 0x0e7f, 0x1078, 0x5c02, 0x007c, 0x0f7e, 0x6003, 0x0003, - 0x2079, 0x7b8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, - 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19cf, - 0x1078, 0x4891, 0x1078, 0x4d3a, 0x007c, 0x6003, 0x0004, 0x6110, - 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, - 0xa182, 0x0040, 0x0079, 0x632c, 0x633c, 0x633c, 0x633c, 0x633c, - 0x633c, 0x633e, 0x63d5, 0x633c, 0x633c, 0x63eb, 0x644d, 0x633c, - 0x633c, 0x633c, 0x633c, 0x6454, 0x1078, 0x12d5, 0x077e, 0x0f7e, - 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, - 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, - 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x63d0, 0xa694, 0xff00, 0xa284, - 0x0c00, 0x0040, 0x635f, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, - 0x0300, 0x0040, 0x63d0, 0x1078, 0x132f, 0x1040, 0x12d5, 0x2d00, - 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, - 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, - 0x0002, 0x0040, 0x6399, 0xa186, 0x0028, 0x00c0, 0x6383, 0x684b, - 0x001c, 0x0078, 0x639b, 0xd6dc, 0x0040, 0x638e, 0x684b, 0x0015, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x639b, 0xd6d4, 0x0040, - 0x6399, 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, - 0x639b, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, - 0xa01e, 0xd6c4, 0x0040, 0x63b0, 0x7328, 0x732c, 0x6b56, 0x037e, - 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6727, 0x037f, - 0xd6cc, 0x0040, 0x63d0, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, - 0x63c4, 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, - 0x1078, 0x6727, 0x0078, 0x63d0, 0x7838, 0xd0fc, 0x0040, 0x63cd, - 0x2009, 0x0020, 0x695a, 0x0078, 0x63b9, 0x2d78, 0x1078, 0x66bf, - 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, - 0x2079, 0x7b8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, - 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19cf, - 0x1078, 0x5567, 0x007c, 0x0d7e, 0x6003, 0x0002, 0x1078, 0x4c29, - 0x1078, 0x4d3a, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x644b, - 0xd1cc, 0x0040, 0x6426, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x641e, - 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, - 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, - 0x8210, 0x00f0, 0x640d, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, - 0x017f, 0x2168, 0x1078, 0x1358, 0x0078, 0x6449, 0x017e, 0x1078, - 0x1358, 0x0d7f, 0x1078, 0x6714, 0x0078, 0x6449, 0x6837, 0x0103, - 0x6944, 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x6445, 0xa086, - 0x0028, 0x00c0, 0x6437, 0x684b, 0x001c, 0x0078, 0x6447, 0xd1dc, - 0x0040, 0x643e, 0x684b, 0x0015, 0x0078, 0x6447, 0xd1d4, 0x0040, - 0x6445, 0x684b, 0x0007, 0x0078, 0x6447, 0x684b, 0x0000, 0x1078, - 0x3a7a, 0x1078, 0x5c02, 0x0d7f, 0x007c, 0x6003, 0x0002, 0x1078, - 0x4c29, 0x1078, 0x4d3a, 0x007c, 0x1078, 0x4c29, 0x1078, 0x22bb, - 0x0d7e, 0x6110, 0x2168, 0x1078, 0x693e, 0x0040, 0x6467, 0x6837, - 0x0103, 0x684b, 0x0029, 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, - 0x1078, 0x5c02, 0x1078, 0x4d3a, 0x007c, 0x684b, 0x0015, 0xd1fc, - 0x0040, 0x6479, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, - 0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x6480, - 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6492, 0x6490, 0x6536, - 0x653e, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, 0x6490, - 0x1078, 0x12d5, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, - 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, - 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, - 0x6528, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x64b3, 0x7018, - 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x6525, 0x1078, - 0x132f, 0x1040, 0x12d5, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, - 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, - 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x64ee, - 0xa186, 0x0028, 0x00c0, 0x64d8, 0x684b, 0x001c, 0x0078, 0x64f0, - 0xd6dc, 0x0040, 0x64e3, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0x0078, 0x64f0, 0xd6d4, 0x0040, 0x64ee, 0x684b, 0x0007, - 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64f0, 0x684b, 0x0000, - 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, - 0x6505, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, 0x7b98, - 0xad90, 0x0019, 0x1078, 0x6727, 0x037f, 0xd6cc, 0x0040, 0x6525, - 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x6519, 0x2071, 0x7b98, - 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x6727, 0x0078, - 0x6525, 0x7838, 0xd0fc, 0x0040, 0x6522, 0x2009, 0x0020, 0x695a, - 0x0078, 0x650e, 0x2d78, 0x1078, 0x66bf, 0xd6dc, 0x00c0, 0x652b, - 0xa006, 0x0078, 0x652f, 0x2001, 0x0001, 0x7218, 0x731c, 0x1078, - 0x15b6, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x20e1, 0x0005, - 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x007c, 0x0d7e, 0x6003, - 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x65a5, 0xd1cc, - 0x0040, 0x6575, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x656d, 0x017e, - 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, 0x000d, - 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, - 0x00f0, 0x655c, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, - 0x2168, 0x1078, 0x1358, 0x0078, 0x65a3, 0x017e, 0x1078, 0x1358, - 0x0d7f, 0x1078, 0x6714, 0x0078, 0x65a3, 0x6837, 0x0103, 0x6944, - 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x6594, 0xa086, 0x0028, - 0x00c0, 0x6586, 0x684b, 0x001c, 0x0078, 0x65a1, 0xd1dc, 0x0040, - 0x658d, 0x684b, 0x0015, 0x0078, 0x65a1, 0xd1d4, 0x0040, 0x6594, - 0x684b, 0x0007, 0x0078, 0x65a1, 0x684b, 0x0000, 0x684c, 0xd0ac, - 0x0040, 0x65a1, 0x6810, 0x6914, 0xa115, 0x0040, 0x65a1, 0x1078, - 0x646d, 0x1078, 0x3a7a, 0x1078, 0x5c02, 0x0d7f, 0x007c, 0x1078, - 0x4b81, 0x0078, 0x65ad, 0x1078, 0x4c29, 0x1078, 0x693e, 0x0040, - 0x65c4, 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0x760c, - 0x210c, 0xd18c, 0x00c0, 0x65cd, 0xd184, 0x00c0, 0x65c9, 0x6108, - 0x694a, 0x1078, 0x3a7a, 0x0d7f, 0x1078, 0x5c02, 0x1078, 0x4c7a, - 0x007c, 0x684b, 0x0004, 0x0078, 0x65c1, 0x684b, 0x0004, 0x0078, - 0x65c1, 0xa182, 0x0040, 0x0079, 0x65d5, 0x65e5, 0x65e5, 0x65e5, - 0x65e5, 0x65e5, 0x65e7, 0x65e5, 0x65ea, 0x65e5, 0x65e5, 0x65e5, - 0x65e5, 0x65e5, 0x65e5, 0x65e5, 0x65e5, 0x1078, 0x12d5, 0x1078, - 0x5c02, 0x007c, 0x007e, 0x027e, 0xa016, 0x1078, 0x1572, 0x027f, - 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, 0x65f6, 0x65ff, 0x65fd, - 0x65fd, 0x65fd, 0x65fd, 0x65fd, 0x65fd, 0x1078, 0x12d5, 0x6003, - 0x0001, 0x6106, 0x1078, 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, - 0x4c7a, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x6615, 0x6004, - 0xa082, 0x0085, 0x2008, 0x0079, 0x6649, 0xa186, 0x0027, 0x00c0, - 0x6636, 0x1078, 0x4b81, 0x1078, 0x22bb, 0x0d7e, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x662c, 0x6837, 0x0103, 0x684b, 0x0029, - 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x1078, - 0x4c7a, 0x007c, 0x1078, 0x5c37, 0x0078, 0x6631, 0xa186, 0x0014, - 0x00c0, 0x6632, 0x1078, 0x4b81, 0x0d7e, 0x6010, 0x2068, 0x1078, - 0x693e, 0x0040, 0x662c, 0x6837, 0x0103, 0x684b, 0x0006, 0x0078, - 0x6628, 0x6652, 0x6650, 0x6650, 0x6650, 0x6650, 0x6650, 0x665b, - 0x1078, 0x12d5, 0x1078, 0x4b81, 0x6017, 0x0014, 0x6003, 0x000c, - 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x6017, 0x0014, 0x6003, - 0x000e, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x008c, 0x00c8, 0x666e, - 0xa182, 0x0085, 0x0048, 0x666e, 0x0079, 0x6671, 0x1078, 0x5c37, - 0x007c, 0x6678, 0x6678, 0x6678, 0x6678, 0x667a, 0x6699, 0x6678, - 0x1078, 0x12d5, 0x0d7e, 0x1078, 0x6a94, 0x1078, 0x693e, 0x0040, - 0x6695, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, - 0x668d, 0x684b, 0x0006, 0x0078, 0x6691, 0x684b, 0x0005, 0x1078, - 0x6b47, 0x6847, 0x0000, 0x1078, 0x3a7a, 0x1078, 0x5c02, 0x0d7f, - 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x66b4, - 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x66aa, 0x684b, 0x0006, - 0x0078, 0x66ae, 0x684b, 0x0005, 0x1078, 0x6b47, 0x6847, 0x0000, - 0x1078, 0x3a7a, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x5c02, 0x007c, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x057e, - 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, 0x0101, 0x00c8, - 0x66cb, 0x0078, 0x66cd, 0x2009, 0x0100, 0x2130, 0x2069, 0x7b98, - 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, 0x001d, 0x1078, - 0x6727, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, 0x66e1, 0x1078, - 0x1358, 0x1078, 0x132f, 0x0040, 0x670b, 0x8528, 0x6837, 0x0110, - 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x00c8, 0x66f7, - 0x2608, 0xad90, 0x000f, 0x1078, 0x6727, 0x0078, 0x670b, 0xa6b2, - 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, 0x1078, 0x6727, - 0x0078, 0x66e1, 0x0f7f, 0x852f, 0xa5ad, 0x0003, 0x7d36, 0xa5ac, - 0x0000, 0x0078, 0x6710, 0x0f7f, 0x852f, 0xa5ad, 0x0003, 0x7d36, - 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, 0x0040, 0x6725, - 0x6804, 0xa07d, 0x0040, 0x6723, 0x6807, 0x0000, 0x1078, 0x3a7a, - 0x2f68, 0x0078, 0x6718, 0x1078, 0x3a7a, 0x0f7f, 0x007c, 0x157e, - 0xa184, 0x0001, 0x0040, 0x672d, 0x8108, 0x810c, 0x21a8, 0x2304, - 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x672f, 0x157f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x601c, 0xa084, 0x000f, 0x1079, 0x6742, - 0x127f, 0x007c, 0x6751, 0x674a, 0x674c, 0x676a, 0x674a, 0x674c, - 0x674c, 0x674c, 0x1078, 0x12d5, 0xa006, 0x007c, 0xa085, 0x0001, - 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, 0x6767, - 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b0a, 0x1078, 0x6b47, 0x1078, - 0x3a7a, 0x1078, 0x5c02, 0xa085, 0x0001, 0x0d7f, 0x007c, 0xa006, - 0x0078, 0x6765, 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12d5, 0x1079, - 0x6772, 0x007c, 0x6782, 0x679f, 0x6784, 0x67b0, 0x679b, 0x6782, - 0x674c, 0x6751, 0x6751, 0x674c, 0x674c, 0x674c, 0x674c, 0x674c, - 0x674c, 0x674c, 0x1078, 0x12d5, 0x0d7e, 0x6010, 0x2068, 0x1078, - 0x693e, 0x0040, 0x678d, 0x1078, 0x6b47, 0x0d7f, 0x6007, 0x0085, - 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x4825, 0x1078, 0x4c7a, - 0xa085, 0x0001, 0x007c, 0x1078, 0x1676, 0x0078, 0x6784, 0x0e7e, - 0x2071, 0x7836, 0x7024, 0xac06, 0x00c0, 0x67a8, 0x1078, 0x56d6, - 0x1078, 0x560b, 0x0e7f, 0x00c0, 0x6784, 0x1078, 0x674c, 0x007c, - 0x037e, 0x0e7e, 0x2071, 0x7836, 0x703c, 0xac06, 0x00c0, 0x67c0, - 0x2019, 0x0000, 0x1078, 0x5768, 0x0e7f, 0x037f, 0x0078, 0x6784, - 0x1078, 0x5a44, 0x0e7f, 0x037f, 0x00c0, 0x6784, 0x1078, 0x674c, - 0x007c, 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x67d1, 0x0c7f, - 0x007c, 0x67e0, 0x683d, 0x68e2, 0x67e4, 0x67e0, 0x67e0, 0x71dd, - 0x5c02, 0x683d, 0x1078, 0x6ace, 0x00c0, 0x67e0, 0x1078, 0x5e57, - 0x007c, 0x6017, 0x0001, 0x007c, 0x6000, 0xa08a, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x67ec, 0x007c, 0x67fc, 0x67fe, 0x681e, 0x6830, - 0x6830, 0x67fc, 0x67e0, 0x67e0, 0x67e0, 0x6830, 0x6830, 0x67fc, - 0x67fc, 0x67fc, 0x67fc, 0x683a, 0x1078, 0x12d5, 0x0e7e, 0x6010, - 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x7836, 0x7024, 0xac06, - 0x0040, 0x681a, 0x1078, 0x560b, 0x6007, 0x0085, 0x6003, 0x000b, - 0x601f, 0x0002, 0x6017, 0x0014, 0x1078, 0x4825, 0x1078, 0x4c7a, - 0x0e7f, 0x007c, 0x6017, 0x0001, 0x0078, 0x6818, 0x0d7e, 0x6010, - 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x6007, 0x0085, 0x6003, - 0x000b, 0x601f, 0x0002, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x007c, - 0x0d7e, 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, - 0x0d7f, 0x007c, 0x1078, 0x5c02, 0x007c, 0x6000, 0xa08a, 0x0010, - 0x10c8, 0x12d5, 0x1079, 0x6845, 0x007c, 0x6855, 0x67e1, 0x6857, - 0x6855, 0x6857, 0x6855, 0x6855, 0x6855, 0x67da, 0x67da, 0x6855, - 0x6855, 0x6855, 0x6855, 0x6855, 0x6855, 0x1078, 0x12d5, 0x0d7e, - 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c, - 0x10c8, 0x12d5, 0x1079, 0x6865, 0x007c, 0x6871, 0x6890, 0x6871, - 0x6890, 0x6871, 0x6890, 0x6873, 0x687c, 0x6871, 0x6890, 0x6871, - 0x6889, 0x1078, 0x12d5, 0x6004, 0xa08e, 0x0004, 0x0040, 0x688b, - 0xa08e, 0x0002, 0x0040, 0x688b, 0x6004, 0x1078, 0x6ace, 0x0040, - 0x68da, 0xa08e, 0x0021, 0x0040, 0x68de, 0xa08e, 0x0022, 0x0040, - 0x68da, 0x1078, 0x22bb, 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, - 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, 0x68ca, 0xa186, - 0x0002, 0x00c0, 0x68b9, 0x6018, 0x2068, 0x68a0, 0xd0bc, 0x00c0, - 0x68b9, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x68b9, 0x8001, - 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0398, 0x1078, - 0x5b9c, 0x0040, 0x68b9, 0x2d00, 0x601a, 0x601f, 0x0001, 0x0078, - 0x68ca, 0x0d7f, 0x0c7f, 0x1078, 0x5e57, 0x1078, 0x22bb, 0x0e7e, - 0x127e, 0x2091, 0x8000, 0x1078, 0x22dd, 0x127f, 0x0e7f, 0x1078, - 0x5c02, 0x007c, 0x2001, 0x0002, 0x1078, 0x37d1, 0x6003, 0x0001, - 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0d7f, 0x0c7f, - 0x0078, 0x68c9, 0x1078, 0x5e57, 0x0078, 0x688d, 0x1078, 0x5e66, - 0x0078, 0x688d, 0x6000, 0xa08a, 0x0010, 0x10c8, 0x12d5, 0x1079, - 0x68ea, 0x007c, 0x68fa, 0x68fa, 0x68fa, 0x68fa, 0x68fa, 0x68fa, - 0x68fa, 0x68fa, 0x68fa, 0x67e0, 0x68fa, 0x67e1, 0x68fc, 0x67e1, - 0x6905, 0x68fa, 0x1078, 0x12d5, 0x6007, 0x008b, 0x6003, 0x000d, - 0x1078, 0x4825, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x6a94, 0x1078, - 0x693e, 0x0040, 0x6927, 0x1078, 0x22bb, 0x0d7e, 0x1078, 0x693e, - 0x0040, 0x691a, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, - 0x1078, 0x3a7a, 0x0d7f, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, - 0x0001, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0078, 0x6929, 0x1078, - 0x5c02, 0x007c, 0xa284, 0x0007, 0x00c0, 0x693b, 0xa282, 0x7d00, - 0x0048, 0x693b, 0x2001, 0x7615, 0x2004, 0xa202, 0x00c8, 0x693b, - 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x693a, 0x027e, 0x0e7e, - 0x2071, 0x7600, 0x6210, 0x7058, 0xa202, 0x0048, 0x6950, 0x705c, - 0xa202, 0x00c8, 0x6950, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, - 0xa006, 0x0078, 0x694d, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, - 0x2091, 0x8000, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7344, 0x7060, - 0xa302, 0x00c8, 0x6979, 0x601c, 0xa206, 0x00c0, 0x6971, 0x1078, - 0x6ace, 0x00c0, 0x696d, 0x1078, 0x5e57, 0x0c7e, 0x1078, 0x5c02, - 0x0c7f, 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, 0x6979, 0x0078, - 0x695e, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, - 0x0c7e, 0x017e, 0xa188, 0x7720, 0x210c, 0x81ff, 0x0040, 0x699c, - 0x2061, 0x7d00, 0x2071, 0x7600, 0x7344, 0x7060, 0xa302, 0x00c8, - 0x699c, 0x017e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x699f, 0x611a, - 0x1078, 0x22bb, 0x1078, 0x5c02, 0xa006, 0x0078, 0x69a1, 0xa085, - 0x0001, 0x017f, 0x0c7f, 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, - 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x057f, 0x0040, 0x69be, - 0x6612, 0x651a, 0x601f, 0x0003, 0x2009, 0x004b, 0x1078, 0x5c29, - 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x69ba, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, - 0x1078, 0x5b9c, 0x057f, 0x0040, 0x69e8, 0x6013, 0x0000, 0x651a, - 0x601f, 0x0003, 0x0c7e, 0x2560, 0x1078, 0x39a6, 0x0c7f, 0x1078, - 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, 0x737b, 0x2009, 0x004c, - 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x69e4, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, - 0x62a0, 0x0c7e, 0x1078, 0x5b9c, 0x057f, 0x0040, 0x6a13, 0x6612, + 0x0015, 0x00c0, 0x5ce4, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, + 0x680e, 0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x5ca5, 0x2100, + 0xa1b2, 0x0030, 0x10c8, 0x12cd, 0x0079, 0x5cee, 0x5d20, 0x5d2c, + 0x5d20, 0x5d20, 0x5d20, 0x5d20, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d20, 0x5d1e, 0x5d20, + 0x5d20, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d20, 0x5d1e, + 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x5d1e, 0x1078, 0x12cd, + 0x6003, 0x0001, 0x6106, 0x1078, 0x486a, 0x127e, 0x2091, 0x8000, + 0x1078, 0x4c72, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, + 0x486a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, + 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12cd, 0xa1b6, 0x0013, 0x00c0, + 0x5d44, 0x2008, 0x0079, 0x5dcb, 0xa1b6, 0x0027, 0x00c0, 0x5d99, + 0x1078, 0x4b79, 0x6004, 0x1078, 0x6aaf, 0x0040, 0x5d5d, 0x1078, + 0x6ac3, 0x0040, 0x5d91, 0xa08e, 0x0021, 0x0040, 0x5d95, 0xa08e, + 0x0022, 0x0040, 0x5d91, 0x0078, 0x5d8c, 0x1078, 0x22d7, 0x2001, + 0x0007, 0x1078, 0x37c9, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, + 0x5e4d, 0xa186, 0x007e, 0x00c0, 0x5d72, 0x2001, 0x762f, 0x2014, + 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, + 0x1078, 0x495a, 0x1078, 0x489d, 0x0c7e, 0x6018, 0xa065, 0x0040, + 0x5d83, 0x1078, 0x399e, 0x0c7f, 0x2c08, 0x1078, 0x7370, 0x037f, + 0x027f, 0x017f, 0x1078, 0x3805, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x1078, 0x5e4d, 0x0078, 0x5d8c, 0x1078, 0x5e5c, 0x0078, + 0x5d8c, 0xa186, 0x0014, 0x00c0, 0x5d90, 0x1078, 0x4b79, 0x1078, + 0x22b5, 0x1078, 0x6aaf, 0x00c0, 0x5db8, 0x1078, 0x22d7, 0x6018, + 0xa080, 0x0028, 0x200c, 0x1078, 0x5e4d, 0xa186, 0x007e, 0x00c0, + 0x5db6, 0x2001, 0x762f, 0x200c, 0xc185, 0x2102, 0x0078, 0x5d8c, + 0x1078, 0x6ac3, 0x00c0, 0x5dc0, 0x1078, 0x5e4d, 0x0078, 0x5d8c, + 0x6004, 0xa08e, 0x0021, 0x0040, 0x5dbc, 0xa08e, 0x0022, 0x1040, + 0x5e5c, 0x0078, 0x5d8c, 0x5dfd, 0x5dff, 0x5e03, 0x5e07, 0x5e0b, + 0x5e0f, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5e13, 0x5e19, 0x5dfb, 0x5e23, 0x5e19, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x5e19, 0x5e19, 0x5dfb, 0x5dfb, 0x5dfb, + 0x5dfb, 0x5dfb, 0x5dfb, 0x1078, 0x12cd, 0x0078, 0x5e19, 0x2001, + 0x000b, 0x0078, 0x5e2c, 0x2001, 0x0003, 0x0078, 0x5e2c, 0x2001, + 0x0005, 0x0078, 0x5e2c, 0x2001, 0x0001, 0x0078, 0x5e2c, 0x2001, + 0x0009, 0x0078, 0x5e2c, 0x1078, 0x12cd, 0x0078, 0x5e2b, 0x1078, + 0x37c9, 0x1078, 0x4b79, 0x6003, 0x0002, 0x6017, 0x0028, 0x1078, + 0x4c72, 0x0078, 0x5e2b, 0x1078, 0x4b79, 0x6003, 0x0004, 0x6017, + 0x0028, 0x1078, 0x4c72, 0x007c, 0x1078, 0x37c9, 0x1078, 0x4b79, + 0x6003, 0x0002, 0x037e, 0x2019, 0x765c, 0x2304, 0xa084, 0xff00, + 0x00c0, 0x5e3e, 0x2019, 0x0028, 0x0078, 0x5e47, 0x8007, 0xa09a, + 0x0004, 0x0048, 0x5e3a, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, + 0x037f, 0x1078, 0x4c72, 0x0078, 0x5e2b, 0x0e7e, 0x1078, 0x6938, + 0x0040, 0x5e5a, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, + 0x7033, 0x0100, 0x0e7f, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, + 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001, 0x0e7f, 0x007c, + 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa0b2, + 0x000c, 0x10c8, 0x12cd, 0x6604, 0xa6b6, 0x0028, 0x00c0, 0x5e7c, + 0x1078, 0x6af8, 0x0078, 0x5eae, 0x6604, 0xa6b6, 0x0029, 0x00c0, + 0x5e85, 0x1078, 0x6b12, 0x0078, 0x5eae, 0x6604, 0xa6b6, 0x001f, + 0x00c0, 0x5e8e, 0x1078, 0x5c8b, 0x0078, 0x5eae, 0x6604, 0xa6b6, + 0x0000, 0x00c0, 0x5e97, 0x1078, 0x5cd0, 0x0078, 0x5eae, 0x6604, + 0xa6b6, 0x0022, 0x00c0, 0x5ea0, 0x1078, 0x5cb4, 0x0078, 0x5eae, + 0xa1b6, 0x0015, 0x00c0, 0x5ea8, 0x1079, 0x5eb3, 0x0078, 0x5eae, + 0xa1b6, 0x0016, 0x00c0, 0x5eaf, 0x1079, 0x5ff0, 0x007c, 0x1078, + 0x5c2f, 0x0078, 0x5eae, 0x5ed7, 0x5eda, 0x5ed7, 0x5f1b, 0x5ed7, + 0x5f8c, 0x5ed7, 0x5ed7, 0x5ed7, 0x5fc8, 0x5ed7, 0x5fde, 0xa1b6, + 0x0048, 0x0040, 0x5ecb, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x1078, 0x156a, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, + 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x0005, + 0x0005, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, 0xa086, 0x0074, + 0x00c0, 0x5f04, 0x1078, 0x7344, 0x00c0, 0x5ef6, 0x0d7e, 0x6018, + 0x2068, 0x1078, 0x5f08, 0x0d7f, 0x2001, 0x0006, 0x1078, 0x37c9, + 0x1078, 0x22d7, 0x1078, 0x5bfa, 0x0078, 0x5f06, 0x2001, 0x000a, + 0x1078, 0x37c9, 0x1078, 0x22d7, 0x6003, 0x0001, 0x6007, 0x0001, + 0x1078, 0x486a, 0x0078, 0x5f06, 0x1078, 0x5f7c, 0x0e7f, 0x007c, + 0x6800, 0xd084, 0x0040, 0x5f1a, 0x2001, 0x0000, 0x1078, 0x37b5, + 0x2069, 0x7651, 0x6804, 0xd0a4, 0x0040, 0x5f1a, 0x2001, 0x0006, + 0x1078, 0x37d7, 0x007c, 0x0d7e, 0x2011, 0x761e, 0x2204, 0xa086, + 0x0074, 0x00c0, 0x5f78, 0x1078, 0x60ca, 0x6018, 0x2068, 0xa080, + 0x0028, 0x2014, 0xa286, 0x007e, 0x0040, 0x5f43, 0xa286, 0x0080, + 0x00c0, 0x5f6c, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, + 0x0040, 0x5f62, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, + 0x0200, 0x0078, 0x5f62, 0x0e7e, 0x0f7e, 0x6813, 0x00ff, 0x6817, + 0xfffe, 0x2071, 0x762f, 0x2e04, 0xa085, 0x0003, 0x2072, 0x2071, + 0x7b80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0x7619, + 0x206a, 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x761a, 0x206a, 0x78ea, + 0x0f7f, 0x0e7f, 0x2001, 0x0006, 0x1078, 0x37c9, 0x1078, 0x22d7, + 0x1078, 0x5bfa, 0x0078, 0x5f7a, 0x2001, 0x0004, 0x1078, 0x37c9, + 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x486a, 0x0078, 0x5f7a, + 0x1078, 0x5f7c, 0x0d7f, 0x007c, 0x2001, 0x7600, 0x2004, 0xa086, + 0x0003, 0x0040, 0x5f87, 0x2001, 0x0007, 0x1078, 0x37c9, 0x1078, + 0x22d7, 0x1078, 0x5bfa, 0x007c, 0x0e7e, 0x2071, 0x7600, 0x7078, + 0xa086, 0x0014, 0x00c0, 0x5fc2, 0x7000, 0xa086, 0x0003, 0x00c0, + 0x5f9f, 0x6010, 0xa005, 0x00c0, 0x5f9f, 0x1078, 0x2db9, 0x0d7e, + 0x6018, 0x2068, 0x1078, 0x3899, 0x1078, 0x5f08, 0x0d7f, 0x1078, + 0x60d4, 0x00c0, 0x5fc2, 0x2001, 0x0006, 0x1078, 0x37c9, 0x0e7e, + 0x6010, 0xa005, 0x0040, 0x5fbb, 0x2070, 0x7007, 0x0000, 0x7037, + 0x0103, 0x7033, 0x0200, 0x0e7f, 0x1078, 0x22d7, 0x1078, 0x5bfa, + 0x0078, 0x5fc6, 0x1078, 0x5e4d, 0x1078, 0x5f7c, 0x0e7f, 0x007c, + 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, 0x5fdb, 0x2001, + 0x0002, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, + 0x486a, 0x0078, 0x5fdd, 0x1078, 0x5f7c, 0x007c, 0x2011, 0x761e, + 0x2204, 0xa086, 0x0004, 0x00c0, 0x5fed, 0x2001, 0x0007, 0x1078, + 0x37c9, 0x1078, 0x5bfa, 0x0078, 0x5fef, 0x1078, 0x5f7c, 0x007c, + 0x5ed7, 0x5ffc, 0x5ed7, 0x6022, 0x5ed7, 0x607d, 0x5ed7, 0x5ed7, + 0x5ed7, 0x6092, 0x5ed7, 0x60a5, 0x0c7e, 0x1078, 0x60b8, 0x00c0, + 0x6011, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, + 0x37c9, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x486a, 0x0078, + 0x6020, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, + 0x00c0, 0x601e, 0x1078, 0x5bfa, 0x0078, 0x6020, 0x1078, 0x5f7c, + 0x0c7f, 0x007c, 0x1078, 0x60c7, 0x00c0, 0x6036, 0x2001, 0x0000, + 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, 0x37c9, 0x6003, 0x0001, + 0x6007, 0x0002, 0x1078, 0x486a, 0x0078, 0x6058, 0x1078, 0x5e4d, + 0x2009, 0x7b8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x0040, + 0x6059, 0x2009, 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x1900, + 0x00c0, 0x6056, 0xa686, 0x0009, 0x0040, 0x6059, 0x2001, 0x0004, + 0x1078, 0x37c9, 0x1078, 0x5bfa, 0x0078, 0x6058, 0x1078, 0x5f7c, + 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6067, + 0x6838, 0xd0fc, 0x0040, 0x6067, 0x0d7f, 0x0078, 0x6056, 0x6018, + 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x6078, 0x8001, + 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f, 0x0078, 0x6058, + 0x1078, 0x22b5, 0x0d7f, 0x0078, 0x6056, 0x1078, 0x60c7, 0x00c0, + 0x608d, 0x2001, 0x0004, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, + 0x0003, 0x1078, 0x486a, 0x0078, 0x6091, 0x1078, 0x5e4d, 0x1078, + 0x5f7c, 0x007c, 0x1078, 0x60c7, 0x00c0, 0x60a2, 0x2001, 0x0008, + 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, 0x0005, 0x1078, 0x486a, + 0x0078, 0x60a4, 0x1078, 0x5f7c, 0x007c, 0x1078, 0x60c7, 0x00c0, + 0x60b5, 0x2001, 0x000a, 0x1078, 0x37c9, 0x6003, 0x0001, 0x6007, + 0x0001, 0x1078, 0x486a, 0x0078, 0x60b7, 0x1078, 0x5f7c, 0x007c, + 0x2009, 0x7b8e, 0x2104, 0xa086, 0x0003, 0x00c0, 0x60c6, 0x2009, + 0x7b8f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x007c, 0xa085, + 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, 0x2164, 0x1078, + 0x382f, 0x017f, 0x0c7f, 0x007c, 0x0e7e, 0x2071, 0x7b8c, 0x7004, + 0xa086, 0x0014, 0x00c0, 0x60f7, 0x7008, 0xa086, 0x0800, 0x00c0, + 0x60f7, 0x700c, 0xd0ec, 0x0040, 0x60f5, 0xa084, 0x0f00, 0xa086, + 0x0100, 0x00c0, 0x60f5, 0x7024, 0xd0a4, 0x0040, 0x60f5, 0xd08c, + 0x0040, 0x60f5, 0xa006, 0x0078, 0x60f7, 0xa085, 0x0001, 0x0e7f, + 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, + 0x007e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, 0x2021, + 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7244, 0x7060, + 0xa202, 0x00c8, 0x614e, 0x1078, 0x754e, 0x0040, 0x6146, 0x671c, + 0xa786, 0x0001, 0x0040, 0x6146, 0xa786, 0x0007, 0x0040, 0x6146, + 0x2500, 0xac06, 0x0040, 0x6146, 0x2400, 0xac06, 0x0040, 0x6146, + 0x0c7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x6130, 0x1078, 0x166e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6143, 0xa786, 0x0003, + 0x00c0, 0x6158, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, + 0x3a72, 0x1078, 0x6a89, 0x1078, 0x6a96, 0x0c7f, 0xace0, 0x0008, + 0x7054, 0xac02, 0x00c8, 0x614e, 0x0078, 0x610e, 0x127f, 0x007f, + 0x027f, 0x047f, 0x057f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, + 0xa786, 0x0006, 0x00c0, 0x613a, 0x1078, 0x74f2, 0x0078, 0x6143, + 0x220c, 0x2304, 0xa106, 0x00c0, 0x616b, 0x8210, 0x8318, 0x00f0, + 0x6160, 0xa006, 0x007c, 0x2304, 0xa102, 0x0048, 0x6173, 0x2001, + 0x0001, 0x0078, 0x6175, 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, + 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x1078, 0x6aaf, 0x0040, + 0x6187, 0x1078, 0x6ac3, 0x0040, 0x6190, 0x0078, 0x6189, 0x1078, + 0x22d7, 0x1078, 0x4b79, 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, + 0x1078, 0x5e4d, 0x0078, 0x6189, 0xa182, 0x0040, 0x0079, 0x6198, + 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, 0x61a8, + 0x61a8, 0x61a8, 0x61a8, 0x61aa, 0x61aa, 0x61aa, 0x61aa, 0x61a8, + 0x1078, 0x12cd, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, + 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0xa186, 0x0013, + 0x00c0, 0x61bf, 0x6004, 0xa082, 0x0040, 0x0079, 0x6235, 0xa186, + 0x0027, 0x00c0, 0x61dc, 0x1078, 0x4b79, 0x1078, 0x22b5, 0x0d7e, + 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, 0x61d6, 0x6837, 0x0103, + 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0xa186, 0x0014, 0x00c0, 0x61e5, + 0x6004, 0xa082, 0x0040, 0x0079, 0x6205, 0xa186, 0x0047, 0x10c0, + 0x12cd, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, 0x6202, 0x127e, + 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, 0x46de, 0x027f, + 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, 0x00c0, 0x6202, + 0x0078, 0x625c, 0x1078, 0x5c2f, 0x007c, 0x6217, 0x6215, 0x6215, + 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, 0x6215, + 0x622e, 0x622e, 0x622e, 0x622e, 0x6215, 0x1078, 0x12cd, 0x1078, + 0x4b79, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, 0x6228, + 0x6837, 0x0103, 0x684b, 0x0006, 0x1078, 0x3a72, 0x1078, 0x6a89, + 0x0d7f, 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x1078, 0x4b79, + 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x6247, 0x6245, 0x6245, + 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, 0x6245, + 0x6255, 0x6255, 0x6255, 0x6255, 0x6245, 0x1078, 0x12cd, 0x1078, + 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, 0x6010, 0xa088, 0x0013, + 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, 0x4b79, 0x6003, + 0x000f, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x6260, + 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6272, 0x62fb, 0x6313, + 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, 0x6270, + 0x1078, 0x12cd, 0x0e7e, 0x0d7e, 0x2071, 0x7b8c, 0x6110, 0x2168, + 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040, 0x62df, 0xa68c, 0x00ff, + 0xa186, 0x0002, 0x0040, 0x62a4, 0xa186, 0x0028, 0x00c0, 0x628e, + 0x1078, 0x6a9d, 0x684b, 0x001c, 0x0078, 0x62a6, 0xd6dc, 0x0040, + 0x6299, 0x684b, 0x0015, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, + 0x62a6, 0xd6d4, 0x0040, 0x62a4, 0x684b, 0x0007, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0x0078, 0x62a6, 0x684b, 0x0000, 0x6837, 0x0103, + 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x62b9, 0x7328, 0x732c, 0x6b56, + 0x037e, 0x2308, 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, + 0x037f, 0xd6cc, 0x0040, 0x62ef, 0x7124, 0x695a, 0xa192, 0x0021, + 0x00c8, 0x62cd, 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, + 0x001d, 0x1078, 0x6721, 0x0078, 0x62ef, 0x6838, 0xd0fc, 0x0040, + 0x62d6, 0x2009, 0x0020, 0x695a, 0x0078, 0x62c2, 0x0f7e, 0x2d78, + 0x1078, 0x66b9, 0x0f7f, 0x1078, 0x670e, 0x0078, 0x62f1, 0x684b, + 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x62ef, + 0x6810, 0x6914, 0xa115, 0x0040, 0x62ef, 0x1078, 0x6467, 0x1078, + 0x3a72, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x0d7f, 0x0e7f, + 0x1078, 0x5bfa, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0x7b8c, + 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, + 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19c7, 0x1078, 0x4889, + 0x1078, 0x4d32, 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, + 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, 0x007c, 0xa182, 0x0040, + 0x0079, 0x6322, 0x6332, 0x6332, 0x6332, 0x6332, 0x6332, 0x6334, + 0x63cb, 0x6332, 0x6332, 0x63e1, 0x6443, 0x6332, 0x6332, 0x6332, + 0x6332, 0x644e, 0x1078, 0x12cd, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, + 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0040, 0x63c6, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, + 0x6355, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, + 0x63c6, 0x1078, 0x1327, 0x1040, 0x12cd, 0x2d00, 0x784a, 0x7f4c, + 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, + 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, + 0x638f, 0xa186, 0x0028, 0x00c0, 0x6379, 0x684b, 0x001c, 0x0078, + 0x6391, 0xd6dc, 0x0040, 0x6384, 0x684b, 0x0015, 0x7318, 0x6b62, + 0x731c, 0x6b5e, 0x0078, 0x6391, 0xd6d4, 0x0040, 0x638f, 0x684b, + 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x6391, 0x684b, + 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, + 0x0040, 0x63a6, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, 0x2019, + 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, 0x037f, 0xd6cc, 0x0040, + 0x63c6, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x63ba, 0x2071, + 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x6721, + 0x0078, 0x63c6, 0x7838, 0xd0fc, 0x0040, 0x63c3, 0x2009, 0x0020, + 0x695a, 0x0078, 0x63af, 0x2d78, 0x1078, 0x66b9, 0x0d7f, 0x0e7f, + 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0x7b8c, + 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, + 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x19c7, 0x1078, 0x555f, + 0x007c, 0x0d7e, 0x6003, 0x0002, 0x1078, 0x4c21, 0x1078, 0x4d32, + 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x6441, 0xd1cc, 0x0040, + 0x641c, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x6414, 0x017e, 0x684c, + 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, + 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x00f0, + 0x6403, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, 0x2168, + 0x1078, 0x1350, 0x0078, 0x643f, 0x017e, 0x1078, 0x1350, 0x0d7f, + 0x1078, 0x670e, 0x0078, 0x643f, 0x6837, 0x0103, 0x6944, 0xa184, + 0x00ff, 0xa186, 0x0002, 0x0040, 0x643b, 0xa086, 0x0028, 0x00c0, + 0x642d, 0x684b, 0x001c, 0x0078, 0x643d, 0xd1dc, 0x0040, 0x6434, + 0x684b, 0x0015, 0x0078, 0x643d, 0xd1d4, 0x0040, 0x643b, 0x684b, + 0x0007, 0x0078, 0x643d, 0x684b, 0x0000, 0x1078, 0x3a72, 0x1078, + 0x5bfa, 0x0d7f, 0x007c, 0x2019, 0x0001, 0x1078, 0x5760, 0x6003, + 0x0002, 0x1078, 0x4c21, 0x1078, 0x4d32, 0x007c, 0x1078, 0x4c21, + 0x1078, 0x22b5, 0x0d7e, 0x6110, 0x2168, 0x1078, 0x6938, 0x0040, + 0x6461, 0x6837, 0x0103, 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, + 0x6a89, 0x0d7f, 0x1078, 0x5bfa, 0x1078, 0x4d32, 0x007c, 0x684b, + 0x0015, 0xd1fc, 0x0040, 0x6473, 0x684b, 0x0007, 0x8002, 0x8000, + 0x810a, 0xa189, 0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, + 0x0079, 0x647a, 0x648a, 0x648a, 0x648a, 0x648a, 0x648a, 0x648c, + 0x648a, 0x6530, 0x6538, 0x648a, 0x648a, 0x648a, 0x648a, 0x648a, + 0x648a, 0x648a, 0x1078, 0x12cd, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, + 0x2071, 0x7b8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0040, 0x6522, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, + 0x64ad, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, + 0x651f, 0x1078, 0x1327, 0x1040, 0x12cd, 0x2d00, 0x784a, 0x7f4c, + 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, + 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x00ff, 0xa186, 0x0002, + 0x0040, 0x64e8, 0xa186, 0x0028, 0x00c0, 0x64d2, 0x684b, 0x001c, + 0x0078, 0x64ea, 0xd6dc, 0x0040, 0x64dd, 0x684b, 0x0015, 0x7318, + 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64ea, 0xd6d4, 0x0040, 0x64e8, + 0x684b, 0x0007, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0x0078, 0x64ea, + 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, + 0xd6c4, 0x0040, 0x64ff, 0x7328, 0x732c, 0x6b56, 0x037e, 0x2308, + 0x2019, 0x7b98, 0xad90, 0x0019, 0x1078, 0x6721, 0x037f, 0xd6cc, + 0x0040, 0x651f, 0x7124, 0x695a, 0xa192, 0x0021, 0x00c8, 0x6513, + 0x2071, 0x7b98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, + 0x6721, 0x0078, 0x651f, 0x7838, 0xd0fc, 0x0040, 0x651c, 0x2009, + 0x0020, 0x695a, 0x0078, 0x6508, 0x2d78, 0x1078, 0x66b9, 0xd6dc, + 0x00c0, 0x6525, 0xa006, 0x0078, 0x6529, 0x2001, 0x0001, 0x7218, + 0x731c, 0x1078, 0x15ae, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, 0x007c, + 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, + 0x659f, 0xd1cc, 0x0040, 0x656f, 0x6948, 0x6838, 0xd0fc, 0x0040, + 0x6567, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, + 0xa198, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, + 0x8318, 0x8210, 0x00f0, 0x6556, 0x157f, 0x007f, 0x6852, 0x007f, + 0x684e, 0x017f, 0x2168, 0x1078, 0x1350, 0x0078, 0x659d, 0x017e, + 0x1078, 0x1350, 0x0d7f, 0x1078, 0x670e, 0x0078, 0x659d, 0x6837, + 0x0103, 0x6944, 0xa184, 0x00ff, 0xa186, 0x0002, 0x0040, 0x658e, + 0xa086, 0x0028, 0x00c0, 0x6580, 0x684b, 0x001c, 0x0078, 0x659b, + 0xd1dc, 0x0040, 0x6587, 0x684b, 0x0015, 0x0078, 0x659b, 0xd1d4, + 0x0040, 0x658e, 0x684b, 0x0007, 0x0078, 0x659b, 0x684b, 0x0000, + 0x684c, 0xd0ac, 0x0040, 0x659b, 0x6810, 0x6914, 0xa115, 0x0040, + 0x659b, 0x1078, 0x6467, 0x1078, 0x3a72, 0x1078, 0x5bfa, 0x0d7f, + 0x007c, 0x1078, 0x4b79, 0x0078, 0x65a7, 0x1078, 0x4c21, 0x1078, + 0x6938, 0x0040, 0x65be, 0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, + 0x2009, 0x760c, 0x210c, 0xd18c, 0x00c0, 0x65c7, 0xd184, 0x00c0, + 0x65c3, 0x6108, 0x694a, 0x1078, 0x3a72, 0x0d7f, 0x1078, 0x5bfa, + 0x1078, 0x4c72, 0x007c, 0x684b, 0x0004, 0x0078, 0x65bb, 0x684b, + 0x0004, 0x0078, 0x65bb, 0xa182, 0x0040, 0x0079, 0x65cf, 0x65df, + 0x65df, 0x65df, 0x65df, 0x65df, 0x65e1, 0x65df, 0x65e4, 0x65df, + 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x65df, 0x1078, + 0x12cd, 0x1078, 0x5bfa, 0x007c, 0x007e, 0x027e, 0xa016, 0x1078, + 0x156a, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, 0x65f0, + 0x65f9, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x65f7, 0x1078, + 0x12cd, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, 0x2091, + 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, + 0x660f, 0x6004, 0xa082, 0x0085, 0x2008, 0x0079, 0x6643, 0xa186, + 0x0027, 0x00c0, 0x6630, 0x1078, 0x4b79, 0x1078, 0x22b5, 0x0d7e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x6626, 0x6837, 0x0103, + 0x684b, 0x0029, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x1078, 0x5c2f, 0x0078, 0x662b, + 0xa186, 0x0014, 0x00c0, 0x662c, 0x1078, 0x4b79, 0x0d7e, 0x6010, + 0x2068, 0x1078, 0x6938, 0x0040, 0x6626, 0x6837, 0x0103, 0x684b, + 0x0006, 0x0078, 0x6622, 0x664c, 0x664a, 0x664a, 0x664a, 0x664a, + 0x664a, 0x6655, 0x1078, 0x12cd, 0x1078, 0x4b79, 0x6017, 0x0014, + 0x6003, 0x000c, 0x1078, 0x4c72, 0x007c, 0x1078, 0x4b79, 0x6017, + 0x0014, 0x6003, 0x000e, 0x1078, 0x4c72, 0x007c, 0xa182, 0x008c, + 0x00c8, 0x6668, 0xa182, 0x0085, 0x0048, 0x6668, 0x0079, 0x666b, + 0x1078, 0x5c2f, 0x007c, 0x6672, 0x6672, 0x6672, 0x6672, 0x6674, + 0x6693, 0x6672, 0x1078, 0x12cd, 0x0d7e, 0x1078, 0x6a89, 0x1078, + 0x6938, 0x0040, 0x668f, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, + 0xd0b4, 0x0040, 0x6687, 0x684b, 0x0006, 0x0078, 0x668b, 0x684b, + 0x0005, 0x1078, 0x6b3c, 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, + 0x5bfa, 0x0d7f, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x66ae, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x66a4, + 0x684b, 0x0006, 0x0078, 0x66a8, 0x684b, 0x0005, 0x1078, 0x6b3c, + 0x6847, 0x0000, 0x1078, 0x3a72, 0x1078, 0x6a89, 0x0d7f, 0x1078, + 0x5bfa, 0x007c, 0x1078, 0x4b79, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, + 0x0101, 0x00c8, 0x66c5, 0x0078, 0x66c7, 0x2009, 0x0100, 0x2130, + 0x2069, 0x7b98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, + 0x001d, 0x1078, 0x6721, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, + 0x66db, 0x1078, 0x1350, 0x1078, 0x1327, 0x0040, 0x6705, 0x8528, + 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, + 0x00c8, 0x66f1, 0x2608, 0xad90, 0x000f, 0x1078, 0x6721, 0x0078, + 0x6705, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, + 0x1078, 0x6721, 0x0078, 0x66db, 0x0f7f, 0x852f, 0xa5ad, 0x0003, + 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x670a, 0x0f7f, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, + 0x0040, 0x671f, 0x6804, 0xa07d, 0x0040, 0x671d, 0x6807, 0x0000, + 0x1078, 0x3a72, 0x2f68, 0x0078, 0x6712, 0x1078, 0x3a72, 0x0f7f, + 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x6727, 0x8108, 0x810c, + 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x6729, + 0x157f, 0x007c, 0x127e, 0x2091, 0x8000, 0x601c, 0xa084, 0x000f, + 0x1079, 0x673c, 0x127f, 0x007c, 0x674b, 0x6744, 0x6746, 0x6764, + 0x6744, 0x6746, 0x6746, 0x6746, 0x1078, 0x12cd, 0xa006, 0x007c, + 0xa085, 0x0001, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x6938, + 0x0040, 0x6761, 0xa00e, 0x2001, 0x0005, 0x1078, 0x3b02, 0x1078, + 0x6b3c, 0x1078, 0x3a72, 0x1078, 0x5bfa, 0xa085, 0x0001, 0x0d7f, + 0x007c, 0xa006, 0x0078, 0x675f, 0x6000, 0xa08a, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x676c, 0x007c, 0x677c, 0x6799, 0x677e, 0x67aa, + 0x6795, 0x677c, 0x6746, 0x674b, 0x674b, 0x6746, 0x6746, 0x6746, + 0x6746, 0x6746, 0x6746, 0x6746, 0x1078, 0x12cd, 0x0d7e, 0x6010, + 0x2068, 0x1078, 0x6938, 0x0040, 0x6787, 0x1078, 0x6b3c, 0x0d7f, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x481d, + 0x1078, 0x4c72, 0xa085, 0x0001, 0x007c, 0x1078, 0x166e, 0x0078, + 0x677e, 0x0e7e, 0x2071, 0x7836, 0x7024, 0xac06, 0x00c0, 0x67a2, + 0x1078, 0x56ce, 0x1078, 0x5603, 0x0e7f, 0x00c0, 0x677e, 0x1078, + 0x6746, 0x007c, 0x037e, 0x0e7e, 0x2071, 0x7836, 0x703c, 0xac06, + 0x00c0, 0x67ba, 0x2019, 0x0000, 0x1078, 0x5760, 0x0e7f, 0x037f, + 0x0078, 0x677e, 0x1078, 0x5a3c, 0x0e7f, 0x037f, 0x00c0, 0x677e, + 0x1078, 0x6746, 0x007c, 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, + 0x67cb, 0x0c7f, 0x007c, 0x67da, 0x6837, 0x68dc, 0x67de, 0x67da, + 0x67da, 0x71d2, 0x5bfa, 0x6837, 0x1078, 0x6ac3, 0x00c0, 0x67da, + 0x1078, 0x5e4d, 0x007c, 0x6017, 0x0001, 0x007c, 0x6000, 0xa08a, + 0x0010, 0x10c8, 0x12cd, 0x1079, 0x67e6, 0x007c, 0x67f6, 0x67f8, + 0x6818, 0x682a, 0x682a, 0x67f6, 0x67da, 0x67da, 0x67da, 0x682a, + 0x682a, 0x67f6, 0x67f6, 0x67f6, 0x67f6, 0x6834, 0x1078, 0x12cd, + 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x7836, + 0x7024, 0xac06, 0x0040, 0x6814, 0x1078, 0x5603, 0x6007, 0x0085, + 0x6003, 0x000b, 0x601f, 0x0002, 0x6017, 0x0014, 0x1078, 0x481d, + 0x1078, 0x4c72, 0x0e7f, 0x007c, 0x6017, 0x0001, 0x0078, 0x6812, + 0x0d7e, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x6007, + 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, 0x481d, 0x1078, + 0x4c72, 0x007c, 0x0d7e, 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, + 0xc0b5, 0x6852, 0x0d7f, 0x007c, 0x1078, 0x5bfa, 0x007c, 0x6000, + 0xa08a, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x683f, 0x007c, 0x684f, + 0x67db, 0x6851, 0x684f, 0x6851, 0x684f, 0x684f, 0x684f, 0x67d4, + 0x67d4, 0x684f, 0x684f, 0x684f, 0x684f, 0x684f, 0x684f, 0x1078, + 0x12cd, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, + 0xa08a, 0x000c, 0x10c8, 0x12cd, 0x1079, 0x685f, 0x007c, 0x686b, + 0x688a, 0x686b, 0x688a, 0x686b, 0x688a, 0x686d, 0x6876, 0x686b, + 0x688a, 0x686b, 0x6883, 0x1078, 0x12cd, 0x6004, 0xa08e, 0x0004, + 0x0040, 0x6885, 0xa08e, 0x0002, 0x0040, 0x6885, 0x6004, 0x1078, + 0x6ac3, 0x0040, 0x68d4, 0xa08e, 0x0021, 0x0040, 0x68d8, 0xa08e, + 0x0022, 0x0040, 0x68d4, 0x1078, 0x22b5, 0x1078, 0x5e4d, 0x1078, + 0x5bfa, 0x007c, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, + 0x68c4, 0xa186, 0x0002, 0x00c0, 0x68b3, 0x6018, 0x2068, 0x68a0, + 0xd0bc, 0x00c0, 0x68b3, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, + 0x68b3, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, + 0x0398, 0x1078, 0x5b94, 0x0040, 0x68b3, 0x2d00, 0x601a, 0x601f, + 0x0001, 0x0078, 0x68c4, 0x0d7f, 0x0c7f, 0x1078, 0x5e4d, 0x1078, + 0x22b5, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x22d7, 0x127f, + 0x0e7f, 0x1078, 0x5bfa, 0x007c, 0x2001, 0x0002, 0x1078, 0x37c9, + 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x486a, 0x1078, 0x4c72, + 0x0d7f, 0x0c7f, 0x0078, 0x68c3, 0x1078, 0x5e4d, 0x0078, 0x6887, + 0x1078, 0x5e5c, 0x0078, 0x6887, 0x6000, 0xa08a, 0x0010, 0x10c8, + 0x12cd, 0x1079, 0x68e4, 0x007c, 0x68f4, 0x68f4, 0x68f4, 0x68f4, + 0x68f4, 0x68f4, 0x68f4, 0x68f4, 0x68f4, 0x67da, 0x68f4, 0x67db, + 0x68f6, 0x67db, 0x68ff, 0x68f4, 0x1078, 0x12cd, 0x6007, 0x008b, + 0x6003, 0x000d, 0x1078, 0x481d, 0x1078, 0x4c72, 0x007c, 0x1078, + 0x6a89, 0x1078, 0x6938, 0x0040, 0x6921, 0x1078, 0x22b5, 0x0d7e, + 0x1078, 0x6938, 0x0040, 0x6914, 0x6010, 0x2068, 0x6837, 0x0103, + 0x684b, 0x0006, 0x1078, 0x3a72, 0x0d7f, 0x601f, 0x0001, 0x6007, + 0x0001, 0x6003, 0x0001, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0078, + 0x6923, 0x1078, 0x5bfa, 0x007c, 0xa284, 0x0007, 0x00c0, 0x6935, + 0xa282, 0x7d00, 0x0048, 0x6935, 0x2001, 0x7615, 0x2004, 0xa202, + 0x00c8, 0x6935, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x6934, + 0x027e, 0x0e7e, 0x2071, 0x7600, 0x6210, 0x7058, 0xa202, 0x0048, + 0x694a, 0x705c, 0xa202, 0x00c8, 0x694a, 0xa085, 0x0001, 0x0e7f, + 0x027f, 0x007c, 0xa006, 0x0078, 0x6947, 0x0e7e, 0x0c7e, 0x037e, + 0x007e, 0x127e, 0x2091, 0x8000, 0x2061, 0x7d00, 0x2071, 0x7600, + 0x7344, 0x7060, 0xa302, 0x00c8, 0x6973, 0x601c, 0xa206, 0x00c0, + 0x696b, 0x1078, 0x6ac3, 0x00c0, 0x6967, 0x1078, 0x5e4d, 0x0c7e, + 0x1078, 0x5bfa, 0x0c7f, 0xace0, 0x0008, 0x7054, 0xac02, 0x00c8, + 0x6973, 0x0078, 0x6958, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, + 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0x7720, 0x210c, 0x81ff, + 0x0040, 0x6991, 0x2061, 0x7d00, 0x2071, 0x7600, 0x017e, 0x1078, + 0x5b94, 0x017f, 0x0040, 0x6994, 0x611a, 0x1078, 0x22b5, 0x1078, + 0x5bfa, 0xa006, 0x0078, 0x6996, 0xa085, 0x0001, 0x017f, 0x0c7f, + 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x5b94, 0x057f, 0x0040, 0x69b3, 0x6612, 0x651a, 0x601f, + 0x0003, 0x2009, 0x004b, 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x69af, 0x0c7e, 0x057e, + 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x5b94, 0x057f, + 0x0040, 0x69dd, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, + 0x2560, 0x1078, 0x399e, 0x0c7f, 0x1078, 0x495a, 0x1078, 0x489d, + 0x2c08, 0x1078, 0x7370, 0x2009, 0x004c, 0x1078, 0x5c21, 0xa085, + 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x69d9, + 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, + 0x5b94, 0x057f, 0x0040, 0x6a08, 0x6612, 0x651a, 0x601f, 0x0003, + 0x2019, 0x0005, 0x0c7e, 0x2560, 0x1078, 0x399e, 0x0c7f, 0x1078, + 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, 0x7370, 0x2009, 0x004d, + 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, + 0xa006, 0x0078, 0x6a04, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, + 0x62a0, 0x0c7e, 0x1078, 0x5b94, 0x057f, 0x0040, 0x6a33, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, 0x0c7e, 0x2560, 0x1078, - 0x39a6, 0x0c7f, 0x1078, 0x4962, 0x1078, 0x48a5, 0x2c08, 0x1078, - 0x737b, 0x2009, 0x004d, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, - 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a0f, 0x0c7e, 0x057e, - 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x5b9c, 0x057f, - 0x0040, 0x6a3e, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, - 0x0c7e, 0x2560, 0x1078, 0x39a6, 0x0c7f, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x2c08, 0x1078, 0x737b, 0x2009, 0x004e, 0x1078, 0x5c29, - 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x6a3a, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, - 0x017f, 0x0040, 0x6a5a, 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, - 0x6012, 0x2009, 0x001f, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, - 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a57, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x6a76, 0x660a, - 0x611a, 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x1078, - 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x6a73, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, - 0x017f, 0x0040, 0x6a91, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, - 0x2009, 0x0000, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, - 0x007c, 0xa006, 0x0078, 0x6a8e, 0x027e, 0x0d7e, 0x6218, 0x2268, - 0x6a3c, 0x82ff, 0x0040, 0x6a9e, 0x8211, 0x6a3e, 0x0d7f, 0x027f, - 0x007c, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0014, 0x007c, - 0x067e, 0x0c7e, 0x0d7e, 0x2031, 0x7652, 0x2634, 0xd6e4, 0x0040, - 0x6ab6, 0x6618, 0x2660, 0x6e44, 0x1078, 0x38de, 0x0d7f, 0x0c7f, - 0x067f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, - 0x6acb, 0xa08e, 0x0003, 0x0040, 0x6acb, 0xa08e, 0x0004, 0x0040, - 0x6acb, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x007e, 0x017e, - 0x6004, 0xa08e, 0x0000, 0x0040, 0x6ae3, 0xa08e, 0x001f, 0x0040, - 0x6ae3, 0xa08e, 0x0028, 0x0040, 0x6ae3, 0xa08e, 0x0029, 0x0040, - 0x6ae3, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x127e, - 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b9c, 0x017f, 0x0040, 0x6b00, - 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x1078, 0x22bb, 0x2009, - 0x0028, 0x1078, 0x5c29, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, - 0xa006, 0x0078, 0x6afd, 0xa186, 0x0015, 0x00c0, 0x6b18, 0x2011, - 0x761e, 0x2204, 0xa086, 0x0074, 0x00c0, 0x6b18, 0x1078, 0x60d4, - 0x6003, 0x0001, 0x6007, 0x0029, 0x1078, 0x4872, 0x0078, 0x6b1c, - 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, 0xa186, 0x0015, 0x00c0, - 0x6b3a, 0x2011, 0x761e, 0x2204, 0xa086, 0x0014, 0x00c0, 0x6b3a, - 0x0d7e, 0x6018, 0x2068, 0x1078, 0x38a1, 0x0d7f, 0x1078, 0x60de, - 0x00c0, 0x6b3a, 0x2001, 0x0006, 0x1078, 0x37d1, 0x1078, 0x5cad, - 0x0078, 0x6b3e, 0x1078, 0x5e57, 0x1078, 0x5c02, 0x007c, 0x6848, - 0xa086, 0x0005, 0x00c0, 0x6b46, 0x1078, 0x6b47, 0x007c, 0x6850, - 0xc0ad, 0x6852, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x6b55, 0x067f, 0x007c, 0x6b65, 0x6d3c, 0x6e1d, - 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b9f, 0x6e8b, 0x6b65, - 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x6b65, 0x1078, 0x12d5, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12d5, 0x1079, 0x6b71, 0x067f, - 0x007c, 0x6b81, 0x718c, 0x6b81, 0x6b81, 0x6b81, 0x6b81, 0x6b81, - 0x6b81, 0x7167, 0x71d6, 0x6b81, 0x6b81, 0x6b81, 0x6b81, 0x6b81, - 0x6b81, 0x1078, 0x12d5, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x12d5, 0x1079, 0x6b8d, 0x067f, 0x007c, 0x6b9d, 0x6fd8, 0x704a, - 0x706c, 0x70b8, 0x6b9d, 0x6b9d, 0x7112, 0x6e97, 0x714f, 0x7153, - 0x6b9d, 0x6b9d, 0x6b9d, 0x6b9d, 0x6b9d, 0x1078, 0x12d5, 0xa1b2, - 0x0030, 0x10c8, 0x12d5, 0x2100, 0x0079, 0x6ba6, 0x6bd6, 0x6cb3, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd8, 0x6c07, 0x6c12, - 0x6c3a, 0x6c40, 0x6c74, 0x6cac, 0x6bd6, 0x6bd6, 0x6cbb, 0x6bd6, - 0x6bd6, 0x6cc2, 0x6cc9, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, 0x6bd6, - 0x6ce6, 0x6bd6, 0x6bd6, 0x6cf1, 0x6bd6, 0x6bd6, 0x1078, 0x12d5, - 0x1078, 0x3a26, 0x6618, 0x0c7e, 0x2660, 0x1078, 0x3837, 0x0c7f, + 0x399e, 0x0c7f, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, + 0x7370, 0x2009, 0x004e, 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, + 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a2f, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x6a4f, + 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, + 0x1078, 0x5c21, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, + 0x0078, 0x6a4c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, + 0x5b94, 0x017f, 0x0040, 0x6a6b, 0x660a, 0x611a, 0x601f, 0x0008, + 0x2d00, 0x6012, 0x2009, 0x0021, 0x1078, 0x5c21, 0xa085, 0x0001, + 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6a68, 0x0c7e, 0x127e, + 0x2091, 0x8000, 0x0c7e, 0x1078, 0x5b94, 0x017f, 0x0040, 0x6a86, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x1078, + 0x5c21, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, + 0x6a83, 0x027e, 0x0d7e, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0040, + 0x6a93, 0x8211, 0x6a3e, 0x0d7f, 0x027f, 0x007c, 0x6013, 0x0000, + 0x601f, 0x0007, 0x6017, 0x0014, 0x007c, 0x067e, 0x0c7e, 0x0d7e, + 0x2031, 0x7652, 0x2634, 0xd6e4, 0x0040, 0x6aab, 0x6618, 0x2660, + 0x6e44, 0x1078, 0x38d6, 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, + 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, 0x6ac0, 0xa08e, 0x0003, + 0x0040, 0x6ac0, 0xa08e, 0x0004, 0x0040, 0x6ac0, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0000, + 0x0040, 0x6ad8, 0xa08e, 0x001f, 0x0040, 0x6ad8, 0xa08e, 0x0028, + 0x0040, 0x6ad8, 0xa08e, 0x0029, 0x0040, 0x6ad8, 0xa085, 0x0001, + 0x017f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, + 0x1078, 0x5b94, 0x017f, 0x0040, 0x6af5, 0x611a, 0x601f, 0x0001, + 0x2d00, 0x6012, 0x1078, 0x22b5, 0x2009, 0x0028, 0x1078, 0x5c21, + 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x6af2, + 0xa186, 0x0015, 0x00c0, 0x6b0d, 0x2011, 0x761e, 0x2204, 0xa086, + 0x0074, 0x00c0, 0x6b0d, 0x1078, 0x60ca, 0x6003, 0x0001, 0x6007, + 0x0029, 0x1078, 0x486a, 0x0078, 0x6b11, 0x1078, 0x5e4d, 0x1078, + 0x5bfa, 0x007c, 0xa186, 0x0015, 0x00c0, 0x6b2f, 0x2011, 0x761e, + 0x2204, 0xa086, 0x0014, 0x00c0, 0x6b2f, 0x0d7e, 0x6018, 0x2068, + 0x1078, 0x3899, 0x0d7f, 0x1078, 0x60d4, 0x00c0, 0x6b2f, 0x2001, + 0x0006, 0x1078, 0x37c9, 0x1078, 0x5ca5, 0x0078, 0x6b33, 0x1078, + 0x5e4d, 0x1078, 0x5bfa, 0x007c, 0x6848, 0xa086, 0x0005, 0x00c0, + 0x6b3b, 0x1078, 0x6b3c, 0x007c, 0x6850, 0xc0ad, 0x6852, 0x007c, + 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x6b4a, + 0x067f, 0x007c, 0x6b5a, 0x6d31, 0x6e12, 0x6b5a, 0x6b5a, 0x6b5a, + 0x6b5a, 0x6b5a, 0x6b94, 0x6e80, 0x6b5a, 0x6b5a, 0x6b5a, 0x6b5a, + 0x6b5a, 0x6b5a, 0x1078, 0x12cd, 0x067e, 0x6000, 0xa0b2, 0x0010, + 0x10c8, 0x12cd, 0x1079, 0x6b66, 0x067f, 0x007c, 0x6b76, 0x7181, + 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x715c, 0x71cb, + 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x6b76, 0x1078, 0x12cd, + 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x12cd, 0x1079, 0x6b82, + 0x067f, 0x007c, 0x6b92, 0x6fcd, 0x703f, 0x7061, 0x70ad, 0x6b92, + 0x6b92, 0x7107, 0x6e8c, 0x7144, 0x7148, 0x6b92, 0x6b92, 0x6b92, + 0x6b92, 0x6b92, 0x1078, 0x12cd, 0xa1b2, 0x0030, 0x10c8, 0x12cd, + 0x2100, 0x0079, 0x6b9b, 0x6bcb, 0x6ca8, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, + 0x6bcb, 0x6bcb, 0x6bcd, 0x6bfc, 0x6c07, 0x6c2f, 0x6c35, 0x6c69, + 0x6ca1, 0x6bcb, 0x6bcb, 0x6cb0, 0x6bcb, 0x6bcb, 0x6cb7, 0x6cbe, + 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6bcb, 0x6cdb, 0x6bcb, 0x6bcb, + 0x6ce6, 0x6bcb, 0x6bcb, 0x1078, 0x12cd, 0x1078, 0x3a1e, 0x6618, + 0x0c7e, 0x2660, 0x1078, 0x382f, 0x0c7f, 0xa6b0, 0x0001, 0x2634, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x6bee, 0x1078, 0x72ac, + 0x00c0, 0x6c29, 0x1078, 0x724a, 0x00c0, 0x6bea, 0x6007, 0x0008, + 0x0078, 0x6ca3, 0x6007, 0x0009, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6bf8, 0x1078, 0x72ac, 0x0040, 0x6be2, 0x0078, 0x6c29, + 0x6013, 0x1900, 0x0078, 0x6bea, 0x6106, 0x1078, 0x720c, 0x6007, + 0x0006, 0x0078, 0x6ca3, 0x6007, 0x0007, 0x0078, 0x6ca3, 0x0d7e, + 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, + 0x0040, 0x6c19, 0xa686, 0x0004, 0x0040, 0x6c19, 0x0d7f, 0x0078, + 0x6c29, 0x1078, 0x730a, 0x00c0, 0x6c24, 0x1078, 0x3899, 0x6007, + 0x000a, 0x0d7f, 0x0078, 0x6ca3, 0x6007, 0x000b, 0x0d7f, 0x0078, + 0x6ca3, 0x1078, 0x22b5, 0x6007, 0x0001, 0x0078, 0x6ca3, 0x1078, + 0x22b5, 0x6007, 0x000c, 0x0078, 0x6ca3, 0x1078, 0x3a1e, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, - 0x6bf9, 0x1078, 0x72b7, 0x00c0, 0x6c34, 0x1078, 0x7255, 0x00c0, - 0x6bf5, 0x6007, 0x0008, 0x0078, 0x6cae, 0x6007, 0x0009, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6c03, 0x1078, 0x72b7, 0x0040, - 0x6bed, 0x0078, 0x6c34, 0x6013, 0x1900, 0x0078, 0x6bf5, 0x6106, - 0x1078, 0x7217, 0x6007, 0x0006, 0x0078, 0x6cae, 0x6007, 0x0007, - 0x0078, 0x6cae, 0x0d7e, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, - 0x8637, 0xa686, 0x0006, 0x0040, 0x6c24, 0xa686, 0x0004, 0x0040, - 0x6c24, 0x0d7f, 0x0078, 0x6c34, 0x1078, 0x7315, 0x00c0, 0x6c2f, - 0x1078, 0x38a1, 0x6007, 0x000a, 0x0d7f, 0x0078, 0x6cae, 0x6007, - 0x000b, 0x0d7f, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x0001, - 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x000c, 0x0078, 0x6cae, - 0x1078, 0x3a26, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, - 0xa082, 0x0006, 0x0048, 0x6c61, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0006, 0x00c0, 0x6c34, 0x1078, 0x7324, 0x00c0, 0x6c5b, 0x6007, - 0x000e, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x000f, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6c6e, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0040, 0x6c53, 0x0078, 0x6c34, 0x6013, 0x1900, - 0x6007, 0x0009, 0x0078, 0x6cae, 0x1078, 0x3a26, 0x6618, 0xa6b0, - 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x6c99, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x00c0, 0x6c34, 0x1078, - 0x734f, 0x00c0, 0x6c93, 0x1078, 0x7255, 0x00c0, 0x6c93, 0x6007, - 0x0010, 0x0078, 0x6cae, 0x1078, 0x22bb, 0x6007, 0x0011, 0x0078, - 0x6cae, 0x1078, 0x744c, 0x0040, 0x6ca6, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0040, 0x6c87, 0x0078, 0x6c34, 0x6013, 0x1900, - 0x6007, 0x0009, 0x0078, 0x6cae, 0x6007, 0x0012, 0x6003, 0x0001, - 0x1078, 0x4872, 0x007c, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, - 0x4872, 0x0078, 0x6cb2, 0x6007, 0x0020, 0x6003, 0x0001, 0x1078, - 0x4872, 0x007c, 0x6007, 0x0023, 0x6003, 0x0001, 0x1078, 0x4872, - 0x007c, 0x017e, 0x027e, 0x2011, 0x7b88, 0x2214, 0x2c08, 0x1078, - 0x7514, 0x00c0, 0x6cda, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, - 0x0078, 0x6cdf, 0x1078, 0x5c02, 0x2160, 0x6007, 0x0025, 0x6003, - 0x0001, 0x1078, 0x4872, 0x027f, 0x017f, 0x007c, 0x6106, 0x1078, - 0x6cf8, 0x6007, 0x002b, 0x0078, 0x6cae, 0x6007, 0x002c, 0x0078, - 0x6cae, 0x6106, 0x1078, 0x6cfd, 0x6007, 0x002e, 0x0078, 0x6cae, - 0x0d7e, 0x1078, 0x6d23, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x6d32, - 0x00c0, 0x6d1c, 0x680c, 0xa08c, 0xff00, 0x6824, 0xa084, 0x00ff, - 0xa115, 0x6212, 0xd1e4, 0x0040, 0x6d11, 0x2009, 0x0001, 0x0078, - 0x6d18, 0xd1ec, 0x0040, 0x6d1c, 0x2009, 0x0000, 0xa294, 0x00ff, - 0x1078, 0x22ff, 0x0078, 0x6d20, 0xa085, 0x0001, 0x0078, 0x6d21, - 0xa006, 0x0d7f, 0x007c, 0x2069, 0x7b8d, 0x6800, 0xa082, 0x0010, - 0x00c8, 0x6d30, 0x6013, 0x0000, 0xa085, 0x0001, 0x0078, 0x6d31, - 0xa006, 0x007c, 0x6013, 0x0000, 0x2069, 0x7b8c, 0x6808, 0xa084, - 0xff00, 0xa086, 0x0800, 0x007c, 0x6004, 0xa0b2, 0x0030, 0x10c8, - 0x12d5, 0xa1b6, 0x0013, 0x00c0, 0x6d48, 0x2008, 0x0079, 0x6d5b, - 0xa1b6, 0x0027, 0x0040, 0x6d50, 0xa1b6, 0x0014, 0x10c0, 0x12d5, - 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, - 0x1078, 0x4c7a, 0x007c, 0x6d8b, 0x6d8d, 0x6d8b, 0x6d8b, 0x6d8b, - 0x6d8d, 0x6d95, 0x6df8, 0x6dbb, 0x6df8, 0x6dcf, 0x6df8, 0x6d95, - 0x6df8, 0x6df0, 0x6df8, 0x6df0, 0x6df8, 0x6df8, 0x6d8b, 0x6d8b, - 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, - 0x6d8b, 0x6d8b, 0x6d8b, 0x6df8, 0x6d8b, 0x6d8b, 0x6df8, 0x6d8b, - 0x6df8, 0x6df8, 0x6d8b, 0x6d8b, 0x6d8b, 0x6d8b, 0x6df8, 0x6df8, - 0x6d8b, 0x6df8, 0x6df8, 0x1078, 0x12d5, 0x1078, 0x4b81, 0x6003, - 0x0002, 0x1078, 0x4c7a, 0x0078, 0x6dfe, 0x0f7e, 0x2079, 0x7651, - 0x7804, 0x0f7f, 0xd0ac, 0x00c0, 0x6df8, 0x2001, 0x0000, 0x1078, - 0x37bd, 0x2001, 0x0002, 0x1078, 0x37d1, 0x1078, 0x4b81, 0x601f, - 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, - 0x4c7a, 0x0c7e, 0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x457b, - 0x0c7f, 0x0078, 0x6dfe, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6df8, 0xa686, - 0x0004, 0x0040, 0x6df8, 0x2001, 0x0004, 0x0078, 0x6df6, 0x2001, - 0x7600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x6dd8, 0x1078, 0x2dc8, - 0x2001, 0x0006, 0x1078, 0x6dff, 0x6618, 0x0d7e, 0x2668, 0x6e04, - 0x0d7f, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x6df8, - 0x2001, 0x0006, 0x0078, 0x6df6, 0x2001, 0x0004, 0x0078, 0x6df6, - 0x2001, 0x0006, 0x1078, 0x6dff, 0x0078, 0x6df8, 0x1078, 0x37df, - 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x017e, - 0x0d7e, 0x6118, 0x2168, 0x6900, 0xd184, 0x0040, 0x6e1a, 0x6104, - 0xa18e, 0x000a, 0x00c0, 0x6e12, 0x699c, 0xd1a4, 0x00c0, 0x6e12, - 0x2001, 0x0007, 0x1078, 0x37d1, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x1078, 0x22dd, 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, - 0x6804, 0xa084, 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, - 0x12d5, 0xa1b6, 0x0015, 0x00c0, 0x6e31, 0x1079, 0x6e38, 0x0078, - 0x6e37, 0xa1b6, 0x0016, 0x10c0, 0x12d5, 0x1079, 0x6e70, 0x007c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x6e44, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x0f7e, 0x2079, 0x7651, 0x7804, - 0x0f7f, 0xd0ac, 0x00c0, 0x6e60, 0x2001, 0x0000, 0x1078, 0x37bd, - 0x2001, 0x0002, 0x1078, 0x37d1, 0x601f, 0x0001, 0x6003, 0x0001, - 0x6007, 0x0002, 0x1078, 0x4872, 0x1078, 0x4c7a, 0x0078, 0x6e6f, - 0x2011, 0x7b83, 0x220c, 0x017e, 0x0c7e, 0x1078, 0x3825, 0x00c0, - 0x6e6f, 0x1078, 0x3621, 0x0c7f, 0x017f, 0x1078, 0x5c02, 0x007c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x6e7c, - 0x5ee1, 0x5ee1, 0x5ee1, 0x5ee1, 0x1078, 0x60d1, 0x00c0, 0x6e88, - 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x4872, 0x0078, 0x6e8a, - 0x1078, 0x5c02, 0x007c, 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12d5, - 0x1078, 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, - 0x0040, 0x0079, 0x6e9b, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6ead, - 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, 0x6eab, - 0x6eab, 0x6eab, 0x6eab, 0x1078, 0x12d5, 0x0d7e, 0x0e7e, 0x0f7e, - 0x157e, 0x047e, 0x027e, 0x6106, 0x2071, 0x7b80, 0x7444, 0xa4a4, - 0xe600, 0x0040, 0x6f1e, 0xa486, 0x2000, 0x0040, 0x6edd, 0xa486, - 0x0400, 0x0040, 0x6edd, 0x7130, 0xa18c, 0x00ff, 0xa182, 0x0010, - 0x00c8, 0x6fb0, 0x0c7e, 0x1078, 0x460c, 0x2c68, 0x0c7f, 0x6a00, - 0xa284, 0x0001, 0x0040, 0x6f91, 0x1078, 0x46ca, 0x0040, 0x6fbc, - 0xa295, 0x0200, 0x6a02, 0x0078, 0x6ee3, 0x2009, 0x0001, 0x2011, - 0x0200, 0x1078, 0x46b4, 0x1078, 0x132f, 0x1040, 0x12d5, 0x6003, - 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, - 0x6c5a, 0x2c00, 0x685e, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, - 0xa18c, 0x00ff, 0xa10d, 0x6946, 0x684f, 0x0000, 0x6857, 0x0036, - 0x1078, 0x3a7a, 0xa486, 0x2000, 0x00c0, 0x6f0c, 0x2019, 0x0017, - 0x1078, 0x74d9, 0x0078, 0x6f7e, 0xa486, 0x0400, 0x00c0, 0x6f16, - 0x2019, 0x0002, 0x1078, 0x74d9, 0x0078, 0x6f7e, 0xa486, 0x0200, - 0x00c0, 0x6f1c, 0x1078, 0x74ca, 0x0078, 0x6f7e, 0x7130, 0xa184, - 0xff00, 0x00c0, 0x6fd0, 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, - 0x6fd0, 0x0c7e, 0x1078, 0x460c, 0x2c68, 0x0c7f, 0x6a00, 0xa284, - 0x0001, 0x0040, 0x6fd4, 0xa284, 0x0300, 0x00c0, 0x6fcc, 0x6804, - 0xa005, 0x0040, 0x6fbc, 0x8001, 0x6806, 0x6003, 0x0007, 0x1078, - 0x1314, 0x0040, 0x6f85, 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, - 0x0116, 0x683b, 0x0000, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, - 0x8007, 0xa10d, 0x6946, 0x6853, 0x003d, 0x7044, 0xa084, 0x0003, - 0xa086, 0x0002, 0x00c0, 0x6f60, 0x684f, 0x0040, 0x0078, 0x6f6a, - 0xa086, 0x0001, 0x00c0, 0x6f68, 0x684f, 0x0080, 0x0078, 0x6f6a, - 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0x7b90, 0xad90, 0x0015, - 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x6f70, 0x200c, - 0x6982, 0x8000, 0x200c, 0x697e, 0x1078, 0x3a7a, 0x027f, 0x047f, - 0x157f, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, - 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x0078, - 0x6f7e, 0x2069, 0x7b92, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, - 0x00c0, 0x6fb0, 0x2069, 0x7b80, 0x686c, 0xa084, 0x00ff, 0x017e, - 0x6110, 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, - 0x6007, 0x0043, 0x1078, 0x4825, 0x1078, 0x4c7a, 0x0078, 0x6f7e, - 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, - 0x1078, 0x4c7a, 0x0078, 0x6f7e, 0x6013, 0x0300, 0x0078, 0x6fc2, - 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x4825, - 0x1078, 0x4c7a, 0x0078, 0x6f7e, 0x6013, 0x0500, 0x0078, 0x6fc2, - 0x6013, 0x0600, 0x0078, 0x6f91, 0x6013, 0x0200, 0x0078, 0x6f91, - 0xa186, 0x0013, 0x00c0, 0x6fea, 0x6004, 0xa08a, 0x0040, 0x1048, - 0x12d5, 0xa08a, 0x0050, 0x10c8, 0x12d5, 0xa082, 0x0040, 0x2008, - 0x0079, 0x701b, 0xa186, 0x0047, 0x00c0, 0x6ff0, 0x0078, 0x704a, - 0xa186, 0x0027, 0x0040, 0x6ff8, 0xa186, 0x0014, 0x10c0, 0x12d5, - 0x6004, 0xa082, 0x0040, 0x2008, 0x0079, 0x6ffe, 0x700e, 0x7010, - 0x7010, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, - 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x700e, 0x1078, 0x12d5, - 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, - 0x1078, 0x4c7a, 0x007c, 0x702b, 0x703b, 0x7034, 0x7044, 0x702b, - 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, 0x702b, - 0x702b, 0x702b, 0x702b, 0x1078, 0x12d5, 0x6010, 0xa088, 0x0013, - 0x2104, 0xa085, 0x0400, 0x200a, 0x1078, 0x4b81, 0x6003, 0x0002, - 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x1078, 0x468d, 0x1078, - 0x5c02, 0x1078, 0x4c7a, 0x007c, 0x1078, 0x4b81, 0x2009, 0x0041, - 0x0078, 0x7112, 0xa182, 0x0040, 0x0079, 0x704e, 0x705e, 0x7060, - 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x7061, 0x705e, 0x705e, - 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x705e, 0x1078, 0x12d5, - 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, - 0x2c10, 0x1078, 0x1572, 0x007c, 0xa182, 0x0040, 0x0079, 0x7070, - 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, 0x7080, - 0x7080, 0x7082, 0x70a5, 0x7080, 0x7080, 0x7080, 0x7080, 0x70a5, - 0x1078, 0x12d5, 0x1078, 0x4c29, 0x1078, 0x4d3a, 0x6010, 0x0d7e, - 0x2068, 0x684c, 0xd0fc, 0x0040, 0x7098, 0xa08c, 0x0003, 0xa18e, - 0x0002, 0x0040, 0x709e, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x7112, - 0x6003, 0x0007, 0x1078, 0x468d, 0x0d7f, 0x007c, 0x1078, 0x468d, - 0x1078, 0x5c02, 0x0d7f, 0x0078, 0x709d, 0x037e, 0x1078, 0x4c29, - 0x1078, 0x4d3a, 0x6010, 0x0d7e, 0x2068, 0x2019, 0x0004, 0x1078, - 0x74fd, 0x1078, 0x6aa1, 0x6017, 0x0028, 0x0d7f, 0x037f, 0x007c, - 0xa186, 0x0013, 0x00c0, 0x70c6, 0x6004, 0xa086, 0x0042, 0x10c0, - 0x12d5, 0x1078, 0x4b81, 0x1078, 0x4c7a, 0x007c, 0xa186, 0x0027, - 0x0040, 0x70ce, 0xa186, 0x0014, 0x00c0, 0x70de, 0x6004, 0xa086, - 0x0042, 0x10c0, 0x12d5, 0x2001, 0x0007, 0x1078, 0x37df, 0x1078, - 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, 0x0040, - 0x0079, 0x70e2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, - 0x70f2, 0x70f4, 0x7100, 0x70f2, 0x70f2, 0x70f2, 0x70f2, 0x70f2, - 0x70f2, 0x70f2, 0x1078, 0x12d5, 0x037e, 0x047e, 0x20e1, 0x0005, - 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x1572, 0x047f, 0x037f, 0x007c, - 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x710c, 0x2009, - 0x0041, 0x0d7f, 0x0078, 0x7112, 0x6003, 0x0007, 0x1078, 0x468d, - 0x0d7f, 0x007c, 0xa182, 0x0040, 0x0079, 0x7116, 0x7126, 0x7128, - 0x7134, 0x7140, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, - 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x7126, 0x1078, 0x12d5, - 0x6003, 0x0001, 0x6106, 0x1078, 0x4825, 0x127e, 0x2091, 0x8000, - 0x1078, 0x4c7a, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x4825, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c7a, 0x127f, 0x007c, - 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, 0x19cf, 0x127e, 0x2091, - 0x8000, 0x1078, 0x4891, 0x1078, 0x4d3a, 0x127f, 0x007c, 0x1078, - 0x4b81, 0x0078, 0x7155, 0x1078, 0x4c29, 0x6110, 0x81ff, 0x0040, - 0x7162, 0x0d7e, 0x2168, 0x037e, 0x2019, 0x0029, 0x1078, 0x74fd, - 0x037f, 0x0d7f, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0xa182, - 0x0085, 0x0079, 0x716b, 0x7172, 0x7172, 0x7172, 0x7174, 0x7172, - 0x7172, 0x7172, 0x1078, 0x12d5, 0x027e, 0x0e7e, 0x2071, 0x7b80, - 0x7220, 0x1078, 0x7417, 0x0040, 0x7181, 0x6007, 0x0086, 0x0078, - 0x7183, 0x6007, 0x0087, 0x6003, 0x0001, 0x1078, 0x4825, 0x1078, - 0x4c7a, 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x719d, - 0x6004, 0xa08a, 0x0085, 0x1048, 0x12d5, 0xa08a, 0x008c, 0x10c8, - 0x12d5, 0xa082, 0x0085, 0x0079, 0x71b0, 0xa186, 0x0027, 0x0040, - 0x71a5, 0xa186, 0x0014, 0x10c0, 0x12d5, 0x2001, 0x0007, 0x1078, - 0x37df, 0x1078, 0x4b81, 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, - 0x71b7, 0x71b9, 0x71b9, 0x71b7, 0x71b7, 0x71b7, 0x71b7, 0x1078, - 0x12d5, 0x1078, 0x4b81, 0x1078, 0x5c02, 0x1078, 0x4c7a, 0x007c, - 0xa182, 0x0085, 0x1048, 0x12d5, 0xa182, 0x008c, 0x10c8, 0x12d5, - 0xa182, 0x0085, 0x0079, 0x71cc, 0x71d3, 0x71d3, 0x71d3, 0x71d5, - 0x71d3, 0x71d3, 0x71d3, 0x1078, 0x12d5, 0x007c, 0x1078, 0x4b81, - 0x1078, 0x6aa1, 0x1078, 0x4c7a, 0x007c, 0x037e, 0x2019, 0x000b, - 0x1078, 0x71e6, 0x601f, 0x0006, 0x037f, 0x007c, 0x127e, 0x037e, - 0x087e, 0x2091, 0x8000, 0x2c40, 0x1078, 0x5915, 0x00c0, 0x7213, - 0x1078, 0x59b6, 0x00c0, 0x7213, 0x6000, 0xa086, 0x0000, 0x0040, - 0x7213, 0x601c, 0xa086, 0x0007, 0x0040, 0x7213, 0x0d7e, 0x6000, - 0xa086, 0x0004, 0x00c0, 0x7206, 0x1078, 0x1676, 0x6010, 0x2068, - 0x1078, 0x693e, 0x0040, 0x720e, 0x1078, 0x74fd, 0x0d7f, 0x6013, - 0x0000, 0x601f, 0x0007, 0x087f, 0x037f, 0x127f, 0x007c, 0x0f7e, - 0x0c7e, 0x037e, 0x157e, 0x2079, 0x7b80, 0x7838, 0xa08c, 0x00ff, - 0x783c, 0x1078, 0x2085, 0x00c0, 0x724e, 0x017e, 0x0c7e, 0x1078, - 0x3825, 0x00c0, 0x724e, 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, - 0x0004, 0x1078, 0x616a, 0x00c0, 0x724e, 0x017f, 0x027f, 0x027e, - 0x017e, 0x2019, 0x0029, 0x1078, 0x5a8a, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x017f, 0x1078, 0x737b, 0x1078, 0x39a6, 0x017f, 0x1078, - 0x3621, 0x6612, 0x6516, 0xa006, 0x0078, 0x7250, 0x0c7f, 0x017f, - 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, - 0x2009, 0x761e, 0x2104, 0xa086, 0x0074, 0x00c0, 0x72ac, 0x2069, - 0x7b8e, 0x690c, 0xa182, 0x0100, 0x0048, 0x729c, 0x6908, 0xa184, - 0x8000, 0x0040, 0x72a8, 0xa184, 0x0800, 0x0040, 0x72a8, 0x6910, - 0xa18a, 0x0001, 0x0048, 0x72a0, 0x6914, 0x2069, 0x7bae, 0x6904, - 0x81ff, 0x00c0, 0x7294, 0x690c, 0xa182, 0x0100, 0x0048, 0x729c, - 0x6908, 0x81ff, 0x00c0, 0x7298, 0x6910, 0xa18a, 0x0001, 0x0048, - 0x72a0, 0x6918, 0xa18a, 0x0001, 0x0048, 0x72a8, 0x0078, 0x72b2, - 0x6013, 0x0100, 0x0078, 0x72ae, 0x6013, 0x0300, 0x0078, 0x72ae, - 0x6013, 0x0500, 0x0078, 0x72ae, 0x6013, 0x0700, 0x0078, 0x72ae, - 0x6013, 0x0900, 0x0078, 0x72ae, 0x6013, 0x0b00, 0x0078, 0x72ae, - 0x6013, 0x0f00, 0x0078, 0x72ae, 0x6013, 0x2d00, 0xa085, 0x0001, - 0x0078, 0x72b3, 0xa006, 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, - 0x0d7e, 0x027e, 0x037e, 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, - 0x00ff, 0xa286, 0x0006, 0x0040, 0x72db, 0xa286, 0x0004, 0x0040, - 0x72db, 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x72db, - 0xa286, 0x0004, 0x0040, 0x72db, 0x0c7e, 0x2d60, 0x1078, 0x3837, - 0x0c7f, 0x0078, 0x730e, 0x2011, 0x7b96, 0xad98, 0x000a, 0x20a9, - 0x0004, 0x1078, 0x616a, 0x00c0, 0x730f, 0x2011, 0x7b9a, 0xad98, - 0x0006, 0x20a9, 0x0004, 0x1078, 0x616a, 0x00c0, 0x730f, 0x047e, - 0x017e, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x7652, - 0x210c, 0xd1a4, 0x0040, 0x7303, 0x2009, 0x0029, 0x1078, 0x7541, - 0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x1078, 0x4962, 0x1078, - 0x48a5, 0x2c08, 0x1078, 0x737b, 0x017f, 0x047f, 0xa006, 0x157f, - 0x037f, 0x027f, 0x0d7f, 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0x7b8e, - 0x6800, 0xa086, 0x0800, 0x0040, 0x7321, 0x6013, 0x0000, 0x0078, - 0x7322, 0xa006, 0x0d7f, 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, - 0x037e, 0x157e, 0x2079, 0x7b8c, 0x7930, 0x7834, 0x1078, 0x2085, - 0x00c0, 0x7348, 0x1078, 0x3825, 0x00c0, 0x7348, 0x2011, 0x7b90, - 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x616a, 0x00c0, 0x7348, - 0x2011, 0x7b94, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, 0x616a, - 0x157f, 0x037f, 0x027f, 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, - 0x007e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2011, 0x7b83, 0x2204, - 0x8211, 0x220c, 0x1078, 0x2085, 0x00c0, 0x7374, 0x1078, 0x3825, - 0x00c0, 0x7374, 0x2011, 0x7b96, 0xac98, 0x000a, 0x20a9, 0x0004, - 0x1078, 0x616a, 0x00c0, 0x7374, 0x2011, 0x7b9a, 0xac98, 0x0006, - 0x20a9, 0x0004, 0x1078, 0x616a, 0x157f, 0x037f, 0x027f, 0x017f, - 0x007f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, - 0x047e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, - 0x2021, 0x7845, 0x2424, 0x2061, 0x7d00, 0x2071, 0x7600, 0x7644, - 0x7060, 0x8001, 0xa602, 0x00c8, 0x73e0, 0x2100, 0xac06, 0x0040, - 0x73d6, 0x1078, 0x7559, 0x0040, 0x73d6, 0x671c, 0xa786, 0x0001, - 0x0040, 0x73f5, 0xa786, 0x0007, 0x0040, 0x73d6, 0x2500, 0xac06, - 0x0040, 0x73d6, 0x2400, 0xac06, 0x0040, 0x73d6, 0x1078, 0x756d, - 0x00c0, 0x73d6, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x73bc, - 0x017e, 0x1078, 0x1676, 0x017f, 0x6010, 0x2068, 0x1078, 0x693e, - 0x0040, 0x73d3, 0xa786, 0x0003, 0x00c0, 0x73e9, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x017e, 0x1078, 0x6b3f, 0x1078, 0x3a7a, - 0x017f, 0x1078, 0x6a94, 0x0d7f, 0x1078, 0x6aa1, 0xace0, 0x0008, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x73e0, 0x0078, 0x738d, - 0x127f, 0x027f, 0x047f, 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, - 0x007c, 0xa786, 0x0006, 0x00c0, 0x73c6, 0xa386, 0x0005, 0x0040, - 0x73d6, 0x1078, 0x74fd, 0x0078, 0x73d3, 0x1078, 0x756d, 0x00c0, - 0x73d6, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x00c0, 0x73d6, - 0x6000, 0xa086, 0x0002, 0x00c0, 0x73d6, 0x1078, 0x6aba, 0x0040, - 0x7411, 0x1078, 0x6ace, 0x00c0, 0x73d6, 0x1078, 0x5e57, 0x0078, - 0x7413, 0x1078, 0x22dd, 0x1078, 0x6aa1, 0x0078, 0x73d6, 0x0c7e, - 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x7514, 0x017f, 0x0040, - 0x7426, 0x601c, 0xa084, 0x000f, 0x1079, 0x7429, 0x0e7f, 0x0c7f, - 0x007c, 0x7431, 0x7431, 0x7431, 0x7431, 0x7431, 0x7431, 0x7433, - 0x7431, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, 0xa080, 0x0028, - 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x1078, - 0x7541, 0x017f, 0x047f, 0x037e, 0x2019, 0x0002, 0x1078, 0x71e6, - 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0001, 0x1078, 0x37bd, - 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, 0x7605, - 0x2011, 0x7b96, 0x1078, 0x616a, 0x037f, 0x027f, 0x017f, 0x157f, - 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x027e, - 0x127e, 0x2091, 0x8000, 0x2061, 0x7d00, 0x2079, 0x0001, 0x8fff, - 0x0040, 0x74bd, 0x2071, 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, - 0x00c8, 0x74bd, 0x88ff, 0x0040, 0x7483, 0x2800, 0xac06, 0x00c0, - 0x74b3, 0x2079, 0x0000, 0x1078, 0x7559, 0x0040, 0x74b3, 0x2400, - 0xac06, 0x0040, 0x74b3, 0x671c, 0xa786, 0x0006, 0x00c0, 0x74b3, - 0xa786, 0x0007, 0x0040, 0x74b3, 0x88ff, 0x00c0, 0x749b, 0x6018, - 0xa206, 0x00c0, 0x74b3, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, - 0x74a3, 0x1078, 0x1676, 0x6010, 0x2068, 0x1078, 0x693e, 0x0040, - 0x74ad, 0x047e, 0x1078, 0x74fd, 0x047f, 0x0d7f, 0x1078, 0x6aa1, - 0x88ff, 0x00c0, 0x74c6, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, - 0xac02, 0x00c8, 0x74bd, 0x0078, 0x746f, 0xa006, 0x127f, 0x027f, - 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, - 0x0078, 0x74be, 0x087e, 0x2041, 0x0000, 0x2c20, 0x2019, 0x0002, - 0x6218, 0x1078, 0x5915, 0x1078, 0x59b6, 0x1078, 0x7462, 0x087f, - 0x007c, 0x027e, 0x047e, 0x087e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x017e, 0x037e, 0x1078, 0x3825, 0x00c0, - 0x74f2, 0x2c10, 0x2041, 0x0000, 0x1078, 0x5915, 0x1078, 0x59b6, - 0x1078, 0x7462, 0x037f, 0x017f, 0x8108, 0x00f0, 0x74e3, 0x157f, - 0x0c7f, 0x087f, 0x047f, 0x027f, 0x007c, 0x017e, 0x0f7e, 0x8dff, - 0x0040, 0x7511, 0x6800, 0xa07d, 0x0040, 0x750e, 0x6803, 0x0000, - 0x6b52, 0x1078, 0x3a7a, 0x2f68, 0x0078, 0x7502, 0x6b52, 0x1078, - 0x3a7a, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, - 0x7d00, 0x2071, 0x7600, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, - 0x753c, 0x2100, 0xac06, 0x0040, 0x752e, 0x6000, 0xa086, 0x0000, - 0x0040, 0x752e, 0x6008, 0xa206, 0x0040, 0x7538, 0xace0, 0x0008, - 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x753c, 0x0078, 0x7519, - 0xa085, 0x0001, 0x0078, 0x753d, 0xa006, 0x037f, 0x047f, 0x0e7f, - 0x007c, 0x0d7e, 0x007e, 0x1078, 0x132f, 0x007f, 0x1040, 0x12d5, - 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, - 0x685e, 0x6956, 0x6c46, 0x684f, 0x0000, 0x1078, 0x3a7a, 0x0d7f, - 0x007c, 0x6700, 0xa786, 0x0000, 0x0040, 0x756c, 0xa786, 0x0001, - 0x0040, 0x756c, 0xa786, 0x000a, 0x0040, 0x756c, 0xa786, 0x0009, - 0x0040, 0x756c, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x6018, 0x2070, - 0x70a0, 0xa206, 0x0e7f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, - 0x8000, 0x2071, 0x7640, 0xd5a4, 0x0040, 0x7581, 0x7034, 0x8000, - 0x7036, 0xd5b4, 0x0040, 0x7587, 0x7030, 0x8000, 0x7032, 0xd5ac, - 0x0040, 0x758e, 0x2071, 0x764a, 0x1078, 0x75bd, 0x0e7f, 0x007f, - 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, - 0x7640, 0xd5a4, 0x0040, 0x759f, 0x7034, 0x8000, 0x7036, 0xd5b4, - 0x0040, 0x75a5, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0x75ac, - 0x2071, 0x764a, 0x1078, 0x75bd, 0x0e7f, 0x007f, 0x127f, 0x007c, - 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7642, 0x1078, - 0x75bd, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, - 0x00c8, 0x75c6, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, - 0x2071, 0x7640, 0x1078, 0x75bd, 0x0e7f, 0x007c, 0x0e7e, 0x2071, - 0x7644, 0x1078, 0x75bd, 0x0e7f, 0x007c, 0x0001, 0x0002, 0x0004, - 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, - 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0xaaff + 0x6c56, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x00c0, 0x6c29, + 0x1078, 0x7319, 0x00c0, 0x6c50, 0x6007, 0x000e, 0x0078, 0x6ca3, + 0x1078, 0x22b5, 0x6007, 0x000f, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6c63, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, + 0x6c48, 0x0078, 0x6c29, 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, + 0x6ca3, 0x1078, 0x3a1e, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, + 0x00ff, 0xa082, 0x0006, 0x0048, 0x6c8e, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0006, 0x00c0, 0x6c29, 0x1078, 0x7344, 0x00c0, 0x6c88, + 0x1078, 0x724a, 0x00c0, 0x6c88, 0x6007, 0x0010, 0x0078, 0x6ca3, + 0x1078, 0x22b5, 0x6007, 0x0011, 0x0078, 0x6ca3, 0x1078, 0x7441, + 0x0040, 0x6c9b, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, + 0x6c7c, 0x0078, 0x6c29, 0x6013, 0x1900, 0x6007, 0x0009, 0x0078, + 0x6ca3, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, + 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x486a, 0x0078, 0x6ca7, + 0x6007, 0x0020, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, 0x6007, + 0x0023, 0x6003, 0x0001, 0x1078, 0x486a, 0x007c, 0x017e, 0x027e, + 0x2011, 0x7b88, 0x2214, 0x2c08, 0x1078, 0x7509, 0x00c0, 0x6ccf, + 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x0078, 0x6cd4, 0x1078, + 0x5bfa, 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x486a, + 0x027f, 0x017f, 0x007c, 0x6106, 0x1078, 0x6ced, 0x6007, 0x002b, + 0x0078, 0x6ca3, 0x6007, 0x002c, 0x0078, 0x6ca3, 0x6106, 0x1078, + 0x6cf2, 0x6007, 0x002e, 0x0078, 0x6ca3, 0x0d7e, 0x1078, 0x6d18, + 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x6d27, 0x00c0, 0x6d11, 0x680c, + 0xa08c, 0xff00, 0x6824, 0xa084, 0x00ff, 0xa115, 0x6212, 0xd1e4, + 0x0040, 0x6d06, 0x2009, 0x0001, 0x0078, 0x6d0d, 0xd1ec, 0x0040, + 0x6d11, 0x2009, 0x0000, 0xa294, 0x00ff, 0x1078, 0x22f9, 0x0078, + 0x6d15, 0xa085, 0x0001, 0x0078, 0x6d16, 0xa006, 0x0d7f, 0x007c, + 0x2069, 0x7b8d, 0x6800, 0xa082, 0x0010, 0x00c8, 0x6d25, 0x6013, + 0x0000, 0xa085, 0x0001, 0x0078, 0x6d26, 0xa006, 0x007c, 0x6013, + 0x0000, 0x2069, 0x7b8c, 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, + 0x007c, 0x6004, 0xa0b2, 0x0030, 0x10c8, 0x12cd, 0xa1b6, 0x0013, + 0x00c0, 0x6d3d, 0x2008, 0x0079, 0x6d50, 0xa1b6, 0x0027, 0x0040, + 0x6d45, 0xa1b6, 0x0014, 0x10c0, 0x12cd, 0x2001, 0x0007, 0x1078, + 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, + 0x6d80, 0x6d82, 0x6d80, 0x6d80, 0x6d80, 0x6d82, 0x6d8a, 0x6ded, + 0x6db0, 0x6ded, 0x6dc4, 0x6ded, 0x6d8a, 0x6ded, 0x6de5, 0x6ded, + 0x6de5, 0x6ded, 0x6ded, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, + 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, + 0x6ded, 0x6d80, 0x6d80, 0x6ded, 0x6d80, 0x6ded, 0x6ded, 0x6d80, + 0x6d80, 0x6d80, 0x6d80, 0x6ded, 0x6ded, 0x6d80, 0x6ded, 0x6ded, + 0x1078, 0x12cd, 0x1078, 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, + 0x0078, 0x6df3, 0x0f7e, 0x2079, 0x7651, 0x7804, 0x0f7f, 0xd0ac, + 0x00c0, 0x6ded, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, + 0x1078, 0x37c9, 0x1078, 0x4b79, 0x601f, 0x0001, 0x6003, 0x0001, + 0x6007, 0x0002, 0x1078, 0x486a, 0x1078, 0x4c72, 0x0c7e, 0x6118, + 0x2160, 0x2009, 0x0001, 0x1078, 0x4573, 0x0c7f, 0x0078, 0x6df3, + 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0006, 0x0040, 0x6ded, 0xa686, 0x0004, 0x0040, 0x6ded, + 0x2001, 0x0004, 0x0078, 0x6deb, 0x2001, 0x7600, 0x2004, 0xa086, + 0x0003, 0x00c0, 0x6dcd, 0x1078, 0x2db9, 0x2001, 0x0006, 0x1078, + 0x6df4, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0040, 0x6ded, 0x2001, 0x0006, 0x0078, + 0x6deb, 0x2001, 0x0004, 0x0078, 0x6deb, 0x2001, 0x0006, 0x1078, + 0x6df4, 0x0078, 0x6ded, 0x1078, 0x37d7, 0x1078, 0x4b79, 0x1078, + 0x5bfa, 0x1078, 0x4c72, 0x007c, 0x017e, 0x0d7e, 0x6118, 0x2168, + 0x6900, 0xd184, 0x0040, 0x6e0f, 0x6104, 0xa18e, 0x000a, 0x00c0, + 0x6e07, 0x699c, 0xd1a4, 0x00c0, 0x6e07, 0x2001, 0x0007, 0x1078, + 0x37c9, 0x2001, 0x0000, 0x1078, 0x37b5, 0x1078, 0x22d7, 0x0d7f, + 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0xff00, + 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x12cd, 0xa1b6, 0x0015, + 0x00c0, 0x6e26, 0x1079, 0x6e2d, 0x0078, 0x6e2c, 0xa1b6, 0x0016, + 0x10c0, 0x12cd, 0x1079, 0x6e65, 0x007c, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x5ed7, 0x5ed7, 0x5ed7, 0x6e39, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x0f7e, 0x2079, 0x7651, 0x7804, 0x0f7f, 0xd0ac, 0x00c0, + 0x6e55, 0x2001, 0x0000, 0x1078, 0x37b5, 0x2001, 0x0002, 0x1078, + 0x37c9, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, + 0x486a, 0x1078, 0x4c72, 0x0078, 0x6e64, 0x2011, 0x7b83, 0x220c, + 0x017e, 0x0c7e, 0x1078, 0x381d, 0x00c0, 0x6e64, 0x1078, 0x3619, + 0x0c7f, 0x017f, 0x1078, 0x5bfa, 0x007c, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x5ed7, 0x5ed7, 0x5ed7, 0x6e71, 0x5ed7, 0x5ed7, 0x5ed7, + 0x5ed7, 0x1078, 0x60c7, 0x00c0, 0x6e7d, 0x6003, 0x0001, 0x6007, + 0x0001, 0x1078, 0x486a, 0x0078, 0x6e7f, 0x1078, 0x5bfa, 0x007c, + 0x6004, 0xa08a, 0x0030, 0x10c8, 0x12cd, 0x1078, 0x4b79, 0x1078, + 0x6a96, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x6e90, + 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea2, 0x6ea0, 0x6ea0, 0x6ea0, + 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, 0x6ea0, + 0x1078, 0x12cd, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, 0x027e, + 0x6106, 0x2071, 0x7b80, 0x7444, 0xa4a4, 0xe600, 0x0040, 0x6f13, + 0xa486, 0x2000, 0x0040, 0x6ed2, 0xa486, 0x0400, 0x0040, 0x6ed2, + 0x7130, 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, 0x6fa5, 0x0c7e, + 0x1078, 0x4604, 0x2c68, 0x0c7f, 0x6a00, 0xa284, 0x0001, 0x0040, + 0x6f86, 0x1078, 0x46c2, 0x0040, 0x6fb1, 0xa295, 0x0200, 0x6a02, + 0x0078, 0x6ed8, 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x46ac, + 0x1078, 0x1327, 0x1040, 0x12cd, 0x6003, 0x0007, 0x2d00, 0x6837, + 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, + 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0xa18c, 0x00ff, 0xa10d, + 0x6946, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x3a72, 0xa486, + 0x2000, 0x00c0, 0x6f01, 0x2019, 0x0017, 0x1078, 0x74ce, 0x0078, + 0x6f73, 0xa486, 0x0400, 0x00c0, 0x6f0b, 0x2019, 0x0002, 0x1078, + 0x74ce, 0x0078, 0x6f73, 0xa486, 0x0200, 0x00c0, 0x6f11, 0x1078, + 0x74bf, 0x0078, 0x6f73, 0x7130, 0xa184, 0xff00, 0x00c0, 0x6fc5, + 0xa18c, 0x00ff, 0xa182, 0x0010, 0x00c8, 0x6fc5, 0x0c7e, 0x1078, + 0x4604, 0x2c68, 0x0c7f, 0x6a00, 0xa284, 0x0001, 0x0040, 0x6fc9, + 0xa284, 0x0300, 0x00c0, 0x6fc1, 0x6804, 0xa005, 0x0040, 0x6fb1, + 0x8001, 0x6806, 0x6003, 0x0007, 0x1078, 0x130c, 0x0040, 0x6f7a, + 0x6013, 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, + 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0xa10d, 0x6946, + 0x6853, 0x003d, 0x7044, 0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, + 0x6f55, 0x684f, 0x0040, 0x0078, 0x6f5f, 0xa086, 0x0001, 0x00c0, + 0x6f5d, 0x684f, 0x0080, 0x0078, 0x6f5f, 0x684f, 0x0000, 0x20a9, + 0x000a, 0x2001, 0x7b90, 0xad90, 0x0015, 0x200c, 0x810f, 0x2112, + 0x8000, 0x8210, 0x00f0, 0x6f65, 0x200c, 0x6982, 0x8000, 0x200c, + 0x697e, 0x1078, 0x3a72, 0x027f, 0x047f, 0x157f, 0x0f7f, 0x0e7f, + 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, + 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, 0x6f73, 0x2069, 0x7b92, + 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x00c0, 0x6fa5, 0x2069, + 0x7b80, 0x686c, 0xa084, 0x00ff, 0x017e, 0x6110, 0xa18c, 0x0700, + 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, 0x6007, 0x0043, 0x1078, + 0x481d, 0x1078, 0x4c72, 0x0078, 0x6f73, 0x6013, 0x0200, 0x6003, + 0x0001, 0x6007, 0x0041, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, + 0x6f73, 0x6013, 0x0300, 0x0078, 0x6fb7, 0x6013, 0x0100, 0x6003, + 0x0001, 0x6007, 0x0041, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0078, + 0x6f73, 0x6013, 0x0500, 0x0078, 0x6fb7, 0x6013, 0x0600, 0x0078, + 0x6f86, 0x6013, 0x0200, 0x0078, 0x6f86, 0xa186, 0x0013, 0x00c0, + 0x6fdf, 0x6004, 0xa08a, 0x0040, 0x1048, 0x12cd, 0xa08a, 0x0050, + 0x10c8, 0x12cd, 0xa082, 0x0040, 0x2008, 0x0079, 0x7010, 0xa186, + 0x0047, 0x00c0, 0x6fe5, 0x0078, 0x703f, 0xa186, 0x0027, 0x0040, + 0x6fed, 0xa186, 0x0014, 0x10c0, 0x12cd, 0x6004, 0xa082, 0x0040, + 0x2008, 0x0079, 0x6ff3, 0x7003, 0x7005, 0x7005, 0x7003, 0x7003, + 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, 0x7003, + 0x7003, 0x7003, 0x7003, 0x1078, 0x12cd, 0x2001, 0x0007, 0x1078, + 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, + 0x7020, 0x7030, 0x7029, 0x7039, 0x7020, 0x7020, 0x7020, 0x7020, + 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, 0x7020, + 0x1078, 0x12cd, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, + 0x200a, 0x1078, 0x4b79, 0x6003, 0x0002, 0x1078, 0x4c72, 0x007c, + 0x1078, 0x4b79, 0x1078, 0x4685, 0x1078, 0x5bfa, 0x1078, 0x4c72, + 0x007c, 0x1078, 0x4b79, 0x2009, 0x0041, 0x0078, 0x7107, 0xa182, + 0x0040, 0x0079, 0x7043, 0x7053, 0x7055, 0x7053, 0x7053, 0x7053, + 0x7053, 0x7053, 0x7056, 0x7053, 0x7053, 0x7053, 0x7053, 0x7053, + 0x7053, 0x7053, 0x7053, 0x1078, 0x12cd, 0x007c, 0x6003, 0x0004, + 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x156a, + 0x007c, 0xa182, 0x0040, 0x0079, 0x7065, 0x7075, 0x7075, 0x7075, + 0x7075, 0x7075, 0x7075, 0x7075, 0x7075, 0x7075, 0x7077, 0x709a, + 0x7075, 0x7075, 0x7075, 0x7075, 0x709a, 0x1078, 0x12cd, 0x1078, + 0x4c21, 0x1078, 0x4d32, 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, + 0x0040, 0x708d, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0040, 0x7093, + 0x2009, 0x0041, 0x0d7f, 0x0078, 0x7107, 0x6003, 0x0007, 0x1078, + 0x4685, 0x0d7f, 0x007c, 0x1078, 0x4685, 0x1078, 0x5bfa, 0x0d7f, + 0x0078, 0x7092, 0x037e, 0x1078, 0x4c21, 0x1078, 0x4d32, 0x6010, + 0x0d7e, 0x2068, 0x2019, 0x0004, 0x1078, 0x74f2, 0x1078, 0x6a96, + 0x6017, 0x0028, 0x0d7f, 0x037f, 0x007c, 0xa186, 0x0013, 0x00c0, + 0x70bb, 0x6004, 0xa086, 0x0042, 0x10c0, 0x12cd, 0x1078, 0x4b79, + 0x1078, 0x4c72, 0x007c, 0xa186, 0x0027, 0x0040, 0x70c3, 0xa186, + 0x0014, 0x00c0, 0x70d3, 0x6004, 0xa086, 0x0042, 0x10c0, 0x12cd, + 0x2001, 0x0007, 0x1078, 0x37d7, 0x1078, 0x4b79, 0x1078, 0x6a96, + 0x1078, 0x4c72, 0x007c, 0xa182, 0x0040, 0x0079, 0x70d7, 0x70e7, + 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e9, 0x70f5, + 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x70e7, 0x1078, + 0x12cd, 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, + 0x1078, 0x156a, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, 0x2068, + 0x684c, 0xd0fc, 0x0040, 0x7101, 0x2009, 0x0041, 0x0d7f, 0x0078, + 0x7107, 0x6003, 0x0007, 0x1078, 0x4685, 0x0d7f, 0x007c, 0xa182, + 0x0040, 0x0079, 0x710b, 0x711b, 0x711d, 0x7129, 0x7135, 0x711b, + 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, 0x711b, + 0x711b, 0x711b, 0x711b, 0x1078, 0x12cd, 0x6003, 0x0001, 0x6106, + 0x1078, 0x481d, 0x127e, 0x2091, 0x8000, 0x1078, 0x4c72, 0x127f, + 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x481d, 0x127e, 0x2091, + 0x8000, 0x1078, 0x4c72, 0x127f, 0x007c, 0x6003, 0x0003, 0x6106, + 0x2c10, 0x1078, 0x19c7, 0x127e, 0x2091, 0x8000, 0x1078, 0x4889, + 0x1078, 0x4d32, 0x127f, 0x007c, 0x1078, 0x4b79, 0x0078, 0x714a, + 0x1078, 0x4c21, 0x6110, 0x81ff, 0x0040, 0x7157, 0x0d7e, 0x2168, + 0x037e, 0x2019, 0x0029, 0x1078, 0x74f2, 0x037f, 0x0d7f, 0x1078, + 0x6a96, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0085, 0x0079, 0x7160, + 0x7167, 0x7167, 0x7167, 0x7169, 0x7167, 0x7167, 0x7167, 0x1078, + 0x12cd, 0x027e, 0x0e7e, 0x2071, 0x7b80, 0x7220, 0x1078, 0x740c, + 0x0040, 0x7176, 0x6007, 0x0086, 0x0078, 0x7178, 0x6007, 0x0087, + 0x6003, 0x0001, 0x1078, 0x481d, 0x1078, 0x4c72, 0x0e7f, 0x027f, + 0x007c, 0xa186, 0x0013, 0x00c0, 0x7192, 0x6004, 0xa08a, 0x0085, + 0x1048, 0x12cd, 0xa08a, 0x008c, 0x10c8, 0x12cd, 0xa082, 0x0085, + 0x0079, 0x71a5, 0xa186, 0x0027, 0x0040, 0x719a, 0xa186, 0x0014, + 0x10c0, 0x12cd, 0x2001, 0x0007, 0x1078, 0x37d7, 0x1078, 0x4b79, + 0x1078, 0x6a96, 0x1078, 0x4c72, 0x007c, 0x71ac, 0x71ae, 0x71ae, + 0x71ac, 0x71ac, 0x71ac, 0x71ac, 0x1078, 0x12cd, 0x1078, 0x4b79, + 0x1078, 0x5bfa, 0x1078, 0x4c72, 0x007c, 0xa182, 0x0085, 0x1048, + 0x12cd, 0xa182, 0x008c, 0x10c8, 0x12cd, 0xa182, 0x0085, 0x0079, + 0x71c1, 0x71c8, 0x71c8, 0x71c8, 0x71ca, 0x71c8, 0x71c8, 0x71c8, + 0x1078, 0x12cd, 0x007c, 0x1078, 0x4b79, 0x1078, 0x6a96, 0x1078, + 0x4c72, 0x007c, 0x037e, 0x2019, 0x000b, 0x1078, 0x71db, 0x601f, + 0x0006, 0x037f, 0x007c, 0x127e, 0x037e, 0x087e, 0x2091, 0x8000, + 0x2c40, 0x1078, 0x590d, 0x00c0, 0x7208, 0x1078, 0x59ae, 0x00c0, + 0x7208, 0x6000, 0xa086, 0x0000, 0x0040, 0x7208, 0x601c, 0xa086, + 0x0007, 0x0040, 0x7208, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, + 0x71fb, 0x1078, 0x166e, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, + 0x7203, 0x1078, 0x74f2, 0x0d7f, 0x6013, 0x0000, 0x601f, 0x0007, + 0x087f, 0x037f, 0x127f, 0x007c, 0x0f7e, 0x0c7e, 0x037e, 0x157e, + 0x2079, 0x7b80, 0x7838, 0xa08c, 0x00ff, 0x783c, 0x1078, 0x207f, + 0x00c0, 0x7243, 0x017e, 0x0c7e, 0x1078, 0x381d, 0x00c0, 0x7243, + 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, + 0x00c0, 0x7243, 0x017f, 0x027f, 0x027e, 0x017e, 0x2019, 0x0029, + 0x1078, 0x5a82, 0x1078, 0x495a, 0x1078, 0x489d, 0x017f, 0x1078, + 0x7370, 0x1078, 0x399e, 0x017f, 0x1078, 0x3619, 0x6612, 0x6516, + 0xa006, 0x0078, 0x7245, 0x0c7f, 0x017f, 0x157f, 0x037f, 0x0c7f, + 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, 0x2009, 0x761e, 0x2104, + 0xa086, 0x0074, 0x00c0, 0x72a1, 0x2069, 0x7b8e, 0x690c, 0xa182, + 0x0100, 0x0048, 0x7291, 0x6908, 0xa184, 0x8000, 0x0040, 0x729d, + 0xa184, 0x0800, 0x0040, 0x729d, 0x6910, 0xa18a, 0x0001, 0x0048, + 0x7295, 0x6914, 0x2069, 0x7bae, 0x6904, 0x81ff, 0x00c0, 0x7289, + 0x690c, 0xa182, 0x0100, 0x0048, 0x7291, 0x6908, 0x81ff, 0x00c0, + 0x728d, 0x6910, 0xa18a, 0x0001, 0x0048, 0x7295, 0x6918, 0xa18a, + 0x0001, 0x0048, 0x729d, 0x0078, 0x72a7, 0x6013, 0x0100, 0x0078, + 0x72a3, 0x6013, 0x0300, 0x0078, 0x72a3, 0x6013, 0x0500, 0x0078, + 0x72a3, 0x6013, 0x0700, 0x0078, 0x72a3, 0x6013, 0x0900, 0x0078, + 0x72a3, 0x6013, 0x0b00, 0x0078, 0x72a3, 0x6013, 0x0f00, 0x0078, + 0x72a3, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x72a8, 0xa006, + 0x017f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e, + 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006, + 0x0040, 0x72d0, 0xa286, 0x0004, 0x0040, 0x72d0, 0xa394, 0xff00, + 0x8217, 0xa286, 0x0006, 0x0040, 0x72d0, 0xa286, 0x0004, 0x0040, + 0x72d0, 0x0c7e, 0x2d60, 0x1078, 0x382f, 0x0c7f, 0x0078, 0x7303, + 0x2011, 0x7b96, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, + 0x00c0, 0x7304, 0x2011, 0x7b9a, 0xad98, 0x0006, 0x20a9, 0x0004, + 0x1078, 0x6160, 0x00c0, 0x7304, 0x047e, 0x017e, 0x6aa0, 0xa294, + 0x00ff, 0x8227, 0xa006, 0x2009, 0x7652, 0x210c, 0xd1a4, 0x0040, + 0x72f8, 0x2009, 0x0029, 0x1078, 0x7536, 0x6800, 0xc0e5, 0x6802, + 0x2019, 0x0029, 0x1078, 0x495a, 0x1078, 0x489d, 0x2c08, 0x1078, + 0x7370, 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f, + 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0x7b8e, 0x6800, 0xa086, 0x0800, + 0x0040, 0x7316, 0x6013, 0x0000, 0x0078, 0x7317, 0xa006, 0x0d7f, + 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079, + 0x7b8c, 0x7930, 0x7834, 0x1078, 0x207f, 0x00c0, 0x733d, 0x1078, + 0x381d, 0x00c0, 0x733d, 0x2011, 0x7b90, 0xac98, 0x000a, 0x20a9, + 0x0004, 0x1078, 0x6160, 0x00c0, 0x733d, 0x2011, 0x7b94, 0xac98, + 0x0006, 0x20a9, 0x0004, 0x1078, 0x6160, 0x157f, 0x037f, 0x027f, + 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e, + 0x037e, 0x157e, 0x2011, 0x7b83, 0x2204, 0x8211, 0x220c, 0x1078, + 0x207f, 0x00c0, 0x7369, 0x1078, 0x381d, 0x00c0, 0x7369, 0x2011, + 0x7b96, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x6160, 0x00c0, + 0x7369, 0x2011, 0x7b9a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, + 0x6160, 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c, + 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x127e, + 0x2091, 0x8000, 0x2029, 0x783f, 0x252c, 0x2021, 0x7845, 0x2424, + 0x2061, 0x7d00, 0x2071, 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, + 0x00c8, 0x73d5, 0x2100, 0xac06, 0x0040, 0x73cb, 0x1078, 0x754e, + 0x0040, 0x73cb, 0x671c, 0xa786, 0x0001, 0x0040, 0x73ea, 0xa786, + 0x0007, 0x0040, 0x73cb, 0x2500, 0xac06, 0x0040, 0x73cb, 0x2400, + 0xac06, 0x0040, 0x73cb, 0x1078, 0x7562, 0x00c0, 0x73cb, 0x0d7e, + 0x6000, 0xa086, 0x0004, 0x00c0, 0x73b1, 0x017e, 0x1078, 0x166e, + 0x017f, 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x73c8, 0xa786, + 0x0003, 0x00c0, 0x73de, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x017e, 0x1078, 0x6b34, 0x1078, 0x3a72, 0x017f, 0x1078, 0x6a89, + 0x0d7f, 0x1078, 0x6a96, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x73d5, 0x0078, 0x7382, 0x127f, 0x027f, 0x047f, + 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, + 0x00c0, 0x73bb, 0xa386, 0x0005, 0x0040, 0x73cb, 0x1078, 0x74f2, + 0x0078, 0x73c8, 0x1078, 0x7562, 0x00c0, 0x73cb, 0xa180, 0x0001, + 0x2004, 0xa086, 0x0018, 0x00c0, 0x73cb, 0x6000, 0xa086, 0x0002, + 0x00c0, 0x73cb, 0x1078, 0x6aaf, 0x0040, 0x7406, 0x1078, 0x6ac3, + 0x00c0, 0x73cb, 0x1078, 0x5e4d, 0x0078, 0x7408, 0x1078, 0x22d7, + 0x1078, 0x6a96, 0x0078, 0x73cb, 0x0c7e, 0x0e7e, 0x017e, 0x2c08, + 0x2170, 0x1078, 0x7509, 0x017f, 0x0040, 0x741b, 0x601c, 0xa084, + 0x000f, 0x1079, 0x741e, 0x0e7f, 0x0c7f, 0x007c, 0x7426, 0x7426, + 0x7426, 0x7426, 0x7426, 0x7426, 0x7428, 0x7426, 0xa006, 0x007c, + 0x047e, 0x017e, 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, + 0x8427, 0x2c00, 0x2009, 0x0020, 0x1078, 0x7536, 0x017f, 0x047f, + 0x037e, 0x2019, 0x0002, 0x1078, 0x71db, 0x037f, 0xa085, 0x0001, + 0x007c, 0x2001, 0x0001, 0x1078, 0x37b5, 0x157e, 0x017e, 0x027e, + 0x037e, 0x20a9, 0x0004, 0x2019, 0x7605, 0x2011, 0x7b96, 0x1078, + 0x6160, 0x037f, 0x027f, 0x017f, 0x157f, 0xa005, 0x007c, 0x0f7e, + 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, + 0x2061, 0x7d00, 0x2079, 0x0001, 0x8fff, 0x0040, 0x74b2, 0x2071, + 0x7600, 0x7644, 0x7060, 0x8001, 0xa602, 0x00c8, 0x74b2, 0x88ff, + 0x0040, 0x7478, 0x2800, 0xac06, 0x00c0, 0x74a8, 0x2079, 0x0000, + 0x1078, 0x754e, 0x0040, 0x74a8, 0x2400, 0xac06, 0x0040, 0x74a8, + 0x671c, 0xa786, 0x0006, 0x00c0, 0x74a8, 0xa786, 0x0007, 0x0040, + 0x74a8, 0x88ff, 0x00c0, 0x7490, 0x6018, 0xa206, 0x00c0, 0x74a8, + 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x7498, 0x1078, 0x166e, + 0x6010, 0x2068, 0x1078, 0x6938, 0x0040, 0x74a2, 0x047e, 0x1078, + 0x74f2, 0x047f, 0x0d7f, 0x1078, 0x6a96, 0x88ff, 0x00c0, 0x74bb, + 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, 0xac02, 0x00c8, 0x74b2, + 0x0078, 0x7464, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f, 0x0c7f, + 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078, 0x74b3, 0x087e, + 0x2041, 0x0000, 0x2c20, 0x2019, 0x0002, 0x6218, 0x1078, 0x590d, + 0x1078, 0x59ae, 0x1078, 0x7457, 0x087f, 0x007c, 0x027e, 0x047e, + 0x087e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, + 0x017e, 0x037e, 0x1078, 0x381d, 0x00c0, 0x74e7, 0x2c10, 0x2041, + 0x0000, 0x1078, 0x590d, 0x1078, 0x59ae, 0x1078, 0x7457, 0x037f, + 0x017f, 0x8108, 0x00f0, 0x74d8, 0x157f, 0x0c7f, 0x087f, 0x047f, + 0x027f, 0x007c, 0x017e, 0x0f7e, 0x8dff, 0x0040, 0x7506, 0x6800, + 0xa07d, 0x0040, 0x7503, 0x6803, 0x0000, 0x6b52, 0x1078, 0x3a72, + 0x2f68, 0x0078, 0x74f7, 0x6b52, 0x1078, 0x3a72, 0x0f7f, 0x017f, + 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, 0x7d00, 0x2071, 0x7600, + 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, 0x7531, 0x2100, 0xac06, + 0x0040, 0x7523, 0x6000, 0xa086, 0x0000, 0x0040, 0x7523, 0x6008, + 0xa206, 0x0040, 0x752d, 0xace0, 0x0008, 0x2001, 0x7615, 0x2004, + 0xac02, 0x00c8, 0x7531, 0x0078, 0x750e, 0xa085, 0x0001, 0x0078, + 0x7532, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, 0x0d7e, 0x007e, + 0x1078, 0x1327, 0x007f, 0x1040, 0x12cd, 0x6837, 0x010d, 0x6803, + 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x685e, 0x6956, 0x6c46, + 0x684f, 0x0000, 0x1078, 0x3a72, 0x0d7f, 0x007c, 0x6700, 0xa786, + 0x0000, 0x0040, 0x7561, 0xa786, 0x0001, 0x0040, 0x7561, 0xa786, + 0x000a, 0x0040, 0x7561, 0xa786, 0x0009, 0x0040, 0x7561, 0xa085, + 0x0001, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x70a0, 0xa206, 0x0e7f, + 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7640, + 0xd5a4, 0x0040, 0x7576, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, + 0x757c, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0x7583, 0x2071, + 0x764a, 0x1078, 0x75b2, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, + 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x7640, 0xd5a4, 0x0040, + 0x7594, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0x759a, 0x7030, + 0x8000, 0x7032, 0xd5ac, 0x0040, 0x75a1, 0x2071, 0x764a, 0x1078, + 0x75b2, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0x7642, 0x1078, 0x75b2, 0x0e7f, 0x007f, + 0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, 0x00c8, 0x75bb, 0x8e70, + 0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, 0x2071, 0x7640, 0x1078, + 0x75b2, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x7644, 0x1078, 0x75b2, + 0x0e7f, 0x007c, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, + 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, + 0x4000, 0x8000, 0x2212 +}; + +/* + * Firmware Version 2.00.16 (09:36 Jun 29, 1999) + */ + +unsigned short risc_code2200[] = { + 0x0470, 0x0000, 0x0000, 0x81bd, 0x0000, 0x0002, 0x0000, 0x0010, + 0x0027, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, + 0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, + 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972, + 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, + 0x322e, 0x3030, 0x2e31, 0x3620, 0x2020, 0x2020, 0x2400, 0x20c1, + 0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0x96ff, 0x2091, + 0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x2490, + 0x2051, 0x9200, 0x2a70, 0x2029, 0xb100, 0x2031, 0xffff, 0x2039, + 0xb0f5, 0x2021, 0x0200, 0x0804, 0x136b, 0x20a1, 0x91bd, 0xa00e, + 0x20a9, 0x0743, 0x41a4, 0x3400, 0x755e, 0x7662, 0x775a, 0x7466, + 0x746a, 0x20a1, 0x9900, 0x7160, 0x810d, 0x810d, 0x810d, 0x810d, + 0xa18c, 0x000f, 0x2001, 0x0009, 0xa112, 0xa00e, 0x21a8, 0x41a4, + 0x3400, 0x8211, 0x1dd8, 0x7160, 0x3400, 0xa102, 0x0120, 0x0218, + 0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0x9200, + 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001, + 0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0, + 0x2009, 0x9200, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e, + 0x41a4, 0x080c, 0x1322, 0x080c, 0x14b6, 0x080c, 0x1649, 0x080c, + 0x1c81, 0x080c, 0x41d4, 0x080c, 0x7494, 0x080c, 0x1439, 0x080c, + 0x2819, 0x080c, 0x4e42, 0x080c, 0x4757, 0x080c, 0x5874, 0x080c, + 0x56c0, 0x080c, 0x2138, 0x080c, 0x5ed0, 0x080c, 0x532f, 0x080c, + 0x206a, 0x080c, 0x210e, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, + 0x10c7, 0x7820, 0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, + 0x10bf, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, + 0x7003, 0x0000, 0x2a70, 0x7000, 0xa08e, 0x0003, 0x1168, 0x080c, + 0x36d4, 0x080c, 0x2840, 0x080c, 0x4e90, 0x080c, 0x493b, 0x080c, + 0x58b1, 0x080c, 0x56d8, 0x0c70, 0x000b, 0x0c88, 0x10e8, 0x10e9, + 0x11b8, 0x10e6, 0x123f, 0x131f, 0x1320, 0x1321, 0x080c, 0x13fe, + 0x0005, 0x0126, 0x00f6, 0x2091, 0x8000, 0x080c, 0x4dc5, 0x0150, + 0x080c, 0x4deb, 0x11f8, 0x2079, 0x0100, 0x7828, 0xa085, 0x1800, + 0x782a, 0x00c0, 0x080c, 0x4d10, 0x7088, 0xa086, 0x0026, 0x1904, + 0x119d, 0x2079, 0x0100, 0x7827, 0xffff, 0x782b, 0x1c2b, 0x2011, + 0x4ce2, 0x080c, 0x5731, 0x2011, 0x8030, 0x2019, 0x0000, 0x7087, + 0x0000, 0x00a8, 0x080c, 0x3a6a, 0x2079, 0x0100, 0x7844, 0xa005, + 0x1904, 0x119d, 0x2011, 0x40af, 0x080c, 0x5731, 0x780f, 0x03ff, + 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, 0x8010, 0x73c4, 0x080c, + 0x3698, 0x080c, 0x706b, 0x2011, 0x0004, 0x080c, 0x82f3, 0x080c, + 0x46a8, 0x080c, 0x4dc5, 0x0158, 0x080c, 0x41bd, 0x0140, 0x7087, + 0x0001, 0x70bf, 0x0000, 0x080c, 0x3bfd, 0x0804, 0x119d, 0x70d3, + 0x0000, 0x70cf, 0x0000, 0x706f, 0x0000, 0x7073, 0x0000, 0x080c, + 0x11a0, 0x72c8, 0x080c, 0x4dc5, 0x1160, 0x2011, 0x0000, 0x2001, + 0x0204, 0x2004, 0x2019, 0x94c8, 0x201a, 0x704f, 0xffff, 0x7053, + 0x00ef, 0x2079, 0x9251, 0x7804, 0xd0ac, 0x0108, 0xc295, 0x72ca, + 0x080c, 0x4dc5, 0x0118, 0xa296, 0x0004, 0x0500, 0x2011, 0x0001, + 0x080c, 0x82f3, 0x080c, 0x854a, 0x7097, 0x0000, 0x709b, 0xffff, + 0x7003, 0x0002, 0x00fe, 0x080c, 0x251c, 0x2011, 0x0005, 0x080c, + 0x718f, 0x080c, 0x6462, 0x080c, 0x4dc5, 0x0130, 0x00c6, 0x2061, + 0x0100, 0x60e3, 0x0008, 0x00ce, 0x012e, 0x00c8, 0x080c, 0x854a, + 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, + 0x080c, 0x718f, 0x080c, 0x6462, 0x080c, 0x4dc5, 0x0130, 0x00c6, + 0x2061, 0x0100, 0x60e3, 0x0008, 0x00ce, 0x00fe, 0x012e, 0x0005, + 0x00c6, 0x080c, 0x4dc5, 0x1118, 0x20a9, 0x0100, 0x0010, 0x20a9, + 0x0082, 0x080c, 0x4dc5, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, + 0x007e, 0x080c, 0x441f, 0x8108, 0x1f04, 0x11b1, 0x00ce, 0x0005, + 0x0126, 0x2091, 0x8000, 0x7098, 0xa086, 0xffff, 0x0130, 0x080c, + 0x251c, 0x080c, 0x6462, 0x0804, 0x123d, 0x70c8, 0xd0ac, 0x1110, + 0xd09c, 0x0558, 0xd084, 0x0548, 0x0006, 0x70c8, 0xa084, 0x0030, + 0x000e, 0x1138, 0x00f6, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, + 0x00fe, 0xd08c, 0x01d0, 0x70cc, 0xa086, 0xffff, 0x0190, 0x080c, + 0x25fd, 0x080c, 0x6462, 0x70c8, 0xd094, 0x1904, 0x123d, 0x2011, + 0x0001, 0x2019, 0x0000, 0x080c, 0x2631, 0x080c, 0x6462, 0x0804, + 0x123d, 0x70d0, 0xa005, 0x1904, 0x123d, 0x7094, 0xa005, 0x1904, + 0x123d, 0x70c8, 0xd0a4, 0x0110, 0xd0b4, 0x05f8, 0x2001, 0x9252, + 0x2004, 0xd0ac, 0x01c0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, + 0x0000, 0x0016, 0x080c, 0x4434, 0x1118, 0x6000, 0xd0ec, 0x1138, + 0x001e, 0x8108, 0x1f04, 0x1209, 0x00ce, 0x015e, 0x0020, 0x001e, + 0x00ce, 0x015e, 0x0410, 0x00f6, 0x2079, 0x0100, 0x780c, 0xc0b5, + 0x780e, 0x00fe, 0x7003, 0x0003, 0x709b, 0xffff, 0xa006, 0x080c, + 0x23ba, 0x080c, 0x370a, 0x2001, 0x94e6, 0x2004, 0xa086, 0x0005, + 0x1120, 0x2011, 0x0000, 0x080c, 0x718f, 0x2011, 0x0000, 0x080c, + 0x7199, 0x080c, 0x6462, 0x080c, 0x651c, 0x012e, 0x0005, 0x0016, + 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, + 0x080c, 0x4186, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, + 0x0110, 0x7827, 0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, + 0x0036, 0x0156, 0x7954, 0xd1ac, 0x1904, 0x12a5, 0x080c, 0x4dd7, + 0x0158, 0x080c, 0x4deb, 0x1128, 0x2001, 0x94d7, 0x2003, 0x0000, + 0x0070, 0x080c, 0x4dcd, 0x0dc0, 0x2001, 0x94d7, 0x2003, 0xaaaa, + 0x2001, 0x94d8, 0x2003, 0x0001, 0x080c, 0x4d10, 0x0058, 0x080c, + 0x4dc5, 0x0140, 0x2009, 0x00f8, 0x080c, 0x4186, 0x7843, 0x0090, + 0x7843, 0x0010, 0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, + 0x4dc5, 0x0138, 0x7824, 0xd0ac, 0x1904, 0x130d, 0x1f04, 0x1284, + 0x0070, 0x7824, 0x080c, 0x4de1, 0x0118, 0xd0ac, 0x1904, 0x130d, + 0xa084, 0x1800, 0x0d98, 0x7003, 0x0001, 0x0804, 0x130d, 0x2001, + 0x0001, 0x080c, 0x23ba, 0x0804, 0x1318, 0x7850, 0xa084, 0x0180, + 0x7852, 0x782f, 0x0020, 0x20a9, 0x0050, 0x1d04, 0x12ad, 0x2091, + 0x6000, 0x1f04, 0x12ad, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, + 0x7852, 0x782f, 0x0000, 0x080c, 0x4dd7, 0x0158, 0x080c, 0x4deb, + 0x1128, 0x2001, 0x94d7, 0x2003, 0x0000, 0x0070, 0x080c, 0x4dcd, + 0x0dc0, 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x0020, 0x2009, 0x00f8, 0x080c, 0x4186, + 0x20a9, 0x000e, 0xe000, 0x1f04, 0x12da, 0x7850, 0xa084, 0x0180, + 0xa085, 0x1400, 0x7852, 0x080c, 0x4dc5, 0x0120, 0x7843, 0x0090, + 0x7843, 0x0010, 0x2019, 0x61a8, 0x7820, 0xd09c, 0x1130, 0x080c, + 0x4dc5, 0x0130, 0x7824, 0xd0ac, 0x11c0, 0x8319, 0x1da8, 0x0080, + 0x7827, 0x1800, 0xe000, 0xe000, 0x7824, 0x080c, 0x4de1, 0x0110, + 0xd0ac, 0x1158, 0xa084, 0x1800, 0x0d80, 0x7003, 0x0001, 0x0028, + 0x2001, 0x0001, 0x080c, 0x23ba, 0x0028, 0x7827, 0x0048, 0x7828, + 0xc09d, 0x782a, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, + 0x015e, 0x003e, 0x000e, 0x012e, 0x00fe, 0x001e, 0x0005, 0x0005, + 0x0005, 0x0005, 0x2a70, 0x2001, 0x94d7, 0x2003, 0x0000, 0x7087, + 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0218, 0x704f, + 0xffff, 0x0010, 0x704f, 0x0000, 0x7057, 0xffff, 0x706f, 0x0000, + 0x7073, 0x0000, 0x080c, 0x854a, 0x2061, 0x94c7, 0x6003, 0x0909, + 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, 0x00ff, + 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, 0x94cf, + 0x6003, 0x8800, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, 0x0200, + 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, 0x0000, + 0x2061, 0x94df, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, + 0x600f, 0x2020, 0x0005, 0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, + 0xa186, 0x0001, 0x1148, 0x2031, 0x8fff, 0x2039, 0xa501, 0x2021, + 0x0100, 0x2029, 0xa500, 0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, + 0x0000, 0x00b8, 0xa186, 0x0005, 0x1118, 0x2011, 0x0001, 0x0088, + 0xa186, 0x0009, 0x1118, 0x2011, 0x0002, 0x0058, 0xa186, 0x000a, + 0x1118, 0x2011, 0x0002, 0x0028, 0xa186, 0x0055, 0x1110, 0x2011, + 0x0003, 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, + 0xa00e, 0x2011, 0x0003, 0x2019, 0x13a7, 0x0804, 0x13f8, 0x2019, + 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, + 0xa306, 0x2262, 0x1110, 0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, + 0x13ba, 0x04f0, 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, + 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, + 0x2061, 0xffff, 0x2262, 0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, + 0x2011, 0x0002, 0x2019, 0x13d5, 0x0418, 0x2061, 0xffff, 0x2019, + 0xaaaa, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, + 0x1180, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, + 0x2c04, 0x2061, 0xffff, 0x2262, 0xa306, 0x1110, 0xc195, 0x0008, + 0xc19d, 0x2011, 0x0001, 0x2019, 0x13f6, 0x0010, 0x0804, 0x136c, + 0x3800, 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0837, 0x2091, 0x8000, + 0x0e04, 0x1400, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084, + 0x1de8, 0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900, + 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0156, + 0x0146, 0x20a9, 0x0010, 0x20a1, 0x95e6, 0x2091, 0x2000, 0x40a1, + 0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010, 0x2091, + 0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1, 0x014e, + 0x015e, 0x2079, 0x9200, 0x7803, 0x0005, 0x2091, 0x4080, 0x0cf8, + 0x0005, 0x2071, 0x9200, 0x715c, 0x712e, 0x2021, 0x0001, 0xa190, + 0x0030, 0xa298, 0x0030, 0x0240, 0x7060, 0xa302, 0x1228, 0x220a, + 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800, 0xd08c, 0x0148, 0x7060, + 0xa086, 0x9200, 0x0128, 0x7063, 0x9200, 0x2011, 0x1000, 0x0c48, + 0x200b, 0x0000, 0x74aa, 0x74ae, 0x70df, 0x0010, 0x0005, 0x00e6, + 0x0126, 0x2091, 0x8000, 0x2071, 0x9200, 0x70ac, 0x0016, 0x2008, + 0x70dc, 0xa16a, 0x2100, 0x001e, 0x0268, 0x8001, 0x70ae, 0x702c, + 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, + 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x2071, 0x9200, 0x0126, + 0x2091, 0x8000, 0x70ac, 0x8001, 0x0260, 0x70ae, 0x702c, 0x2068, + 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, + 0x0005, 0xa06e, 0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, + 0x9200, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, 0x70ae, + 0x012e, 0x00ee, 0x0005, 0x8dff, 0x0138, 0x6804, 0x6807, 0x0000, + 0x0006, 0x0c49, 0x00de, 0x0cb8, 0x0005, 0x00e6, 0x2071, 0x9200, + 0x70ac, 0xa08a, 0x0010, 0xa00d, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x9508, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, + 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x00ee, 0x0005, 0x00e6, + 0x2270, 0x700b, 0x0000, 0x2071, 0x9508, 0x7018, 0xa088, 0x9511, + 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x1128, + 0x00f6, 0x2079, 0x0010, 0x0081, 0x00fe, 0x00ee, 0x0005, 0x00e6, + 0x2071, 0x9508, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, + 0x0019, 0x00fe, 0x00ee, 0x0005, 0x7000, 0x0002, 0x14f3, 0x1557, + 0x1574, 0x1574, 0x1f79, 0x7018, 0x711c, 0xa106, 0x1118, 0x7007, + 0x0000, 0x0005, 0x00d6, 0xa180, 0x9511, 0x2004, 0x700a, 0x2068, + 0x8108, 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, + 0x6828, 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, + 0x680c, 0x7016, 0x6804, 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, + 0x0029, 0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, + 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, + 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, + 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, + 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, 0x2011, + 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x22a8, + 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300, 0x7016, 0x7803, + 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x0136, + 0x0146, 0x0156, 0x2099, 0x930e, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0041, + 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b, 0x9309, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2001, + 0x933d, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, 0x2001, 0x933e, + 0x20ac, 0x53a6, 0x2099, 0x933f, 0x20a1, 0x0018, 0x20a9, 0x0008, + 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0001, + 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0x933a, 0x012e, + 0x015e, 0x014e, 0x013e, 0x0005, 0x0016, 0x00e6, 0x2071, 0x9508, + 0x00f6, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002, 0xd1fc, 0x0120, + 0xa18c, 0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, + 0x14ec, 0x15b8, 0x15e2, 0x1608, 0x1638, 0x1f96, 0x15b7, 0x0cf8, + 0xa18c, 0x0700, 0x1508, 0x0136, 0x0146, 0x0156, 0x7014, 0x20a0, + 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, + 0x7016, 0x015e, 0x014e, 0x013e, 0x700c, 0xa005, 0x0530, 0x080c, + 0x151e, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, + 0x0000, 0x080c, 0x14ec, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, + 0x0200, 0x0ca8, 0xa18c, 0x0700, 0x1130, 0x700c, 0xa005, 0x0168, + 0x080c, 0x1533, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, + 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, 0x00d6, 0x7008, 0x2068, + 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c, 0x6832, + 0x680b, 0x0100, 0x00de, 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, + 0xa18c, 0x0700, 0x1540, 0x0136, 0x0146, 0x0156, 0x2001, 0x930c, + 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, + 0x20a9, 0x0020, 0x53a5, 0x2001, 0x930e, 0x2004, 0xd0bc, 0x0148, + 0x2001, 0x9317, 0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, + 0x53a5, 0x015e, 0x014e, 0x013e, 0x7007, 0x0000, 0x080c, 0x4f27, + 0x080c, 0x14ec, 0x0005, 0x2011, 0x8003, 0x080c, 0x3698, 0x0cf8, + 0xa18c, 0x0700, 0x1148, 0x2001, 0x933c, 0x2003, 0x0100, 0x7007, + 0x0000, 0x080c, 0x14ec, 0x0005, 0x2011, 0x8004, 0x080c, 0x3698, + 0x0cf8, 0x0126, 0x2091, 0x2200, 0x2079, 0x0030, 0x2071, 0x9519, + 0x7003, 0x0000, 0x700f, 0x9520, 0x7013, 0x9520, 0x780f, 0x00f0, + 0x012e, 0x0005, 0x6934, 0xa184, 0x0007, 0x0002, 0x1666, 0x16ab, + 0x1666, 0x1666, 0x166a, 0x1693, 0x167a, 0x1671, 0xa085, 0x0001, + 0x0804, 0x16c5, 0xa186, 0x0024, 0x05f0, 0xa186, 0x002c, 0x05d8, + 0x0ca8, 0x684c, 0xd0bc, 0x0d90, 0x6860, 0x682e, 0x685c, 0x682a, + 0x6858, 0x04c8, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d38, 0x684c, + 0xd0bc, 0x0d20, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, + 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, + 0x6832, 0x6858, 0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x1970, + 0x684c, 0xd0ac, 0x0958, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, + 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, 0x6832, 0xa006, 0x682e, + 0x682a, 0x6858, 0x0080, 0x684c, 0xd0ac, 0x0904, 0x1666, 0xa006, + 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, 0x1f59, 0x210d, + 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, + 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007, + 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x82ff, 0x0178, 0xa280, + 0x0004, 0x00d6, 0x206c, 0x684c, 0xd0dc, 0x1120, 0x080c, 0x165a, + 0x190c, 0x13fe, 0x6808, 0x8000, 0x680a, 0x00de, 0x0126, 0x0046, + 0x0036, 0x0026, 0x2091, 0x2200, 0x002e, 0x003e, 0x004e, 0x7000, + 0xa005, 0x0178, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, + 0x8108, 0xa182, 0x953b, 0x0210, 0x2009, 0x9520, 0x710e, 0x012e, + 0x0005, 0x7206, 0x2001, 0x16f7, 0x0006, 0x2260, 0x0804, 0x17e8, + 0x0126, 0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200, 0x000e, + 0x004e, 0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110, 0x2168, + 0x6a62, 0x6b5e, 0xa005, 0x05b8, 0x6808, 0xa005, 0x0904, 0x177c, + 0x7000, 0xa005, 0x1108, 0x0430, 0x700c, 0x7110, 0xa106, 0x1904, + 0x1784, 0x7004, 0xa406, 0x11f0, 0x2001, 0x0005, 0x2004, 0xd08c, + 0x0130, 0x0046, 0x080c, 0x1942, 0x004e, 0x2460, 0x0c28, 0x2001, + 0x0207, 0x2004, 0xd09c, 0x1d80, 0x7804, 0xa084, 0x6000, 0x0120, + 0xa086, 0x6000, 0x0108, 0x0c40, 0x7803, 0x0004, 0x7003, 0x0000, + 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x15f0, 0x2009, 0x0048, + 0x080c, 0x7518, 0x04c8, 0x6808, 0xa005, 0x0570, 0x7000, 0xa005, + 0x0558, 0x700c, 0x7110, 0xa106, 0x1118, 0x7004, 0xa406, 0x1520, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x0130, 0x0046, 0x080c, 0x1942, + 0x004e, 0x2460, 0x0c40, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1d80, + 0x2001, 0x0005, 0x2004, 0xd08c, 0x1d80, 0x7804, 0xa084, 0x6000, + 0x0118, 0xa086, 0x6000, 0x1d20, 0x7818, 0x6812, 0x781c, 0x6816, + 0x7803, 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x1120, + 0x2009, 0x0048, 0x080c, 0x7518, 0x00ce, 0x00de, 0x012e, 0x0005, + 0x00f6, 0x00e6, 0x0026, 0x0036, 0x0046, 0x080c, 0x1c26, 0x0026, + 0x2071, 0x9519, 0x7000, 0xa086, 0x0000, 0x0580, 0x7004, 0xac06, + 0x11f8, 0x2079, 0x0030, 0x7000, 0xa086, 0x0003, 0x01c8, 0x7804, + 0xd0fc, 0x1198, 0x2001, 0x0207, 0x2004, 0xd09c, 0x1dc0, 0x7803, + 0x0004, 0x7804, 0xd0ac, 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, + 0x7003, 0x0003, 0x7007, 0x0000, 0x0018, 0x080c, 0x1942, 0x08d0, + 0x0156, 0x20a9, 0x0009, 0x2009, 0x9520, 0x2104, 0xac06, 0x1108, + 0x200a, 0xa188, 0x0003, 0x1f04, 0x17bd, 0x015e, 0x002e, 0x2001, + 0x015d, 0x201c, 0x831a, 0x2302, 0x2001, 0x0138, 0x2202, 0x004e, + 0x003e, 0x002e, 0x00ee, 0x00fe, 0x0005, 0x700c, 0x7110, 0xa106, + 0x0904, 0x182c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, + 0x2124, 0x8108, 0xa182, 0x953b, 0x0210, 0x2009, 0x9520, 0x7112, + 0x8cff, 0x05a0, 0x6010, 0x2068, 0x2d58, 0x6828, 0xa406, 0x1598, + 0x682c, 0xa306, 0x1580, 0x684c, 0xd0f4, 0x1540, 0x6850, 0xd0f4, + 0x1130, 0x7803, 0x0004, 0x6810, 0x781a, 0x6814, 0x781e, 0x6824, + 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, + 0x6834, 0xa08c, 0x00ff, 0xa186, 0x0024, 0x0118, 0xa186, 0x002c, + 0x1120, 0x2009, 0x0011, 0x00d9, 0x0038, 0x2009, 0x0011, 0x00b9, + 0x0118, 0x2009, 0x0001, 0x0099, 0x2d58, 0x0005, 0x7803, 0x0004, + 0x080c, 0x1be2, 0x0cd0, 0x601c, 0xa086, 0x0008, 0x1108, 0x0858, + 0x080c, 0x1fa7, 0x1d98, 0x0838, 0x7003, 0x0000, 0x0005, 0x8aff, + 0x0904, 0x191c, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11b8, 0xd0f4, + 0x1538, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x18b6, 0x1867, + 0x1867, 0x18b6, 0x18b9, 0x18ae, 0x18b6, 0x1867, 0x18b6, 0x1878, + 0x1878, 0x18b6, 0x18b9, 0x18b6, 0x18a6, 0x1878, 0x7803, 0x0004, + 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6, 0xd99c, + 0x0904, 0x1909, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x0804, 0x1909, + 0xc0f4, 0x6852, 0x6b6c, 0x6a70, 0x00d6, 0x0804, 0x1910, 0x2d10, + 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, 0xa096, 0x0024, + 0x0904, 0x18e9, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0804, 0x1909, + 0x2d10, 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, 0xa096, + 0x002c, 0x0904, 0x18c6, 0x7b0c, 0xd3bc, 0x01c0, 0x7004, 0x00e6, + 0x2070, 0x701c, 0x00ee, 0xa086, 0x0008, 0x1180, 0x7b08, 0xa39c, + 0x0fff, 0x2d20, 0x7a1c, 0x82ff, 0x1120, 0x7818, 0xa302, 0x0208, + 0x7b18, 0xa016, 0x7a1e, 0x7b1a, 0x2468, 0x0010, 0x6b10, 0x6a14, + 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0804, 0x1909, 0x00de, 0x00d6, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1140, 0x00de, 0x080c, + 0x1f1b, 0x1904, 0x182f, 0xa00e, 0x0804, 0x191c, 0x00de, 0x080c, + 0x13fe, 0x2d10, 0x00de, 0x00d6, 0x6834, 0x2268, 0xa084, 0x00ff, + 0xa096, 0x0024, 0x0530, 0xa096, 0x002c, 0x1d80, 0x6b10, 0xa3a6, + 0xffff, 0x1130, 0x2d10, 0x00de, 0x00d6, 0x080c, 0x59f4, 0x2268, + 0x2d10, 0x00de, 0x00d6, 0x7314, 0x685c, 0xa086, 0x0001, 0x1120, + 0x6868, 0xa005, 0x0108, 0x2018, 0x2268, 0x2011, 0x0000, 0x6d00, + 0x6c04, 0x6f08, 0x6e0c, 0x780f, 0x00f0, 0xe000, 0xe000, 0xe000, + 0x0400, 0x6b08, 0xa3a6, 0xffff, 0x1130, 0x2d10, 0x00de, 0x00d6, + 0x080c, 0x59f4, 0x2268, 0x2d10, 0x00de, 0x00d6, 0x7314, 0x685c, + 0xa086, 0x0001, 0x1120, 0x6868, 0xa005, 0x0108, 0x2018, 0x2268, + 0x2011, 0x0000, 0x6d00, 0x6c04, 0x780f, 0x00f0, 0xe000, 0xe000, + 0xe000, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, + 0x7000, 0x8000, 0x7002, 0x00de, 0x6828, 0xa300, 0x682a, 0x682c, + 0xa201, 0x682e, 0x080c, 0x1f1b, 0x0005, 0x080c, 0x13fe, 0x7803, + 0x0004, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x7003, 0x0000, + 0x080c, 0x1c02, 0x080c, 0x82ee, 0x0170, 0x6808, 0x8001, 0x680a, + 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x80f6, 0x0804, 0x1b4b, + 0x080c, 0x13fe, 0x0126, 0x2091, 0x2200, 0x0006, 0x0016, 0x2b68, + 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x1978, + 0xa184, 0x0003, 0xa086, 0x0003, 0x0d58, 0x7000, 0x0002, 0x195f, + 0x1961, 0x1aa6, 0x1b20, 0x1b3a, 0x195f, 0x195f, 0x195f, 0x080c, + 0x13fe, 0x8001, 0x7002, 0xa184, 0x0880, 0x1904, 0x19a8, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0024, 0x0130, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x1518, 0x6864, 0x8000, 0x6866, 0xd19c, 0x0140, + 0x7004, 0x2060, 0x2009, 0x0102, 0x080c, 0x7518, 0x0804, 0x1a64, + 0x8aff, 0x0130, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, + 0x7004, 0x2060, 0x2009, 0x0106, 0x080c, 0x7518, 0x7007, 0x0000, + 0x7803, 0x0009, 0x7003, 0x0003, 0x0804, 0x1b4b, 0xd19c, 0x1904, + 0x1a49, 0x8aff, 0x0904, 0x1a49, 0x2009, 0x0001, 0x080c, 0x182f, + 0x0904, 0x1b4b, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, + 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1a18, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0024, 0x0130, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x1138, 0xd19c, 0x0128, 0x6864, 0x8000, 0x6866, + 0x0804, 0x1978, 0x0026, 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, + 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, + 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, + 0x0070, 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, 0x0140, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x002c, 0x0110, 0x080c, 0x1b4f, 0x6b28, + 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, 0xa213, 0x6b2a, + 0x6a2e, 0x003e, 0x002e, 0x6e1e, 0x6f22, 0x080c, 0x1f31, 0x2a00, + 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, + 0x6808, 0x8001, 0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004, + 0x2060, 0x2009, 0x0048, 0x080c, 0x7518, 0x7000, 0xa086, 0x0004, + 0x0904, 0x1b4b, 0x7003, 0x0000, 0x080c, 0x17d5, 0x0804, 0x1b4b, + 0x0056, 0x7d0c, 0xd5bc, 0x1110, 0x080c, 0x9171, 0x005e, 0x080c, + 0x1c02, 0x7004, 0x7007, 0x0000, 0x2060, 0x601c, 0xa086, 0x0009, + 0x1198, 0x790c, 0x0016, 0x2009, 0x0106, 0x080c, 0x7518, 0x001e, + 0xd0ec, 0x1118, 0x2009, 0x0009, 0x0010, 0x2009, 0x0019, 0x7902, + 0x7003, 0x0003, 0x0804, 0x1b4b, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, + 0x1b4b, 0x7818, 0x6812, 0x7a1c, 0x6a16, 0xd19c, 0x0118, 0xa205, + 0x1904, 0x19a8, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x1180, + 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x1130, 0x7004, 0x2060, + 0x2009, 0x0048, 0x080c, 0x7518, 0x080c, 0x17d5, 0x0804, 0x1b4b, + 0x7818, 0x6812, 0x781c, 0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, + 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104, 0x8004, + 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x080c, 0x1c40, 0x7803, + 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc, 0x0de8, + 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x00f0, 0x7004, 0x7007, + 0x0000, 0x2060, 0x2009, 0x0048, 0x080c, 0x7518, 0x080c, 0x1c62, + 0x0958, 0x7908, 0xd1ec, 0x1118, 0x2009, 0x0009, 0x0010, 0x2009, + 0x0019, 0x7902, 0x7003, 0x0003, 0x0804, 0x1b4b, 0x8001, 0x7002, + 0xd194, 0x0178, 0x7804, 0xd0fc, 0x1904, 0x194a, 0xd09c, 0x11a8, + 0x8aff, 0x0904, 0x1b4b, 0x2009, 0x0001, 0x080c, 0x182f, 0x0804, + 0x1b4b, 0xa184, 0x0888, 0x1148, 0x8aff, 0x0904, 0x1b4b, 0x2009, + 0x0001, 0x080c, 0x182f, 0x0804, 0x1b4b, 0x7803, 0x0004, 0x7003, + 0x0000, 0xd1bc, 0x1904, 0x1b0d, 0x0026, 0x0036, 0x7c20, 0x7d24, + 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, 0x0201, + 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, 0x0009, + 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, 0x1b4f, 0x001e, 0x6b28, + 0x6a2c, 0x080c, 0x1f31, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, + 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, + 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, 0x19e9, 0x2a00, 0x6826, + 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001, 0x680a, 0x6b2a, + 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1a64, 0x0056, 0x7d0c, 0x080c, + 0x9171, 0x005e, 0x080c, 0x1c02, 0x682b, 0xffff, 0x682f, 0xffff, + 0x6808, 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0458, + 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0180, 0x6808, + 0x8001, 0x680a, 0x1160, 0x7004, 0x2060, 0x2009, 0x0048, 0x601c, + 0xa086, 0x0009, 0x1110, 0x080c, 0x13fe, 0x080c, 0x7518, 0x080c, + 0x17d5, 0x0088, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, + 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28, + 0x6b2c, 0x080c, 0x17e8, 0x001e, 0x000e, 0x012e, 0x0005, 0x700c, + 0x7110, 0xa106, 0x0904, 0x1bd6, 0x7004, 0x0016, 0x210c, 0xa106, + 0x001e, 0x0904, 0x1bd6, 0x00d6, 0x00c6, 0x216c, 0x2d00, 0xa005, + 0x0904, 0x1bd4, 0x6810, 0x2068, 0x6834, 0xa084, 0x00ff, 0xa086, + 0x0024, 0x0904, 0x1bd4, 0x6834, 0xa084, 0x00ff, 0xa086, 0x002c, + 0x0904, 0x1bd4, 0x6850, 0xd0fc, 0x0558, 0x8108, 0x2104, 0x6b2c, + 0xa306, 0x1904, 0x1bd4, 0x8108, 0x2104, 0x6a28, 0xa206, 0x1904, + 0x1bd4, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870, + 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034, + 0xd09c, 0x0150, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, 0x783a, + 0x680c, 0x783e, 0x00de, 0x0490, 0xa006, 0x783a, 0x783e, 0x0470, + 0x8108, 0x2104, 0xa005, 0x1580, 0x8108, 0x2104, 0xa005, 0x1560, + 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2005, 0x6918, 0xa160, 0x6834, + 0xd09c, 0x1170, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, + 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0070, + 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, + 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x6810, 0x781a, + 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce, 0x00de, 0x0005, 0x2011, + 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, 0x1118, 0x8109, 0x1dd8, + 0x0005, 0x0005, 0x0ca1, 0x01e0, 0x7908, 0xd1ec, 0x1160, 0x080c, + 0x1c62, 0x0148, 0x7803, 0x0009, 0x7904, 0xd1fc, 0x0de8, 0x7803, + 0x0006, 0x0c29, 0x0168, 0x780c, 0xd0a4, 0x1150, 0x7007, 0x0000, + 0x080c, 0x1c62, 0x0130, 0x7803, 0x0019, 0x7003, 0x0003, 0x0008, + 0x0009, 0x0005, 0x00c6, 0x0411, 0x20e1, 0x9028, 0x700c, 0x7110, + 0xa106, 0x0190, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, + 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0x953b, 0x0210, + 0x2009, 0x9520, 0x7112, 0x0c50, 0x2001, 0x015d, 0x200c, 0x810a, + 0x2102, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x2001, 0x0138, + 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, + 0xd3dc, 0x1168, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048, 0x1138, + 0x2001, 0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x0005, + 0x3c00, 0x0006, 0x00e6, 0x2071, 0x0200, 0x7808, 0xa084, 0xf000, + 0xa10d, 0x08e1, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, 0x7028, + 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, 0x7037, + 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x00ee, 0x000e, + 0x20e0, 0x0005, 0x3c00, 0x0006, 0x7908, 0xa18c, 0x0fff, 0xa182, + 0x0009, 0x0218, 0xa085, 0x0001, 0x0088, 0x2001, 0x020a, 0x81ff, + 0x0130, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, + 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x000e, 0x20e0, + 0x0005, 0x00e6, 0x2071, 0x953b, 0x7003, 0x0000, 0x00ee, 0x0005, + 0x00d6, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904, 0x1d0d, + 0x6934, 0xa184, 0x0007, 0x0002, 0x1c9c, 0x1cf8, 0x1c9c, 0x1c9e, + 0x1c9c, 0x1cdf, 0x1cbe, 0x1cad, 0x080c, 0x13fe, 0x2100, 0xa084, + 0x00ff, 0xa086, 0x0013, 0x0904, 0x1cf8, 0x2100, 0xa084, 0x00ff, + 0xa086, 0x001b, 0x0904, 0x1cf8, 0x0c78, 0x684c, 0xd0b4, 0x0904, + 0x1e15, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, + 0x680a, 0x6880, 0x680e, 0x6958, 0x0804, 0x1d00, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x19c0, 0x684c, 0xd0b4, 0x0904, 0x1e15, + 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, + 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, + 0x000f, 0xa080, 0x1f59, 0x2005, 0x6832, 0x6958, 0x0450, 0xa18c, + 0x00ff, 0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4, 0x0904, 0x1e15, + 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, + 0x1f59, 0x2005, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0088, + 0x684c, 0xd0b4, 0x0904, 0x191d, 0x6958, 0xa006, 0x682e, 0x682a, + 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, + 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de, 0x0005, 0x00f6, + 0x2079, 0x0020, 0x7804, 0xd0fc, 0x190c, 0x1e3b, 0x00e6, 0x00d6, + 0x2071, 0x953b, 0x7000, 0xa005, 0x1904, 0x1d81, 0x00c6, 0x7206, + 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, + 0x00d6, 0x2068, 0x686c, 0x7812, 0x6890, 0x00f6, 0x20e1, 0x9040, + 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, + 0x00de, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, + 0x6034, 0xa0cc, 0x000f, 0x6908, 0xa184, 0x0007, 0x0128, 0x0016, + 0x2009, 0x0008, 0xa102, 0x001e, 0xa108, 0x791a, 0x7116, 0x701e, + 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, + 0x7004, 0x692c, 0x6814, 0xa106, 0x1120, 0x6928, 0x6810, 0xa106, + 0x0158, 0x0036, 0x0046, 0x6b14, 0x6c10, 0x080c, 0x1fa7, 0x004e, + 0x003e, 0x0110, 0x00ce, 0x00a8, 0x8aff, 0x1120, 0x00ce, 0xa085, + 0x0001, 0x0078, 0x0126, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, + 0x0001, 0x0059, 0x0118, 0x2009, 0x0001, 0x0039, 0x012e, 0x00ce, + 0xa006, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0076, 0x0066, 0x0056, + 0x0046, 0x0036, 0x0026, 0x8aff, 0x0904, 0x1e0e, 0x700c, 0x7214, + 0xa23a, 0x7010, 0x7218, 0xa203, 0x0a04, 0x1e0d, 0xa705, 0x0904, + 0x1e0d, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11a8, 0x00d6, 0x2805, + 0xac68, 0x2900, 0x0002, 0x1ddc, 0x1dc1, 0x1dc1, 0x1ddc, 0x1ddc, + 0x1dd5, 0x1ddc, 0x1dc1, 0x1ddc, 0x1dc6, 0x1dc6, 0x1ddc, 0x1ddc, + 0x1ddc, 0x1dcd, 0x1dc6, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, + 0x6c20, 0xd99c, 0x05c8, 0x00d6, 0x2805, 0xac68, 0x6f08, 0x6e0c, + 0x0490, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x0468, 0x6b10, 0x6a14, + 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0430, 0x00de, 0x00d6, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x001e, 0x1138, 0x00de, 0x080c, 0x1f1b, + 0x1904, 0x1d8b, 0xa00e, 0x0490, 0x2d10, 0x00de, 0x00d6, 0x6834, + 0xa084, 0x00ff, 0xa086, 0x0013, 0x2268, 0x09d8, 0x2d10, 0x00de, + 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001b, 0x2268, 0x09b0, + 0x00de, 0x080c, 0x13fe, 0x00de, 0x7b22, 0x7a26, 0x7d32, 0x7c36, + 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, + 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, + 0xa201, 0x7012, 0x080c, 0x1f1b, 0x0008, 0xa006, 0x002e, 0x003e, + 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, 0x13fe, 0x2001, + 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, + 0x0000, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0118, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x80f6, 0x20e1, + 0x9040, 0x080c, 0x7366, 0x2011, 0x0000, 0x080c, 0x7199, 0x080c, + 0x651c, 0x0804, 0x1ef0, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071, 0x953b, + 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, + 0x1930, 0x7000, 0x0002, 0x1ef0, 0x1e57, 0x1ec3, 0x1eee, 0x8001, + 0x7002, 0xd19c, 0x1170, 0x8aff, 0x0540, 0x2009, 0x0001, 0x080c, + 0x1d85, 0x0904, 0x1ef0, 0x2009, 0x0001, 0x080c, 0x1d85, 0x0804, + 0x1ef0, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc, 0x6852, + 0x8aff, 0x1148, 0x684c, 0xc0f5, 0x684e, 0x0028, 0x080c, 0x1f31, + 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, + 0x6832, 0x7003, 0x0000, 0x0804, 0x1ef0, 0x711c, 0x81ff, 0x0190, + 0x7918, 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, + 0x7002, 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, + 0x0804, 0x1ef0, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, + 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, + 0x7820, 0xd0bc, 0x1de8, 0x79c8, 0x000e, 0xa102, 0x001e, 0x0006, + 0x0016, 0x79c4, 0x000e, 0xa102, 0x78c6, 0x000e, 0x78ca, 0xa284, + 0x0004, 0xa085, 0x0012, 0x7816, 0x002e, 0x00fe, 0x7803, 0x0008, + 0x7003, 0x0000, 0x0468, 0x8001, 0x7002, 0xd194, 0x0168, 0x7804, + 0xd0fc, 0x1904, 0x1e4b, 0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, + 0x0001, 0x080c, 0x1d85, 0x00e0, 0x0026, 0x0036, 0x6b28, 0x6a2c, + 0x080c, 0x1f31, 0x00d6, 0x2805, 0xac68, 0x6034, 0xd09c, 0x1128, + 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, 0x6810, 0xa31a, 0x6814, + 0xa213, 0x00de, 0x0804, 0x1e76, 0x0804, 0x1e76, 0x080c, 0x13fe, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, + 0x00f6, 0x00e6, 0x2071, 0x953b, 0x7000, 0xa086, 0x0000, 0x01c0, + 0x2079, 0x0020, 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0dd8, 0x080c, + 0x1e3b, 0x7000, 0xa086, 0x0000, 0x1da8, 0x7803, 0x0004, 0x7804, + 0xd0ac, 0x1de8, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, + 0x00ee, 0x00fe, 0x0005, 0x8840, 0x2805, 0xa005, 0x1170, 0x6004, + 0xa005, 0x0168, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, + 0x1f59, 0x2045, 0x88ff, 0x090c, 0x13fe, 0x8a51, 0x0005, 0x2050, + 0x0005, 0x8a50, 0x8841, 0x2805, 0xa005, 0x1190, 0x2c00, 0xad06, + 0x0120, 0x6000, 0xa005, 0x1108, 0x2d00, 0x2060, 0x681a, 0x6034, + 0xa084, 0x000f, 0xa080, 0x1f69, 0x2045, 0x88ff, 0x090c, 0x13fe, + 0x0005, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, + 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, + 0x0000, 0x0000, 0x1f4e, 0x1f4a, 0x1f4e, 0x1f4e, 0x1f58, 0x0000, + 0x1f4e, 0x0000, 0x1f55, 0x1f52, 0x1f55, 0x1f55, 0x0000, 0x1f58, + 0x1f55, 0x0000, 0x1f50, 0x1f50, 0x0000, 0x1f50, 0x1f58, 0x0000, + 0x1f50, 0x0000, 0x1f56, 0x1f56, 0x0000, 0x1f56, 0x0000, 0x1f58, + 0x1f56, 0x0136, 0x0146, 0x0156, 0x2099, 0x9359, 0x20a1, 0x0018, + 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126, 0x2091, 0x8000, + 0x7803, 0x0041, 0x7007, 0x0005, 0x7000, 0xc094, 0x7002, 0x700b, + 0x9354, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005, 0x2099, 0x0014, + 0x7803, 0x0040, 0x2001, 0x9359, 0x2004, 0x2010, 0x080c, 0x59a7, + 0x080c, 0x5949, 0x7007, 0x0000, 0x080c, 0x14ec, 0x0005, 0x00a6, + 0x0096, 0x0086, 0x6858, 0xa055, 0x0904, 0x2036, 0x2d60, 0x6034, + 0xa0cc, 0x000f, 0xa9c0, 0x1f59, 0xa986, 0x0007, 0x0130, 0xa986, + 0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422, 0x6060, + 0xa31a, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2036, 0x6004, + 0xa065, 0x0904, 0x2036, 0x0c18, 0x2805, 0xa005, 0x01a8, 0xac68, + 0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020, 0x6810, + 0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150, 0x8a51, + 0x0904, 0x2036, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904, 0x2036, + 0x0830, 0x8a51, 0x0904, 0x2036, 0x8840, 0x2805, 0xa005, 0x1158, + 0x6004, 0xa065, 0x0904, 0x2036, 0x6034, 0xa0cc, 0x000f, 0xa9c0, + 0x1f59, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0458, + 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68, 0x6c6e, + 0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x0a0c, 0x13fe, 0x6800, 0xa420, 0x6804, 0xa319, + 0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x0a0c, + 0x13fe, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, + 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, + 0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e, 0x009e, + 0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, 0xa084, + 0x0007, 0x0002, 0x204a, 0x204b, 0x204e, 0x2051, 0x2056, 0x2059, + 0x205e, 0x2063, 0x0005, 0x080c, 0x1e3b, 0x0005, 0x080c, 0x1942, + 0x0005, 0x080c, 0x1942, 0x080c, 0x1e3b, 0x0005, 0x080c, 0x159c, + 0x0005, 0x080c, 0x1e3b, 0x080c, 0x159c, 0x0005, 0x080c, 0x1942, + 0x080c, 0x159c, 0x0005, 0x080c, 0x1942, 0x080c, 0x1e3b, 0x080c, + 0x159c, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, + 0x9780, 0x2069, 0x9200, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004, + 0x080c, 0x23e6, 0x781b, 0x0002, 0x783b, 0x001f, 0x20e1, 0x8700, + 0x012e, 0x0005, 0x0126, 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, + 0x210b, 0xa084, 0x0007, 0x0002, 0x20a6, 0x2094, 0x2097, 0x209a, + 0x209f, 0x20a1, 0x20a3, 0x20a5, 0x080c, 0x5338, 0x0078, 0x080c, + 0x536c, 0x0060, 0x080c, 0x5338, 0x080c, 0x536c, 0x0038, 0x0041, + 0x0028, 0x0031, 0x0018, 0x0021, 0x0008, 0x0011, 0x012e, 0x0005, + 0x0006, 0x0016, 0x0026, 0x7930, 0xa184, 0x0003, 0x0118, 0x20e1, + 0x9040, 0x00b8, 0xa184, 0x0030, 0x0150, 0x6a00, 0xa286, 0x0003, + 0x1108, 0x0010, 0x080c, 0x4105, 0x20e1, 0x9010, 0x0050, 0xa184, + 0x00c0, 0x0110, 0x080c, 0x13fe, 0xa184, 0x0300, 0x0110, 0x20e1, + 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005, 0x0016, 0x00e6, + 0x00f6, 0x2071, 0x9200, 0x7128, 0x2001, 0x94ca, 0x2102, 0x2001, + 0x94d2, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009, 0x0008, 0x0400, + 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0xa182, 0x02c1, + 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, 0x1218, 0x2009, + 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, 0x0004, 0x0040, + 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, 0x0002, + 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c, 0x23e6, 0x00fe, + 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x13fe, 0x0126, 0x2091, + 0x2400, 0x2061, 0x0100, 0x2071, 0x9200, 0x6024, 0x6026, 0x080c, + 0x2425, 0x6050, 0xa084, 0xfe7f, 0x6052, 0x2009, 0x00ef, 0x6132, + 0x6136, 0x080c, 0x2435, 0x60e7, 0x0000, 0x61ea, 0x60e3, 0x0008, + 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, + 0x6007, 0x0c9f, 0x600f, 0x03ff, 0x602b, 0x002f, 0x012e, 0x0005, + 0x2001, 0x9230, 0x2003, 0x0000, 0x2001, 0x922f, 0x2003, 0x0001, + 0x0005, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, 0x6124, + 0x0066, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x006e, 0x11c0, + 0x6020, 0xd0bc, 0x01a8, 0xd1bc, 0x0198, 0x783c, 0xa005, 0x0180, + 0x00e6, 0x0006, 0x2070, 0x701c, 0xa086, 0x0009, 0x000e, 0x00ee, + 0x1138, 0x00e6, 0x783c, 0x2070, 0x7008, 0xd0fc, 0x00ee, 0x1130, + 0xa184, 0x1c2c, 0x1118, 0xa184, 0x0007, 0x002a, 0xa195, 0x0004, + 0xa284, 0x0007, 0x0002, 0x2195, 0x217b, 0x217e, 0x2181, 0x2186, + 0x2188, 0x218c, 0x2190, 0x080c, 0x5ee3, 0x00b8, 0x080c, 0x5fbe, + 0x00a0, 0x080c, 0x5fbe, 0x080c, 0x5ee3, 0x0078, 0x0099, 0x0068, + 0x080c, 0x5ee3, 0x0079, 0x0048, 0x080c, 0x5fbe, 0x0059, 0x0028, + 0x080c, 0x5fbe, 0x080c, 0x5ee3, 0x0029, 0x002e, 0x001e, 0x000e, + 0x012e, 0x0005, 0xd19c, 0x1904, 0x238f, 0x080c, 0x4dc5, 0x01a0, + 0x080c, 0x4deb, 0x15c0, 0x6024, 0xa084, 0x1800, 0x1108, 0x0498, + 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, 0x0001, + 0x080c, 0x4d10, 0x0804, 0x238f, 0xd1ac, 0x1528, 0x6024, 0xd0dc, + 0x1130, 0xd0e4, 0x1148, 0xd0d4, 0x1180, 0x0804, 0x238f, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x0068, 0xa085, 0x0001, 0x080c, 0x4e05, + 0x2001, 0x94d8, 0x2003, 0x0002, 0x0020, 0x2001, 0x94d8, 0x2003, + 0x0003, 0x0016, 0x2001, 0x9200, 0x2003, 0x0001, 0x080c, 0x4d10, + 0x001e, 0x0804, 0x238f, 0x6220, 0xd1bc, 0x0568, 0xd2bc, 0x0558, + 0x783c, 0xa005, 0x0540, 0x00e6, 0x2070, 0x7008, 0xd0fc, 0x00ee, + 0x0510, 0x6028, 0xc0bc, 0x602a, 0x0026, 0x0036, 0x6288, 0x638c, + 0x608b, 0xbc91, 0x608f, 0xffff, 0x6043, 0x0001, 0xe000, 0xe000, + 0x6027, 0x0080, 0x6017, 0x0000, 0x6043, 0x0000, 0x628a, 0x638e, + 0x003e, 0x002e, 0x0016, 0x2001, 0x9295, 0x200c, 0xc184, 0x2102, + 0x001e, 0x0804, 0x23b6, 0xd1ac, 0x0904, 0x22d7, 0x080c, 0x4dc5, + 0x1550, 0x6027, 0x0020, 0x0006, 0x0026, 0x0036, 0x2001, 0x94d8, + 0x080c, 0x4de1, 0x11d8, 0x2011, 0x9225, 0x2204, 0xa005, 0x1140, + 0x8000, 0x2012, 0x2011, 0x8036, 0x2019, 0x0001, 0x080c, 0x3698, + 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, 0x2003, 0x0001, + 0x080c, 0x4d10, 0x003e, 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, + 0x000e, 0x080c, 0x4ca5, 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, + 0xf0f0, 0x1138, 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, + 0x0010, 0x74c6, 0xa48c, 0xff00, 0xa196, 0xff00, 0x01e8, 0x7050, + 0xa084, 0x00ff, 0x810f, 0xa116, 0x01b8, 0x7130, 0xd18c, 0x11a0, + 0x2011, 0x9252, 0x2214, 0xd2ec, 0x0118, 0xc18d, 0x7132, 0x0060, + 0x6240, 0xa294, 0x0010, 0x0904, 0x22ad, 0x6248, 0xa294, 0xff00, + 0xa296, 0xff00, 0x1904, 0x22ad, 0x70bc, 0xa005, 0x1138, 0x0036, + 0x73c4, 0x2011, 0x8013, 0x080c, 0x3698, 0x003e, 0x7130, 0xc185, + 0x7132, 0x2011, 0x9252, 0x220c, 0xd1a4, 0x01d0, 0x0016, 0x2009, + 0x0001, 0x2011, 0x0100, 0x080c, 0x585b, 0x2019, 0x000e, 0x080c, + 0x9071, 0xa484, 0x00ff, 0xa080, 0x2719, 0x200d, 0xa18c, 0xff00, + 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, 0x90d7, 0x001e, + 0xd1ac, 0x1128, 0x2019, 0x0004, 0x080c, 0x264b, 0x0070, 0x0156, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, 0x4434, 0x1110, 0x080c, + 0x41e0, 0x8108, 0x1f04, 0x22a4, 0x015e, 0x00ce, 0x004e, 0x2011, + 0x0003, 0x080c, 0x718f, 0x2011, 0x0002, 0x080c, 0x7199, 0x080c, + 0x708d, 0x080c, 0x57a1, 0x0036, 0x2019, 0x0000, 0x080c, 0x7110, + 0x003e, 0x60e3, 0x0000, 0x001e, 0x2001, 0x9200, 0x2014, 0xa296, + 0x0004, 0x1128, 0xd19c, 0x1118, 0x6228, 0xc29d, 0x622a, 0x2003, + 0x0001, 0x2001, 0x9222, 0x2003, 0x0000, 0x6027, 0x0020, 0xd194, + 0x0904, 0x238f, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2340, 0x080c, + 0x57a1, 0x080c, 0x6f1e, 0x6027, 0x0004, 0x00f6, 0x2019, 0x94ee, + 0x2304, 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, + 0x00c6, 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, + 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, + 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, + 0x080c, 0x6389, 0x080c, 0x6462, 0x7810, 0x2070, 0x7037, 0x0103, + 0x2f60, 0x080c, 0x74f2, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, + 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, + 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, + 0x94e5, 0x6028, 0xa09a, 0x0002, 0x1238, 0x8000, 0x602a, 0x00ce, + 0x080c, 0x6f11, 0x0804, 0x238e, 0x2019, 0x94ee, 0x2304, 0xa065, + 0x0120, 0x2009, 0x0027, 0x080c, 0x7518, 0x00ce, 0x0804, 0x238e, + 0xd2bc, 0x0904, 0x238e, 0x080c, 0x57ae, 0x6017, 0x0010, 0x6027, + 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0120, + 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, 0x94e5, + 0x6044, 0xa09a, 0x0002, 0x12e0, 0x8000, 0x6046, 0x603c, 0x00ce, + 0xa005, 0x0560, 0x2009, 0x07d0, 0x080c, 0x57a6, 0xa080, 0x0007, + 0x2004, 0xa086, 0x0006, 0x1118, 0x6017, 0x0012, 0x00f8, 0xa080, + 0x0007, 0x2004, 0xa086, 0x0009, 0x0db8, 0x6017, 0x0016, 0x00b0, + 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, 0x003e, 0x2019, 0x94f4, + 0x2304, 0xa065, 0x0150, 0x2009, 0x004f, 0x601c, 0xa086, 0x0009, + 0x1110, 0x2009, 0x0105, 0x080c, 0x7518, 0x00ce, 0x001e, 0xd19c, + 0x0528, 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, + 0x718f, 0x2011, 0x0002, 0x080c, 0x7199, 0x080c, 0x708d, 0x080c, + 0x57a1, 0x0036, 0x2019, 0x0000, 0x080c, 0x7110, 0x003e, 0x60e3, + 0x0000, 0x080c, 0x918b, 0x080c, 0x91a6, 0x2001, 0x9200, 0x2003, + 0x0004, 0x6027, 0x0008, 0x080c, 0x123f, 0x001e, 0xa18c, 0xffd0, + 0x6126, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6, 0x0126, + 0x2091, 0x8000, 0x2071, 0x9200, 0x71bc, 0x70be, 0xa116, 0x01b8, + 0x81ff, 0x0128, 0x2011, 0x8011, 0x080c, 0x3698, 0x0080, 0x2011, + 0x8012, 0x080c, 0x3698, 0x0036, 0x00c6, 0x080c, 0x2480, 0x2061, + 0x0100, 0x2019, 0x0028, 0x080c, 0x264b, 0x00ce, 0x003e, 0x012e, + 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005, 0x00c6, 0x00f6, + 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, 0x23f9, 0x2205, 0x60f2, + 0x2011, 0x2406, 0x2205, 0x60ee, 0x002e, 0x000e, 0x00fe, 0x00ce, + 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, 0x0348, 0x02c0, + 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8, + 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, 0x2130, 0xa094, + 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, 0x550c, 0x0038, 0xa080, + 0x2719, 0x200d, 0xa18c, 0xff00, 0x810f, 0xa006, 0x0005, 0xa080, + 0x2719, 0x200d, 0xa18c, 0x00ff, 0x0005, 0x00d6, 0x2069, 0x0140, + 0x2001, 0x9214, 0x2003, 0x00ef, 0x20a9, 0x0010, 0xa006, 0x6852, + 0x6856, 0x1f04, 0x2430, 0x00de, 0x0005, 0x0006, 0x00d6, 0x0026, + 0x2069, 0x0140, 0x2001, 0x9214, 0x2102, 0x8114, 0x8214, 0x8214, + 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0xa006, 0x82ff, 0x1128, + 0xa184, 0x000f, 0xa080, 0x91ac, 0x2005, 0x6856, 0x8211, 0x1f04, + 0x2445, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6, 0x2061, 0x9200, + 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032, 0x00ce, 0x0005, + 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069, 0x0140, 0x6980, + 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, 0x8210, 0x22a8, 0x2001, + 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e, 0x1f04, 0x2475, + 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de, 0x015e, 0x0005, + 0x2001, 0x9252, 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, + 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0x90d7, 0x004e, 0x0005, + 0x24b0, 0x24b4, 0x24b8, 0x24be, 0x24c4, 0x24ca, 0x24d0, 0x24d8, + 0x24df, 0x24e4, 0x24e9, 0x24f0, 0x24f7, 0x24fe, 0x2505, 0x250e, + 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, + 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, 0x2517, + 0x0106, 0x0006, 0x0804, 0x2519, 0x0106, 0x0006, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x0804, 0x2519, 0x0106, 0x0006, + 0x080c, 0x2141, 0x0804, 0x2519, 0x0106, 0x0006, 0x080c, 0x203c, + 0x0804, 0x2519, 0x0106, 0x0006, 0x080c, 0x203c, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x203c, 0x0804, 0x2519, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x203c, 0x04d0, 0x0106, + 0x0006, 0x080c, 0x2082, 0x04a8, 0x0106, 0x0006, 0x080c, 0x2082, + 0x0480, 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x2082, 0x0448, + 0x0106, 0x0006, 0x080c, 0x2141, 0x080c, 0x2082, 0x0410, 0x0106, + 0x0006, 0x080c, 0x203c, 0x080c, 0x2082, 0x00d8, 0x0106, 0x0006, + 0x080c, 0x203c, 0x080c, 0x2082, 0x00a0, 0x0106, 0x0006, 0x080c, + 0x2141, 0x080c, 0x203c, 0x080c, 0x2082, 0x0058, 0x0106, 0x0006, + 0x080c, 0x2141, 0x080c, 0x203c, 0x080c, 0x2082, 0x0010, 0xe000, + 0x0cf0, 0x000e, 0x010e, 0x000d, 0x00c6, 0x0026, 0x2041, 0x007e, + 0x70c8, 0xd09c, 0x0110, 0x2041, 0x007f, 0xd094, 0x2001, 0x9214, + 0x203c, 0x15d8, 0x7284, 0x82ff, 0x05c0, 0x0036, 0x7398, 0xa38e, + 0xffff, 0x1110, 0x2019, 0x0001, 0x8314, 0xa2e0, 0x98c0, 0x2c04, + 0xa38c, 0x0001, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, + 0x00ff, 0xa70e, 0x01c8, 0xa08e, 0x00ff, 0x01d0, 0x2009, 0x0000, + 0x080c, 0x240b, 0x080c, 0x4400, 0x1188, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x0006, 0x1120, 0x080c, 0x25b1, 0x0140, 0x0028, 0x080c, + 0x26ad, 0x080c, 0x25d7, 0x0110, 0x8318, 0x08b0, 0x739a, 0x0010, + 0x709b, 0xffff, 0x003e, 0x0804, 0x25ae, 0xa780, 0x2719, 0x203d, + 0xa7bc, 0xff00, 0x873f, 0x7098, 0xa096, 0xffff, 0x0128, 0xa812, + 0x12c8, 0x709b, 0xffff, 0x04b8, 0x2009, 0x0000, 0x70c8, 0xd09c, + 0x0120, 0xd094, 0x0110, 0x2009, 0x007e, 0x2001, 0x94d7, 0x2004, + 0xa005, 0x0120, 0x2009, 0x007e, 0x2041, 0x007f, 0x2100, 0xa802, + 0x20a8, 0x0020, 0x2008, 0x2810, 0xa202, 0x20a8, 0x2700, 0x0156, + 0x0016, 0xa106, 0x0180, 0x080c, 0x4400, 0x11a8, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x1118, 0x00a1, 0x0168, 0x0020, 0x080c, + 0x26ad, 0x04a9, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x258e, + 0x709b, 0xffff, 0x0018, 0x001e, 0x015e, 0x719a, 0x002e, 0x00ce, + 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x080c, 0x749c, + 0x01c8, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x2001, 0x0000, 0x080c, 0x43e3, 0x0126, 0x2091, 0x8000, + 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0004, 0x080c, 0x7518, + 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x0016, + 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x080c, 0x749c, 0x01c8, 0x2d00, + 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, + 0x0002, 0x080c, 0x43e3, 0x0126, 0x2091, 0x8000, 0x7094, 0x8000, + 0x7096, 0x012e, 0x2009, 0x0002, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x0026, 0x2009, + 0x0080, 0x080c, 0x4400, 0x1120, 0x0031, 0x0110, 0x70cf, 0xffff, + 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, + 0x080c, 0x749c, 0x01c8, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, + 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, 0x080c, 0x43e3, 0x0126, + 0x2091, 0x8000, 0x70d0, 0x8000, 0x70d2, 0x012e, 0x2009, 0x0002, + 0x080c, 0x7518, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, + 0x0005, 0x00c6, 0x00d6, 0x2009, 0x007f, 0x080c, 0x4400, 0x1180, + 0x2c68, 0x080c, 0x749c, 0x0160, 0x2d00, 0x601a, 0x6312, 0x601f, + 0x0001, 0x620a, 0x2009, 0x0022, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, 0x0026, + 0x080c, 0x6133, 0x080c, 0x60dc, 0x080c, 0x7a8c, 0x20a9, 0x007f, + 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1120, 0x080c, 0x460d, + 0x080c, 0x41e0, 0x001e, 0x8108, 0x1f04, 0x265a, 0x002e, 0x003e, + 0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, + 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, + 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, + 0x8ee4, 0x008e, 0x001e, 0x2e60, 0x080c, 0x460d, 0x6210, 0x6314, + 0x080c, 0x41e0, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x0006, 0x6018, 0xa080, 0x0028, 0x2004, + 0xa086, 0x0080, 0x0150, 0x2071, 0x9200, 0x7094, 0xa005, 0x0110, + 0x8001, 0x7096, 0x000e, 0x00ee, 0x0005, 0x2071, 0x9200, 0x70d0, + 0xa005, 0x0dc0, 0x8001, 0x70d2, 0x0ca8, 0x6000, 0xc08c, 0x6002, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, + 0x2178, 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0x9252, + 0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, + 0x2009, 0x002d, 0x080c, 0x90d7, 0x004e, 0x20a9, 0x00ff, 0x2011, + 0x0000, 0x0026, 0xa288, 0x936e, 0x210c, 0x81ff, 0x0508, 0x8fff, + 0x0559, 0x2019, 0x0029, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, + 0x080c, 0x606d, 0x00c6, 0x0026, 0x2160, 0x6204, 0xa294, 0x00ff, + 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x002e, 0x00ce, 0x0016, + 0x2c08, 0x080c, 0x8ee4, 0x001e, 0x008e, 0x2160, 0x080c, 0x460d, + 0x002e, 0x8210, 0x1f04, 0x26d1, 0x015e, 0x001e, 0x002e, 0x003e, + 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x2001, + 0x9252, 0x2004, 0xd0c4, 0x0148, 0xd0a4, 0x0138, 0xa006, 0x2220, + 0x8427, 0x2009, 0x0029, 0x080c, 0x90d7, 0x001e, 0x002e, 0x004e, + 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, + 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, + 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, + 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, + 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, + 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, + 0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, + 0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, + 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, + 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, + 0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, + 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, + 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, + 0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, + 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, + 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, + 0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, + 0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, + 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, + 0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, + 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, + 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, + 0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, + 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, + 0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, + 0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, + 0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x2071, 0x9296, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, + 0x703a, 0x703e, 0x7033, 0x92a6, 0x7037, 0x92a6, 0x7007, 0x0001, + 0x2061, 0x92e6, 0x6003, 0x0002, 0x0005, 0x1004, 0x283f, 0x0e04, + 0x283f, 0x2071, 0x9296, 0x2b78, 0x7818, 0xd084, 0x1140, 0x2a60, + 0x7820, 0xa08e, 0x0069, 0x1904, 0x2924, 0x0804, 0x28bd, 0x0005, + 0x2071, 0x9296, 0x7004, 0x0002, 0x2848, 0x2849, 0x2852, 0x2863, + 0x0005, 0x1004, 0x2851, 0x0e04, 0x2851, 0x2b78, 0x7818, 0xd084, + 0x01e8, 0x0005, 0x2b78, 0x2061, 0x92e6, 0x6008, 0xa08e, 0x0100, + 0x0128, 0xa086, 0x0200, 0x0904, 0x291e, 0x0005, 0x7014, 0x2068, + 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068, 0x6834, 0xa086, 0x0103, + 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018, 0x0807, 0x2a60, 0x7820, + 0xa08a, 0x0040, 0x1210, 0x61bc, 0x0042, 0x2100, 0xa08a, 0x003f, + 0x1a04, 0x291b, 0x61bc, 0x0804, 0x28bd, 0x28ff, 0x292a, 0x2932, + 0x2936, 0x293e, 0x2944, 0x2948, 0x2951, 0x2954, 0x295e, 0x2961, + 0x291b, 0x291b, 0x291b, 0x2964, 0x291b, 0x2973, 0x298a, 0x29a1, + 0x2a18, 0x2a1d, 0x2a46, 0x2a97, 0x2aa8, 0x2ac6, 0x2af2, 0x2afc, + 0x2b09, 0x2b1c, 0x2b3c, 0x2b45, 0x2b7b, 0x2b81, 0x291b, 0x2ba4, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2ba8, 0x2bae, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2bb6, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x2bc3, 0x2bc9, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x0002, 0x2bdb, 0x2c2e, + 0x2c88, 0x2c98, 0x291b, 0x2cb2, 0x309c, 0x291b, 0x291b, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x295e, 0x2961, + 0x291b, 0x291b, 0x309e, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, + 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x291b, 0x30a2, 0x31e7, + 0x31fb, 0x3215, 0x3276, 0x32c7, 0x32d2, 0x3309, 0x3318, 0x3327, + 0x3336, 0x335e, 0x33a8, 0x340a, 0x3417, 0x3501, 0x35f6, 0x361f, + 0x3716, 0x3732, 0x373e, 0x3777, 0x381e, 0x3878, 0x38ff, 0x3908, + 0x390b, 0x3920, 0x393b, 0x39ab, 0x3a5b, 0x713c, 0x0000, 0x2021, + 0x4000, 0x080c, 0x3675, 0x0126, 0x2091, 0x8000, 0x0e04, 0x290b, + 0x7818, 0xd084, 0x0110, 0x012e, 0x0cb0, 0x7c22, 0x7926, 0x7a2a, + 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, + 0x5000, 0x012e, 0x0005, 0x2021, 0x4001, 0x0c18, 0x2021, 0x4002, + 0x0c00, 0x2021, 0x4003, 0x08e8, 0x2021, 0x4005, 0x08d0, 0x2021, + 0x4006, 0x08b8, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, + 0x0804, 0x3682, 0x7823, 0x0004, 0x7824, 0x0807, 0xa02e, 0x2520, + 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3685, 0x7924, 0x7828, + 0x2114, 0x200a, 0x0804, 0x28ff, 0x7924, 0x2114, 0x0804, 0x28ff, + 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9, 0x0007, 0x53a3, 0x0804, + 0x28ff, 0x7824, 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0000, + 0x2019, 0x0010, 0x783b, 0x0027, 0x0804, 0x28ff, 0x7d38, 0x7c3c, + 0x0858, 0x7d38, 0x7c3c, 0x08a0, 0x2061, 0x1000, 0xe10c, 0xa006, + 0x2c15, 0xa200, 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, + 0x28ff, 0x0804, 0x2921, 0x2069, 0x9251, 0x7824, 0x7930, 0xa11a, + 0x1a04, 0x2927, 0x8019, 0x0904, 0x2927, 0x684a, 0x6942, 0x782c, + 0x6852, 0x7828, 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x4e5d, + 0x0804, 0x28ff, 0x2069, 0x9251, 0x7824, 0x7934, 0xa11a, 0x1a04, + 0x2927, 0x8019, 0x0904, 0x2927, 0x684e, 0x6946, 0x782c, 0x6862, + 0x7828, 0x6866, 0xa006, 0x686a, 0x686e, 0x080c, 0x47d8, 0x0804, + 0x28ff, 0xa02e, 0x2520, 0x81ff, 0x1904, 0x2924, 0x7924, 0x7b28, + 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0x929d, 0x41a1, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0023, 0x080c, 0x3682, 0x701b, 0x29b9, + 0x0005, 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0120, + 0xa096, 0x0019, 0x1904, 0x2924, 0x810f, 0xa18c, 0x00ff, 0x0904, + 0x2924, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0023, 0x2061, 0x92e6, 0x6224, 0x6328, + 0x642c, 0x6530, 0xa290, 0x0046, 0xa399, 0x0000, 0xa4a1, 0x0000, + 0xa5a9, 0x0000, 0x080c, 0x3682, 0x701b, 0x29e7, 0x0005, 0x6834, + 0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, 0x1904, + 0x2924, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x4337, 0x1128, 0x7007, 0x0003, 0x701b, 0x2a01, 0x0005, 0x080c, + 0x492c, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0x929d, + 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, + 0x0000, 0xad80, 0x000d, 0x2009, 0x0023, 0x012e, 0x0804, 0x3685, + 0x61a4, 0x7824, 0x60a6, 0x0804, 0x28ff, 0x2091, 0x8000, 0x7823, + 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, + 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, + 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, + 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, + 0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, 0x1904, + 0x2924, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1904, + 0x2927, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, 0x0804, + 0x2927, 0x7c28, 0x7d2c, 0x080c, 0x45d4, 0xd28c, 0x1118, 0x080c, + 0x457f, 0x0010, 0x080c, 0x45ad, 0x1518, 0x2061, 0x9900, 0x0126, + 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, 0xa06d, + 0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, 0x012e, + 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, 0xac02, 0x1a04, 0x2924, + 0x0c30, 0x080c, 0x80f6, 0x012e, 0x0904, 0x2924, 0x0804, 0x28ff, + 0xa00e, 0x2001, 0x0005, 0x080c, 0x492c, 0x0126, 0x2091, 0x8000, + 0x080c, 0x852d, 0x080c, 0x4809, 0x012e, 0x0804, 0x28ff, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x44d4, + 0x0904, 0x2924, 0x080c, 0x45e0, 0x0904, 0x2924, 0x0804, 0x28ff, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, 0x080c, + 0x4644, 0x0904, 0x2924, 0x2019, 0x0005, 0x080c, 0x45fb, 0x0904, + 0x2924, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2927, 0x8003, 0x800b, + 0x810b, 0xa108, 0x080c, 0x573d, 0x0804, 0x28ff, 0x0126, 0x2091, + 0x8000, 0x81ff, 0x1508, 0x2029, 0x00ff, 0x644c, 0x2400, 0xa506, + 0x01b0, 0x2508, 0x080c, 0x4434, 0x1190, 0x080c, 0x4644, 0x01a0, + 0x2019, 0x0004, 0x080c, 0x45fb, 0x0178, 0x7824, 0xa08a, 0x1000, + 0x1270, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x573d, 0x8529, + 0x1e28, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, 0x2924, 0x012e, + 0x0804, 0x2927, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x453a, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x080c, + 0x3656, 0x0904, 0x2927, 0x080c, 0x452b, 0x080c, 0x45d4, 0x0804, + 0x28ff, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x45af, 0x0904, 0x2924, 0x080c, 0x4373, 0x080c, 0x4578, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x44d4, 0x0904, 0x2924, 0x62a0, 0x2019, 0x0005, 0x00c6, + 0x080c, 0x460d, 0x2061, 0x0000, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x00ce, + 0x080c, 0x45d4, 0x0804, 0x28ff, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x45d4, 0x2208, 0x0804, 0x28ff, 0x0156, 0x00d6, 0x00e6, + 0x2069, 0x9328, 0x6810, 0x6914, 0xa10a, 0x1210, 0x2009, 0x0000, + 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, + 0x936e, 0x2d04, 0xa075, 0x0130, 0x704c, 0x0071, 0xa210, 0x7080, + 0x0059, 0xa318, 0x8d68, 0x1f04, 0x2b59, 0x2300, 0xa218, 0x00ee, + 0x00de, 0x015e, 0x0804, 0x28ff, 0x00f6, 0x0016, 0xa07d, 0x0140, + 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, + 0x001e, 0x00fe, 0x0005, 0x2069, 0x9328, 0x6910, 0x62a8, 0x0804, + 0x28ff, 0x81ff, 0x1904, 0x2924, 0x614c, 0xa190, 0x2719, 0x2215, + 0xa294, 0x00ff, 0x636c, 0x83ff, 0x0108, 0x6270, 0x67c8, 0xd79c, + 0x0118, 0x2031, 0x0001, 0x0060, 0xd7ac, 0x0118, 0x2031, 0x0003, + 0x0038, 0xd7a4, 0x0118, 0x2031, 0x0002, 0x0010, 0x2031, 0x0000, + 0x7e3a, 0x7f3e, 0x0804, 0x28ff, 0x613c, 0x6240, 0x0804, 0x28ff, + 0x080c, 0x3666, 0x0904, 0x2927, 0x0804, 0x28ff, 0x080c, 0x3666, + 0x0904, 0x2927, 0x6244, 0x6338, 0x0804, 0x28ff, 0x613c, 0x6240, + 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0x9251, 0x831f, 0xa305, + 0x6816, 0x0804, 0x28ff, 0x080c, 0x3666, 0x0904, 0x2927, 0x0804, + 0x28ff, 0x080c, 0x3666, 0x0904, 0x2927, 0x7828, 0xa00d, 0x0904, + 0x2927, 0x782c, 0xa005, 0x0904, 0x2927, 0x6244, 0x6146, 0x6338, + 0x603a, 0x0804, 0x28ff, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2924, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, + 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0x9214, 0x2004, 0xa085, + 0xff00, 0x0078, 0xa182, 0x007f, 0x1698, 0xa188, 0x2719, 0x210d, + 0xa18c, 0x00ff, 0x2001, 0x9214, 0x2004, 0xa116, 0x0548, 0x810f, + 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x749c, 0x000e, + 0x01e0, 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x080c, 0x3641, + 0x01d0, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x701b, 0x2c81, 0x2d00, 0x6012, 0x2009, 0x0032, + 0x080c, 0x7518, 0x012e, 0x00ce, 0x0005, 0x00ce, 0x0804, 0x2924, + 0x00ce, 0x0804, 0x2927, 0x080c, 0x74f2, 0x0cb8, 0x2001, 0x9200, + 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x00c6, 0x2061, 0x0100, + 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, + 0x9214, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, 0x007f, 0x1698, + 0xa188, 0x2719, 0x210d, 0xa18c, 0x00ff, 0x2001, 0x9214, 0x2004, + 0xa116, 0x0548, 0x810f, 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, + 0x080c, 0x749c, 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, 0x601f, + 0x0001, 0x080c, 0x3641, 0x01d0, 0x6837, 0x0000, 0x7007, 0x0003, + 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, 0x2c81, 0x2d00, + 0x6012, 0x2009, 0x0032, 0x080c, 0x7518, 0x012e, 0x00ce, 0x0005, + 0x00ce, 0x0804, 0x2924, 0x00ce, 0x0804, 0x2927, 0x080c, 0x74f2, + 0x0cb8, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, + 0x2061, 0x9566, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0128, + 0x6104, 0x6208, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, 0x2927, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x4dc5, 0x0904, 0x2924, 0x0126, + 0x2091, 0x8000, 0x6244, 0x6064, 0xa202, 0x0248, 0xa085, 0x0001, + 0x080c, 0x2455, 0x080c, 0x3bfd, 0x012e, 0x0804, 0x28ff, 0x012e, + 0x0804, 0x2927, 0x0126, 0x2091, 0x8000, 0x7824, 0xa084, 0x0007, + 0x0002, 0x2cc4, 0x2ccd, 0x2cd4, 0x2cc1, 0x2cc1, 0x2cc1, 0x2cc1, + 0x2cc1, 0x012e, 0x0804, 0x2927, 0x2009, 0x0114, 0x2104, 0xa085, + 0x0800, 0x200a, 0x080c, 0x2e1e, 0x0070, 0x2009, 0x010b, 0x200b, + 0x0010, 0x080c, 0x2e1e, 0x0038, 0x81ff, 0x0128, 0x012e, 0x2021, + 0x400b, 0x0804, 0x2901, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, + 0x00d6, 0x00e6, 0x00f6, 0x2009, 0x0101, 0x210c, 0x0016, 0x2001, + 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001, 0x007a, 0x2034, + 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050, 0x2058, 0x080c, + 0x302f, 0x080c, 0x2f99, 0xa03e, 0x2720, 0x00f6, 0x00e6, 0x00c6, + 0x2d60, 0x2071, 0x953b, 0x2079, 0x0020, 0x2011, 0x0001, 0x080c, + 0x2f45, 0x080c, 0x2f45, 0x00ce, 0x00ee, 0x00fe, 0x080c, 0x2ea6, + 0x080c, 0x2f6d, 0x080c, 0x2eea, 0x080c, 0x2e65, 0x080c, 0x2e96, + 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x01d8, 0x7817, 0x0010, + 0x2079, 0x0140, 0x2001, 0x0109, 0x2004, 0xd0ac, 0x11a8, 0x7804, + 0xd0dc, 0x0dc0, 0x2079, 0x0100, 0x7827, 0x0086, 0x7817, 0x0032, + 0x7824, 0xd0ac, 0x1148, 0xd0bc, 0x0dd8, 0x7827, 0x0080, 0xa026, + 0x7c16, 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, 0x2e06, 0x00fe, + 0x0804, 0x2dd0, 0x00fe, 0x1d04, 0x2d55, 0x2091, 0x6000, 0x8420, + 0xa486, 0x0064, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, + 0x007b, 0x2502, 0x080c, 0x2e06, 0x0088, 0x87ff, 0x0140, 0x2001, + 0x0201, 0x2004, 0xa005, 0x1904, 0x2d10, 0x8739, 0x0038, 0x2001, + 0x9519, 0x2004, 0xa086, 0x0000, 0x1904, 0x2d10, 0x2001, 0x0033, + 0x2003, 0x00f0, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, + 0x2dd0, 0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, + 0x2dd0, 0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, + 0xd0ac, 0x1148, 0x2001, 0x9519, 0x2003, 0x0003, 0x2001, 0x0030, + 0x2003, 0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, + 0xa005, 0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, + 0x681a, 0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, + 0x00c6, 0x20a9, 0x0008, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, + 0x0203, 0x2004, 0x1f04, 0x2da5, 0x00ce, 0x0040, 0x6827, 0x0001, + 0x2001, 0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, + 0x2079, 0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, + 0x2004, 0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, + 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x2cfd, + 0x2061, 0x0100, 0x6027, 0x0002, 0x20e1, 0x9028, 0x6050, 0xa084, + 0xf7ef, 0x6052, 0x602f, 0x0000, 0x001e, 0x61e2, 0x001e, 0x6106, + 0x7824, 0xa084, 0x0003, 0xa086, 0x0002, 0x0148, 0x602c, 0xc0ac, + 0x602e, 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, + 0x2a10, 0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, + 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, + 0x28ff, 0x012e, 0x2021, 0x400c, 0x0804, 0x2901, 0x2001, 0x0105, + 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001, 0x0020, + 0x2003, 0x0004, 0x2001, 0x9519, 0x2003, 0x0000, 0x2001, 0x953b, + 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6, 0x2079, + 0x0100, 0x7850, 0xa084, 0x0990, 0x7852, 0x782c, 0xa085, 0x0020, + 0x782e, 0x20a9, 0x0008, 0x1d04, 0x2e2b, 0x2091, 0x6000, 0x1f04, + 0x2e2b, 0x7850, 0xa085, 0x0400, 0x7852, 0x784b, 0xf7f7, 0x7843, + 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e, 0xe000, 0x1f04, 0x2e3d, + 0x7850, 0xa085, 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854, 0xe000, + 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850, + 0xa085, 0x0400, 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4, 0xe000, + 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140, 0x2003, 0x0100, 0x7843, + 0x0000, 0x2003, 0x0000, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, + 0x00f6, 0x00e6, 0x2071, 0x9519, 0x2079, 0x0030, 0x2001, 0x0201, + 0x2004, 0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, + 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, + 0x00fe, 0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, + 0x260a, 0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, + 0x0108, 0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, + 0x0200, 0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, + 0x2001, 0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, + 0x0100, 0x2009, 0x9214, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166, + 0x719e, 0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078, + 0xa080, 0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa, + 0xa006, 0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af, + 0x95d5, 0x7027, 0x0080, 0x7017, 0x0032, 0x080c, 0x2f6d, 0x7024, + 0xd0ac, 0x1120, 0xd0bc, 0x0dc8, 0x7027, 0x0080, 0x00f6, 0x00e6, + 0x2071, 0x9519, 0x2079, 0x0030, 0x2011, 0x0011, 0x080c, 0x2f45, + 0x2011, 0x0001, 0x080c, 0x2f45, 0x00ee, 0x00fe, 0x7017, 0x0000, + 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x9519, 0x2079, 0x0030, + 0x7904, 0xd1fc, 0x0904, 0x2f42, 0x7803, 0x0002, 0xa026, 0xd19c, + 0x1904, 0x2f3e, 0x7000, 0x0002, 0x2f42, 0x2f00, 0x2f24, 0x2f3e, + 0xd1bc, 0x1150, 0xd1dc, 0x1150, 0x8001, 0x7002, 0x2011, 0x0001, + 0x04e1, 0x05c0, 0x04d1, 0x04b0, 0x780f, 0x0000, 0x7820, 0x7924, + 0x7803, 0x0004, 0x7822, 0x7926, 0x2001, 0x0201, 0x200c, 0x81ff, + 0x0de8, 0x080c, 0x2e82, 0x2009, 0x0001, 0x7808, 0xd0ec, 0x0110, + 0x2009, 0x0011, 0x7902, 0x00f0, 0x8001, 0x7002, 0xa184, 0x0880, + 0x1138, 0x7804, 0xd0fc, 0x1940, 0x2011, 0x0001, 0x00b1, 0x0090, + 0x6030, 0xa092, 0x0004, 0xa086, 0x0009, 0x1120, 0x6000, 0x601a, + 0x2011, 0x0025, 0x6232, 0xd1dc, 0x1988, 0x0870, 0x7803, 0x0004, + 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x6024, 0xa005, 0x0520, + 0x8001, 0x6026, 0x6018, 0x6130, 0xa140, 0x2804, 0x7832, 0x8840, + 0x2804, 0x7836, 0x8840, 0x2804, 0x7822, 0x8840, 0x2804, 0x7826, + 0x8840, 0x7a02, 0x7000, 0x8000, 0x7002, 0x6018, 0xa802, 0xa08a, + 0x0029, 0x1138, 0x6018, 0xa080, 0x0001, 0x2004, 0x601a, 0x2001, + 0x000d, 0x6032, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, + 0x2071, 0x953b, 0x2079, 0x0020, 0x7904, 0xd1fc, 0x01f0, 0x7803, + 0x0002, 0x2d60, 0xa026, 0x7000, 0x0002, 0x2f95, 0x2f80, 0x2f8c, + 0x8001, 0x7002, 0xd19c, 0x1188, 0x2011, 0x0001, 0x080c, 0x2f45, + 0x0160, 0x080c, 0x2f45, 0x0048, 0x8001, 0x7002, 0x7804, 0xd0fc, + 0x1d30, 0x2011, 0x0001, 0x080c, 0x2f45, 0x00ce, 0x00ee, 0x00fe, + 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x601b, 0x0004, + 0x2061, 0x0100, 0x60cf, 0x0400, 0x6004, 0xc0ac, 0xa085, 0x0200, + 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038, 0x2001, + 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3089, 0x6833, + 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, 0x2138, + 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, 0x000d, + 0x04a1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3089, 0x6833, + 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001, 0x0076, + 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061, 0x0020, + 0x2079, 0x0100, 0x6013, 0x0400, 0x20e1, 0x9040, 0x2001, 0x0072, + 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a, 0x0006, 0x2001, 0x0073, + 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e, 0x78ca, 0xa006, 0x603a, + 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0010, + 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026, 0x7432, 0x7336, 0xa006, + 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7122, 0x7003, + 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003, 0x0002, 0x7003, 0x0040, + 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180, 0x00c6, 0x00d6, 0x2d60, + 0x00c6, 0x080c, 0x3641, 0x00ce, 0x6018, 0x2070, 0x2d00, 0x7006, + 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, + 0x2001, 0x0075, 0x2004, 0xa005, 0x0508, 0x2038, 0x2001, 0x0078, + 0x2024, 0x2001, 0x0079, 0x201c, 0x080c, 0x3089, 0x2d60, 0x6833, + 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, 0x2138, + 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, 0x000d, + 0x080c, 0x2ffd, 0x1d88, 0x2d00, 0x681a, 0x00d8, 0x0491, 0x2d60, + 0x6033, 0x000d, 0x2070, 0x6027, 0x0001, 0x2c00, 0x601a, 0x2001, + 0x0078, 0x2004, 0x2072, 0x2001, 0x0079, 0x2004, 0x7006, 0x2001, + 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x2001, 0x0073, 0x2004, + 0x700e, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac, 0x1178, + 0x2001, 0x0101, 0x200c, 0xc1ed, 0x2102, 0x6027, 0x0000, 0x2001, + 0x9519, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003, 0x0009, 0x00ee, + 0x0005, 0x080c, 0x147c, 0x0178, 0xa006, 0x6802, 0x7010, 0xa005, + 0x1120, 0x2d00, 0x7012, 0x7016, 0x0020, 0x7014, 0x6802, 0x2d00, + 0x7016, 0xad80, 0x000d, 0x0005, 0x0804, 0x28ff, 0x7d38, 0x7c3c, + 0x0804, 0x29a3, 0x080c, 0x3641, 0x0904, 0x2924, 0x080c, 0x4dc5, + 0x0110, 0x080c, 0x41c5, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x080c, 0x3682, 0x701b, 0x30b6, 0x0005, 0xade8, 0x000d, + 0x6800, 0xa005, 0x0904, 0x2927, 0x6804, 0xd0ac, 0x0118, 0xd0a4, + 0x0904, 0x2927, 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0xa18d, + 0x0020, 0x6106, 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, + 0x0118, 0xa18d, 0x0010, 0x0010, 0xa18c, 0xffef, 0x6106, 0x00ce, + 0x2009, 0x0100, 0x210c, 0xa18a, 0x0002, 0x0268, 0xd084, 0x0158, + 0x6a28, 0xa28a, 0x007f, 0x1a04, 0x2927, 0xa288, 0x2719, 0x210d, + 0xa18c, 0x00ff, 0x6156, 0xd0dc, 0x0130, 0x6828, 0xa08a, 0x007f, + 0x1a04, 0x2927, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0a04, 0x2927, + 0xa08a, 0x0841, 0x1a04, 0x2927, 0xa084, 0x0007, 0x1904, 0x2927, + 0x680c, 0xa005, 0x0904, 0x2927, 0x6810, 0xa005, 0x0904, 0x2927, + 0x6848, 0x6940, 0xa10a, 0x1a04, 0x2927, 0x8001, 0x0904, 0x2927, + 0x684c, 0x6944, 0xa10a, 0x1a04, 0x2927, 0x8001, 0x0904, 0x2927, + 0x6804, 0xd0fc, 0x01f8, 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, + 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, + 0x0000, 0x080c, 0x3682, 0x701b, 0x312e, 0x0005, 0xade8, 0x000d, + 0x20a9, 0x0014, 0x2d98, 0x2069, 0x926d, 0x2da0, 0x53a3, 0x7010, + 0xa0e8, 0x000d, 0x20a9, 0x001c, 0x2d98, 0x2069, 0x9251, 0x2da0, + 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, + 0x6042, 0x080c, 0x4e5d, 0x080c, 0x4780, 0x080c, 0x47d8, 0x6000, + 0xa086, 0x0000, 0x1904, 0x31e5, 0x6808, 0x602a, 0x080c, 0x20ce, + 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, + 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, + 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, + 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x080c, 0x57bc, + 0x6904, 0xd1fc, 0x0520, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, + 0x6b70, 0xd384, 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, + 0x080c, 0x532a, 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, + 0x8007, 0x600a, 0xa184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, + 0x0003, 0x0010, 0x6003, 0x0001, 0x1f04, 0x3184, 0x00ce, 0x2069, + 0x9251, 0x2001, 0x94d7, 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, + 0x0178, 0xa28e, 0x0010, 0x0118, 0xa28e, 0x0020, 0x0148, 0x2003, + 0xaaaa, 0x2001, 0x0204, 0x2004, 0x2009, 0x94c8, 0x200a, 0x0008, + 0x2102, 0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, + 0x00ce, 0x080c, 0x4dc5, 0x0128, 0x080c, 0x3912, 0x0110, 0x080c, + 0x2455, 0x60c0, 0xa005, 0x01a8, 0x6003, 0x0001, 0x2091, 0x301d, + 0x080c, 0x4dc5, 0x1158, 0x2011, 0x4ce2, 0x080c, 0x5731, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0038, 0x080c, 0x4105, + 0x0020, 0x6003, 0x0004, 0x2091, 0x301d, 0x0804, 0x28ff, 0x6000, + 0xa086, 0x0000, 0x0904, 0x2924, 0x2069, 0x9251, 0x7830, 0x6842, + 0x7834, 0x6846, 0x2d00, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x0804, 0x3685, 0x81ff, 0x1904, 0x2924, 0x080c, 0x4dc5, + 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x0038, 0xa006, 0x080c, 0x2455, 0x080c, + 0x41c5, 0x080c, 0x4105, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, + 0x080c, 0x4dc5, 0x1110, 0x0804, 0x2924, 0x6184, 0x81ff, 0x0198, + 0x703f, 0x0000, 0x2001, 0x98c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x0126, 0x2091, 0x8000, 0x080c, 0x3685, 0x701b, + 0x28fd, 0x012e, 0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0x98c0, + 0x20a9, 0x0040, 0x20a1, 0x98c0, 0x2019, 0xffff, 0x43a4, 0x654c, + 0xa588, 0x2719, 0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, + 0x0002, 0x2100, 0xa506, 0x01a8, 0x080c, 0x4434, 0x1190, 0x6014, + 0x821c, 0x0238, 0xa398, 0x98c0, 0xa085, 0xff00, 0x8007, 0x201a, + 0x0038, 0xa398, 0x98c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, + 0x8210, 0x8108, 0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, + 0x2d0c, 0xa105, 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0x98c0, + 0x2099, 0x98c0, 0x080c, 0x4166, 0x0804, 0x3222, 0x080c, 0x3666, + 0x0904, 0x2927, 0x00c6, 0x080c, 0x3641, 0x00ce, 0x0904, 0x2924, + 0x080c, 0x4dc5, 0x0500, 0x2001, 0x9252, 0x2004, 0xd0b4, 0x01d8, + 0x6000, 0xd08c, 0x11c0, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x1190, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x8476, + 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x329f, 0x0005, 0x080c, + 0x3666, 0x0904, 0x2927, 0x20a9, 0x002d, 0x2c98, 0xade8, 0x0002, + 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, + 0x0006, 0x20a0, 0x080c, 0x4166, 0x20a9, 0x0004, 0xac80, 0x000a, + 0x2098, 0xad80, 0x000a, 0x20a0, 0x080c, 0x4166, 0x2d00, 0x2009, + 0x002f, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, 0x45e9, + 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x7828, 0xa08a, 0x1000, + 0x1a04, 0x2927, 0x080c, 0x3666, 0x0904, 0x2927, 0x080c, 0x4644, + 0x0904, 0x2924, 0x2019, 0x0004, 0x080c, 0x45fb, 0x7924, 0x810f, + 0x7a28, 0x0011, 0x0804, 0x28ff, 0xa186, 0x00ff, 0x0110, 0x0071, + 0x0060, 0x2029, 0x007e, 0x2061, 0x9200, 0x644c, 0x2400, 0xa506, + 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, 0x4434, + 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x573d, + 0x0005, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, + 0x080c, 0x44d4, 0x0904, 0x2924, 0x080c, 0x45f2, 0x0804, 0x28ff, + 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, 0x0904, 0x2927, 0x080c, + 0x44d4, 0x0904, 0x2924, 0x080c, 0x45e0, 0x0804, 0x28ff, 0x6100, + 0x2001, 0x94d8, 0x2014, 0xa282, 0x0003, 0x1210, 0x0804, 0x28ff, + 0x2011, 0x0000, 0x0804, 0x28ff, 0x0804, 0x28ff, 0x080c, 0x3666, + 0x0904, 0x2927, 0x6004, 0xa086, 0x0707, 0x0904, 0x2927, 0x2001, + 0x9200, 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x00d6, 0xace8, + 0x000a, 0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007, + 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, + 0x00de, 0x6100, 0xa18c, 0x0200, 0x0804, 0x28ff, 0x7824, 0xa09c, + 0x00ff, 0xa39a, 0x0003, 0x1a04, 0x2924, 0x624c, 0xa294, 0x00ff, + 0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0x9240, 0x2009, + 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, 0x81ff, + 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0006, 0x1904, 0x2924, 0x00c6, 0x080c, 0x3641, + 0x00ce, 0x0904, 0x2924, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, + 0x080c, 0x8428, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3399, + 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0xad80, 0x000e, + 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3685, + 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, 0x0118, 0x81ff, 0x1904, + 0x2924, 0x080c, 0x4dc5, 0x0128, 0xa006, 0x080c, 0x2455, 0x080c, + 0x41c5, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2927, 0x7924, 0xa18c, + 0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f, 0x1a04, + 0x2927, 0x2100, 0x080c, 0x241f, 0x0026, 0x00c6, 0x0126, 0x2091, + 0x8000, 0x2061, 0x94f8, 0x601b, 0x0000, 0x601f, 0x0000, 0x080c, + 0x4dc5, 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x00a0, 0x2061, 0x0100, 0x2001, + 0x9214, 0x2004, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, + 0x0090, 0x6043, 0x0010, 0x2009, 0x001e, 0x2011, 0x412a, 0x080c, + 0x57b3, 0x7924, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4dc5, 0x1110, + 0x2009, 0x00ff, 0x7a28, 0x080c, 0x32ec, 0x012e, 0x00ce, 0x002e, + 0x0804, 0x28ff, 0x7924, 0xa18c, 0xff00, 0x810f, 0x00c6, 0x080c, + 0x4400, 0x2c08, 0x00ce, 0x1904, 0x2927, 0x0804, 0x28ff, 0x81ff, + 0x1904, 0x2924, 0x60c8, 0xd0ac, 0x1118, 0xd09c, 0x0904, 0x2924, + 0x080c, 0x3641, 0x0904, 0x2924, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, + 0x7d38, 0x080c, 0x3682, 0x701b, 0x342e, 0x0005, 0x2009, 0x0080, + 0x080c, 0x4434, 0x1130, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0120, 0x2021, 0x400a, 0x0804, 0x2901, 0x00d6, 0xade8, 0x000d, + 0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, + 0x0100, 0x0904, 0x34a1, 0xa0be, 0x0112, 0x0904, 0x34a1, 0xa0be, + 0x0113, 0x0904, 0x34a1, 0xa0be, 0x0114, 0x0904, 0x34a1, 0xa0be, + 0x0117, 0x0904, 0x34a1, 0xa0be, 0x011a, 0x0904, 0x34a1, 0xa0be, + 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, 0x0171, 0x05c8, + 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, 0x6830, 0x8007, + 0x6832, 0x04a0, 0xa0be, 0x0212, 0x0540, 0xa0be, 0x0213, 0x0528, + 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, 0xa0be, 0x021a, + 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, 0x0300, 0x01c8, + 0x00de, 0x0804, 0x2927, 0xad80, 0x0010, 0x20a9, 0x0007, 0x080c, + 0x34dd, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x34dd, 0x0048, + 0xad80, 0x000c, 0x080c, 0x34eb, 0x0048, 0xad80, 0x000e, 0x080c, + 0x34eb, 0xad80, 0x000c, 0x20a9, 0x0001, 0x04b9, 0x00c6, 0x080c, + 0x3641, 0x0540, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, + 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, + 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, + 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, + 0x0000, 0x080c, 0x8442, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, + 0x34d6, 0x0005, 0x00ce, 0x00de, 0x0804, 0x2924, 0x6820, 0xa086, + 0x8001, 0x0904, 0x2924, 0x0804, 0x28ff, 0x0016, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, 0x1f04, + 0x34df, 0x001e, 0x0005, 0x0016, 0x00a6, 0x00b6, 0x2008, 0x2044, + 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, 0x8108, + 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x00be, 0x00ae, 0x001e, + 0x0005, 0x81ff, 0x1904, 0x2924, 0x7924, 0x2140, 0xa18c, 0xff00, + 0x810f, 0x60c8, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2927, + 0xa182, 0x00ff, 0x1a04, 0x2927, 0x7a2c, 0x7b28, 0x606c, 0xa306, + 0x1140, 0x6070, 0xa24e, 0x0904, 0x2927, 0xa9cc, 0xff00, 0x0904, + 0x2927, 0x00c6, 0x080c, 0x359b, 0x2c68, 0x00ce, 0x01c0, 0xa0c6, + 0x4000, 0x1108, 0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, + 0xa0c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, + 0x1108, 0x0010, 0x2001, 0x4006, 0x2020, 0x0804, 0x2901, 0x2d00, + 0x7022, 0x0016, 0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x749c, + 0x05b8, 0x2d00, 0x601a, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, + 0x3641, 0x00ce, 0x2b70, 0x1140, 0x080c, 0x74f2, 0x00ee, 0x00ce, + 0x00be, 0x001e, 0x0804, 0x2924, 0x6837, 0x0000, 0x683b, 0x0000, + 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0xd88c, 0x0108, + 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x266c, 0x012e, + 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, + 0x080c, 0x43e3, 0x2009, 0x0002, 0x080c, 0x7518, 0xa085, 0x0001, + 0x00ee, 0x00ce, 0x00be, 0x001e, 0x0904, 0x2924, 0x7007, 0x0003, + 0x701b, 0x358b, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, + 0x7020, 0x2060, 0x2009, 0x0000, 0x080c, 0x46a5, 0x1110, 0x2009, + 0x0001, 0x0804, 0x28ff, 0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, + 0x9232, 0x2004, 0xd0ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, + 0x2071, 0x936e, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, + 0x93ee, 0x2e04, 0xa005, 0x1130, 0x2100, 0xa406, 0x1548, 0x2428, + 0xc5fd, 0x0430, 0x2068, 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, + 0x2600, 0xa206, 0x1190, 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, + 0x0540, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1510, 0x2001, + 0x4000, 0x0400, 0x2001, 0x4007, 0x00e8, 0x2400, 0xa106, 0x1140, + 0x6e14, 0x87ff, 0x1110, 0x86ff, 0x09d0, 0x2001, 0x4008, 0x0090, + 0x8420, 0x8e70, 0x1f04, 0x35b1, 0x85ff, 0x1130, 0x2001, 0x4009, + 0x0048, 0x2001, 0x0001, 0x0030, 0x080c, 0x4400, 0x1dd0, 0x6312, + 0x6216, 0xa006, 0xa005, 0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, + 0x2924, 0x080c, 0x3641, 0x0904, 0x2924, 0x6837, 0x0000, 0x6838, + 0xc0fd, 0x683a, 0x7824, 0xa005, 0x0904, 0x2927, 0xa096, 0x00ff, + 0x0120, 0xa092, 0x0004, 0x1a04, 0x2927, 0x2010, 0x2d18, 0x080c, + 0x2631, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3618, 0x0005, + 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, 0x7924, + 0xa18c, 0xff00, 0x810f, 0x60c8, 0xd0ac, 0x1120, 0xa182, 0x0080, + 0x0a04, 0x2927, 0xa182, 0x00ff, 0x1a04, 0x2927, 0x0126, 0x2091, + 0x8000, 0x080c, 0x831a, 0x1150, 0xa190, 0x936e, 0x2204, 0xa065, + 0x0128, 0x080c, 0x41e0, 0x012e, 0x0804, 0x28ff, 0x012e, 0x0804, + 0x2924, 0x080c, 0x147c, 0x0188, 0xa006, 0x6802, 0x7010, 0xa005, + 0x1120, 0x2d00, 0x7012, 0x7016, 0x0030, 0x7014, 0x6802, 0x2060, + 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, 0x0005, 0x7924, 0x810f, + 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1130, 0x7e28, 0xa684, 0x3fff, + 0xa082, 0x4000, 0x0208, 0xa066, 0x8cff, 0x0005, 0x7e24, 0x860f, + 0xa18c, 0x00ff, 0x080c, 0x4434, 0x1128, 0xa6b4, 0x00ff, 0xa682, + 0x4000, 0x0208, 0xa066, 0x8cff, 0x0005, 0x0016, 0x7110, 0x81ff, + 0x0128, 0x2168, 0x6904, 0x080c, 0x1493, 0x0cc8, 0x7112, 0x7116, + 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, 0x2031, 0x0000, 0x2061, + 0x92e6, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, + 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x28ff, 0x0005, + 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, 0x92a4, + 0x2004, 0xa005, 0x1168, 0x0e04, 0x36b0, 0x7818, 0xd084, 0x1140, + 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001, 0x2091, 0x4080, 0x0408, + 0x0016, 0x00c6, 0x00e6, 0x2071, 0x9296, 0x7138, 0xa182, 0x0010, + 0x0218, 0x7030, 0x2060, 0x0078, 0x7030, 0xa0e0, 0x0004, 0xac82, + 0x92e6, 0x0210, 0x2061, 0x92a6, 0x2c00, 0x7032, 0x81ff, 0x1108, + 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x00ee, 0x00ce, + 0x001e, 0x012e, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x9296, 0x7038, + 0xa005, 0x0570, 0x0126, 0x2091, 0x8000, 0x0e04, 0x3707, 0x00f6, + 0x2079, 0x0000, 0x7818, 0xd084, 0x1508, 0x00c6, 0x7034, 0x2060, + 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, 0x782a, 0x781b, 0x0001, + 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0xa005, 0x1130, 0x7033, + 0x92a6, 0x7037, 0x92a6, 0x00ce, 0x0048, 0xac80, 0x0004, 0xa0fa, + 0x92e6, 0x0210, 0x2001, 0x92a6, 0x7036, 0x00ce, 0x00fe, 0x012e, + 0x00ee, 0x0005, 0x0026, 0x2001, 0x9252, 0x2004, 0xd0c4, 0x0120, + 0x2011, 0x8014, 0x080c, 0x3698, 0x002e, 0x0005, 0x81ff, 0x1904, + 0x2924, 0x0126, 0x2091, 0x8000, 0x6030, 0xc08d, 0x6032, 0x080c, + 0x4dc5, 0x1158, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x0010, 0x080c, 0x4105, 0x012e, + 0x0804, 0x28ff, 0x7824, 0x2008, 0xa18c, 0xfffd, 0x1128, 0x61d4, + 0xa10d, 0x61d6, 0x0804, 0x28ff, 0x0804, 0x2927, 0x81ff, 0x1904, + 0x2924, 0x6000, 0xa086, 0x0003, 0x1904, 0x2924, 0x2001, 0x9252, + 0x2004, 0xd0a4, 0x1904, 0x2924, 0x080c, 0x3666, 0x0904, 0x2927, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120, 0x7828, 0xa005, + 0x0904, 0x28ff, 0x00c6, 0x080c, 0x3641, 0x00ce, 0x0904, 0x2924, + 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, + 0x84d7, 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x3770, 0x0005, + 0x6830, 0xa086, 0x0100, 0x0904, 0x2924, 0x0804, 0x28ff, 0x2001, + 0x9200, 0x2004, 0xa086, 0x0003, 0x1904, 0x2924, 0x7f24, 0x7a2c, + 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, + 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, + 0x0005, 0x7026, 0x20a0, 0x080c, 0x4434, 0x15e0, 0x6004, 0xa0c4, + 0x00ff, 0xa8c6, 0x0006, 0x0150, 0xa0c4, 0xff00, 0xa8c6, 0x0600, + 0x0128, 0xa084, 0x00ff, 0xa082, 0x0006, 0x1660, 0xd784, 0x0150, + 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, + 0x34eb, 0x0048, 0xac80, 0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, + 0x53a3, 0x080c, 0x34eb, 0xa186, 0x007e, 0x0178, 0xa186, 0x0080, + 0x0160, 0x6004, 0xa084, 0x00ff, 0xa0c2, 0x0006, 0x1210, 0xc1fd, + 0x0020, 0x080c, 0x46a5, 0x1108, 0xc1fd, 0x21a2, 0xc1fc, 0x94a0, + 0xa6b0, 0x0005, 0x8108, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x0118, + 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186, 0x0100, 0x0148, + 0x0018, 0xa186, 0x007e, 0x0128, 0xa686, 0x0028, 0x0150, 0x0804, + 0x3793, 0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x28ff, 0x702f, + 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0x92e6, + 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3809, + 0x0005, 0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, + 0x2031, 0x0000, 0x2061, 0x92e6, 0x6224, 0x6328, 0x642c, 0x6530, + 0x0804, 0x3793, 0x7120, 0x810b, 0x0804, 0x28ff, 0x2029, 0x007e, + 0x7924, 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, + 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa184, 0x00ff, + 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa284, + 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, + 0x2927, 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, + 0x0a04, 0x2927, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, + 0x2927, 0xa502, 0x0a04, 0x2927, 0xa384, 0x00ff, 0xa0e2, 0x0020, + 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa484, 0xff00, 0x8007, + 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, 0xa484, + 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2927, 0xa502, 0x0a04, 0x2927, + 0x2061, 0x94df, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x28ff, + 0x080c, 0x3641, 0x0904, 0x2924, 0x2009, 0x0015, 0x7a2c, 0x7b28, + 0x7c3c, 0x7d38, 0x080c, 0x3682, 0x701b, 0x3887, 0x0005, 0xade8, + 0x000d, 0x6800, 0xa005, 0x0904, 0x2927, 0x6804, 0x2008, 0xa18c, + 0xfff8, 0x1904, 0x2927, 0x680c, 0xa005, 0x0904, 0x2927, 0xa082, + 0xff01, 0x1a04, 0x2927, 0x6810, 0xa082, 0x005c, 0x0a04, 0x2927, + 0x6824, 0x2008, 0xa082, 0x0008, 0x0a04, 0x2927, 0xa182, 0x0400, + 0x1a04, 0x2927, 0x080c, 0x5a84, 0x6944, 0x6820, 0xa102, 0x0a04, + 0x2927, 0x6828, 0x6944, 0x810c, 0xa102, 0x0a04, 0x2927, 0x6840, + 0xa082, 0x000f, 0x1a04, 0x2927, 0x00d6, 0x080c, 0x145f, 0x0904, + 0x2924, 0x2d00, 0x00de, 0x684e, 0x00d6, 0x6848, 0xa005, 0x0148, + 0x2008, 0x2069, 0x9200, 0x68dc, 0xa108, 0x68a8, 0xa102, 0x1208, + 0x69de, 0x00de, 0x20a9, 0x0015, 0x2d98, 0x2069, 0x9281, 0x2da0, + 0x53a3, 0x080c, 0x5957, 0x0904, 0x2924, 0x080c, 0x5885, 0x1904, + 0x2924, 0x00c6, 0x2061, 0x0100, 0x6104, 0xa18d, 0x8000, 0x6106, + 0x610c, 0xa18d, 0x0100, 0x610e, 0x2061, 0x0140, 0x610c, 0xa18d, + 0x0100, 0x6902, 0x6b10, 0x2061, 0x9519, 0x6316, 0x080c, 0x4716, + 0x2001, 0x9295, 0x2003, 0x0000, 0x00ce, 0x0804, 0x28ff, 0xe000, + 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0x0804, 0x28ff, + 0x7824, 0x0804, 0x28ff, 0x7824, 0x00e6, 0x2071, 0x9281, 0x00ee, + 0x0804, 0x28ff, 0x0006, 0x2001, 0x9252, 0x2004, 0xd0cc, 0x000e, + 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xd0bc, 0x000e, 0x0005, + 0x6164, 0x7a24, 0x6300, 0x82ff, 0x1118, 0x7926, 0x0804, 0x28ff, + 0x83ff, 0x1904, 0x2927, 0x2001, 0xfff0, 0xa200, 0x1a04, 0x2927, + 0x2019, 0xffff, 0x6068, 0xa302, 0xa200, 0x0a04, 0x2927, 0x7926, + 0x6266, 0x0804, 0x28ff, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1904, 0x2924, 0x7c28, 0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3641, + 0x0904, 0x2924, 0x2009, 0x0000, 0x2019, 0x0000, 0x7023, 0x0000, + 0x702f, 0x0000, 0xad80, 0x0003, 0x7026, 0x20a0, 0xa1e0, 0x936e, + 0x2c64, 0x8cff, 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, + 0x0130, 0x6004, 0xa084, 0xff00, 0xa086, 0x0600, 0x1158, 0x6014, + 0x20a2, 0x94a0, 0x6010, 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, + 0xa398, 0x0002, 0x8108, 0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, + 0x0148, 0x08e0, 0x83ff, 0x1120, 0x7120, 0x810c, 0x0804, 0x28ff, + 0x702f, 0x0001, 0x711e, 0x7020, 0xa300, 0x7022, 0x2061, 0x92e6, + 0x6007, 0x0000, 0x6312, 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, + 0x6732, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3999, + 0x0005, 0x702c, 0xa005, 0x1158, 0x711c, 0x7024, 0x20a0, 0x2019, + 0x0000, 0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x3956, 0x7120, + 0x810c, 0x0804, 0x28ff, 0x81ff, 0x1904, 0x2924, 0x60c8, 0xd0ac, + 0x1118, 0xd09c, 0x0904, 0x2924, 0x080c, 0x3641, 0x0904, 0x2924, + 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3682, 0x701b, + 0x39c2, 0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, + 0x0148, 0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, + 0x0804, 0x2927, 0x6820, 0x6924, 0x080c, 0x240b, 0x1500, 0x080c, + 0x4400, 0x11e8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, + 0x3641, 0x01a8, 0x080c, 0x3641, 0x0190, 0x00ce, 0x00de, 0x6837, + 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x080c, 0x845c, + 0x0904, 0x2924, 0x7007, 0x0003, 0x701b, 0x39fa, 0x0005, 0x00de, + 0x0804, 0x2924, 0x7120, 0x080c, 0x441f, 0x6820, 0xa086, 0x8001, + 0x0904, 0x2924, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, 0x0006, + 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4166, 0x000e, 0xade8, + 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0x92e6, 0x6007, + 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018, 0xa7c6, + 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2927, 0x2009, 0x0004, + 0x0804, 0x3685, 0xa7c6, 0x7200, 0x1904, 0x2927, 0xa6c2, 0x0054, + 0x0a04, 0x2927, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, + 0x6532, 0x2c10, 0x080c, 0x14c7, 0x7007, 0x0002, 0x701b, 0x3a41, + 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, + 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4166, + 0x000e, 0x2009, 0x002a, 0x2061, 0x92e6, 0x6224, 0x6328, 0x642c, + 0x6530, 0x0804, 0x3685, 0x81ff, 0x1904, 0x2924, 0x080c, 0x3656, + 0x0904, 0x2927, 0x080c, 0x44d4, 0x0904, 0x2924, 0x080c, 0x4604, + 0x0804, 0x28ff, 0x0126, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, + 0x9200, 0x6044, 0xd0a4, 0x11b0, 0xd084, 0x0118, 0x080c, 0x3bd7, + 0x0068, 0xd08c, 0x0118, 0x080c, 0x3af8, 0x0040, 0xd094, 0x0118, + 0x080c, 0x3ad0, 0x0018, 0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, + 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, + 0x001e, 0x0ca0, 0x624c, 0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, + 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0478, + 0xa294, 0xff00, 0xa296, 0xf700, 0x0160, 0x6240, 0xa295, 0x0100, + 0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x4186, + 0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0040, 0x6042, 0x6043, + 0x0000, 0x7077, 0x0000, 0x7093, 0x0001, 0x70b3, 0x0000, 0x70cb, + 0x0000, 0x2009, 0x98c0, 0x200b, 0x0000, 0x7087, 0x0000, 0x707b, + 0x000f, 0x2009, 0x000f, 0x2011, 0x40a8, 0x080c, 0x57b3, 0x0005, + 0x0156, 0x7078, 0xa005, 0x1510, 0x2011, 0x40a8, 0x080c, 0x5731, + 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, + 0x6044, 0xd08c, 0x1168, 0x1f04, 0x3ae0, 0x6242, 0x708b, 0x0000, + 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, 0x0030, + 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, 0x0000, 0x015e, 0x0005, + 0x707c, 0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, 0x13fe, + 0x0005, 0x3b04, 0x3b54, 0x3bd6, 0x00f6, 0x707f, 0x0001, 0x20e1, + 0xa000, 0xe000, 0x20e1, 0x8700, 0x080c, 0x20ce, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2079, 0x9700, 0x207b, 0x2200, 0x7807, 0x00ef, + 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, + 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, + 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0x970c, 0x207b, 0x1101, + 0x7807, 0x0000, 0x2099, 0x9205, 0x20a1, 0x970e, 0x20a9, 0x0004, + 0x53a3, 0x2079, 0x9712, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, + 0x9700, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, + 0x600f, 0x0000, 0x080c, 0x40ec, 0x00fe, 0x7083, 0x0000, 0x6043, + 0x0008, 0x6043, 0x0000, 0x0005, 0x00d6, 0x7080, 0x7083, 0x0000, + 0xa025, 0x0904, 0x3bbe, 0x6020, 0xd0b4, 0x1904, 0x3bbc, 0x7190, + 0x81ff, 0x0904, 0x3ba6, 0xa486, 0x000c, 0x1904, 0x3bb1, 0xa480, + 0x0018, 0x8004, 0x20a8, 0x2011, 0x9780, 0x2019, 0x9700, 0x220c, + 0x2304, 0xa106, 0x1188, 0x8210, 0x8318, 0x1f04, 0x3b6f, 0x6043, + 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707f, + 0x0002, 0x708b, 0x0002, 0x04c0, 0x2069, 0x9780, 0x6930, 0xa18e, + 0x1101, 0x1538, 0x6834, 0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, + 0x1118, 0x6804, 0xa005, 0x0190, 0x2011, 0x978e, 0x2019, 0x9205, + 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0230, 0x1190, 0x8210, + 0x8318, 0x1f04, 0x3b9a, 0x0068, 0x7093, 0x0000, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x20a9, 0x0014, + 0x53a6, 0x6043, 0x0008, 0x6043, 0x0000, 0x6020, 0xd0b4, 0x1120, + 0x60c3, 0x000c, 0x080c, 0x40ec, 0x00de, 0x0005, 0x6040, 0xa085, + 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c, 0x2011, + 0x94ef, 0x2013, 0x0000, 0x7083, 0x0000, 0x20e1, 0x9080, 0x60a3, + 0x0056, 0x60a7, 0x9575, 0x080c, 0x6f15, 0x0c30, 0x0005, 0x7088, + 0xa08a, 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x13fe, 0x0005, + 0x3c0a, 0x3c19, 0x3c43, 0x3c58, 0x3c7e, 0x3ca6, 0x3ccc, 0x3cfd, + 0x3d23, 0x3d4b, 0x3d86, 0x3dae, 0x3dca, 0x3de0, 0x3e00, 0x3e13, + 0x3e1b, 0x3e45, 0x3e6b, 0x3e93, 0x3eb9, 0x3eea, 0x3f25, 0x3f54, + 0x3f70, 0x3faf, 0x3fcf, 0x3fe8, 0x3fe9, 0x00c6, 0x2061, 0x9200, + 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, + 0x00ce, 0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, + 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x40af, 0x080c, 0x5725, + 0x0005, 0x00f6, 0x7080, 0xa086, 0x0014, 0x1518, 0x6043, 0x0000, + 0x6020, 0xd0b4, 0x11f0, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1102, + 0x11b0, 0x7834, 0xa005, 0x1198, 0x7a38, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x2011, 0x40af, + 0x080c, 0x5731, 0x708b, 0x0010, 0x080c, 0x3e1b, 0x0010, 0x7083, + 0x0000, 0x00fe, 0x0005, 0x708b, 0x0003, 0x6043, 0x0004, 0x080c, + 0x416e, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, 0x20a3, + 0x0000, 0x1f04, 0x3c4f, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, + 0x00f6, 0x7080, 0xa005, 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, + 0xa086, 0x0014, 0x11b8, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1102, + 0x1188, 0x7834, 0xa005, 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x708b, 0x0004, + 0x0029, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0005, + 0x080c, 0x416e, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, + 0x978e, 0x080c, 0x41bd, 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, + 0xa186, 0xffff, 0x0128, 0x080c, 0x4074, 0x0110, 0x080c, 0x419d, + 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, + 0xa005, 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, + 0x11b8, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1103, 0x1188, 0x7834, + 0xa005, 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, + 0x080c, 0x419d, 0x70b3, 0x0001, 0x708b, 0x0006, 0x0029, 0x0010, + 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0007, 0x080c, 0x416e, + 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, + 0x41bd, 0x11a8, 0x7074, 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, + 0x0170, 0xa180, 0x2719, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, + 0x4074, 0x0128, 0x080c, 0x3919, 0x0110, 0x080c, 0x2455, 0x20a9, + 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, + 0x2079, 0x9780, 0x7a30, 0xa296, 0x1104, 0x1188, 0x7834, 0xa005, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x0008, 0x0029, 0x0010, 0x080c, + 0x41b6, 0x00fe, 0x0005, 0x708b, 0x0009, 0x080c, 0x416e, 0x20a3, + 0x1105, 0x20a3, 0x0100, 0x3430, 0x080c, 0x41bd, 0x1150, 0x7074, + 0xa005, 0x1138, 0x080c, 0x3fea, 0x1170, 0xa085, 0x0001, 0x080c, + 0x2455, 0x20a9, 0x0008, 0x2099, 0x978e, 0x26a0, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0010, + 0x080c, 0x3bfd, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05a8, 0x2011, + 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x1560, 0x2079, 0x9780, + 0x7a30, 0xa296, 0x1105, 0x1530, 0x7834, 0x2011, 0x0100, 0xa21e, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x000a, 0x00c1, 0x00a8, 0xa005, + 0x1188, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x7087, 0x0000, 0x708b, 0x000e, 0x080c, + 0x3e00, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, 0x708b, 0x000b, + 0x2011, 0x970e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, + 0x20a9, 0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x416e, 0x20a3, + 0x1106, 0x20a3, 0x0000, 0x080c, 0x41bd, 0x0118, 0x2013, 0x0000, + 0x0020, 0x7050, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, + 0x53a6, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, + 0xa005, 0x01b0, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0084, + 0x1168, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, + 0xa005, 0x1120, 0x708b, 0x000c, 0x0029, 0x0010, 0x080c, 0x41b6, + 0x00fe, 0x0005, 0x708b, 0x000d, 0x080c, 0x416e, 0x20a3, 0x1107, + 0x20a3, 0x0000, 0x2099, 0x978e, 0x20a9, 0x0040, 0x53a6, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, + 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x40af, 0x080c, 0x5731, + 0xa086, 0x0084, 0x1188, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1107, + 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, 0x4160, + 0x708b, 0x000e, 0x0029, 0x0010, 0x080c, 0x41b6, 0x00fe, 0x0005, + 0x708b, 0x000f, 0x7083, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, + 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x40af, + 0x080c, 0x5725, 0x0005, 0x7080, 0xa005, 0x0120, 0x2011, 0x40af, + 0x080c, 0x5731, 0x0005, 0x708b, 0x0011, 0x716c, 0x81ff, 0x0170, + 0x2009, 0x0000, 0x7070, 0xa084, 0x00ff, 0x080c, 0x240b, 0xa186, + 0x0080, 0x0120, 0x2011, 0x978e, 0x080c, 0x4074, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x7480, 0xa480, + 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, + 0x60c3, 0x0014, 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, + 0x0500, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, + 0x2079, 0x9780, 0x7a30, 0xa296, 0x1103, 0x1188, 0x7834, 0xa005, + 0x1170, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x708b, 0x0012, 0x0029, 0x0010, 0x7083, + 0x0000, 0x00fe, 0x0005, 0x708b, 0x0013, 0x080c, 0x417a, 0x20a3, + 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, 0x41bd, + 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, 0xa186, 0xffff, 0x0128, + 0x080c, 0x4074, 0x0110, 0x080c, 0x419d, 0x20a9, 0x0008, 0x2298, + 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, + 0x080c, 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, 0x0500, 0x2011, + 0x40af, 0x080c, 0x5731, 0xa086, 0x0014, 0x11b8, 0x2079, 0x9780, + 0x7a30, 0xa296, 0x1104, 0x1188, 0x7834, 0xa005, 0x1170, 0x7a38, + 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, + 0x0001, 0x708b, 0x0014, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, + 0x0005, 0x708b, 0x0015, 0x080c, 0x417a, 0x20a3, 0x1104, 0x20a3, + 0x0000, 0x3430, 0x2011, 0x978e, 0x080c, 0x41bd, 0x11a8, 0x7074, + 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170, 0xa180, 0x2719, + 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4074, 0x0128, 0x080c, + 0x3919, 0x0110, 0x080c, 0x2455, 0x20a9, 0x0008, 0x2298, 0x26a0, + 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, + 0x40ec, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05a8, 0x2011, 0x40af, + 0x080c, 0x5731, 0xa086, 0x0014, 0x1560, 0x2079, 0x9780, 0x7a30, + 0xa296, 0x1105, 0x1530, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1178, + 0x7a38, 0xd2f4, 0x0110, 0x70cb, 0x0008, 0xd2fc, 0x0138, 0x70b0, + 0xa005, 0x1120, 0x080c, 0x419d, 0x70b3, 0x0001, 0x0070, 0xa005, + 0x1180, 0x7a38, 0xd2fc, 0x0138, 0x70b0, 0xa005, 0x1120, 0x080c, + 0x419d, 0x70b3, 0x0001, 0x7087, 0x0000, 0x708b, 0x0016, 0x0029, + 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x20e1, 0x9080, 0x20e1, + 0x4000, 0x2099, 0x9780, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, + 0x3430, 0x2011, 0x978e, 0x708b, 0x0017, 0x080c, 0x41bd, 0x1150, + 0x7074, 0xa005, 0x1138, 0x080c, 0x3fea, 0x1170, 0xa085, 0x0001, + 0x080c, 0x2455, 0x20a9, 0x0008, 0x2099, 0x978e, 0x26a0, 0x53a6, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x40ec, + 0x0010, 0x080c, 0x3bfd, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01b0, + 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, 0x0084, 0x1168, 0x2079, + 0x9780, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, 0xa005, 0x1120, + 0x708b, 0x0018, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, + 0x708b, 0x0019, 0x080c, 0x417a, 0x20a3, 0x1106, 0x20a3, 0x0000, + 0x3430, 0x2099, 0x978e, 0x2039, 0x970e, 0x27a0, 0x20a9, 0x0040, + 0x53a3, 0x080c, 0x41bd, 0x11e8, 0x2728, 0x2514, 0x8207, 0xa084, + 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, + 0x7050, 0x2310, 0x8214, 0xa2a0, 0x970e, 0x2414, 0xa38c, 0x0001, + 0x0118, 0xa294, 0xff00, 0x0018, 0xa294, 0x00ff, 0x8007, 0xa215, + 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, 0x00f6, + 0x7080, 0xa005, 0x01d0, 0x2011, 0x40af, 0x080c, 0x5731, 0xa086, + 0x0084, 0x1188, 0x2079, 0x9780, 0x7a30, 0xa296, 0x1107, 0x1158, + 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, 0x4160, 0x708b, + 0x001a, 0x0029, 0x0010, 0x7083, 0x0000, 0x00fe, 0x0005, 0x708b, + 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x9780, 0x20a1, + 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, + 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x080c, 0x40ec, 0x0005, + 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0x9252, 0x252c, 0x20a9, + 0x0008, 0x2041, 0x970e, 0x28a0, 0x2099, 0x978e, 0x53a3, 0x20a9, + 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110, 0x2011, 0x0000, 0x2800, + 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148, 0xd5d4, 0x0110, 0x8210, + 0x0008, 0x8211, 0x1f04, 0x3fff, 0x0804, 0x406c, 0x82ff, 0x1160, + 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90, 0x0020, 0xa1a6, 0x3fff, + 0x0904, 0x406c, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, + 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0110, 0x8423, + 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319, 0x0008, 0x8318, + 0x1f04, 0x4025, 0x04c8, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, + 0x1f04, 0x4037, 0x2328, 0x8529, 0xa2be, 0x0007, 0x0158, 0x0006, + 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e, 0x27a8, 0xa5a8, 0x0010, + 0x1f04, 0x4046, 0x754e, 0xa5c8, 0x2719, 0x292d, 0xa5ac, 0x00ff, + 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x2435, 0x001e, 0x60e7, + 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405, 0x201a, 0x7077, 0x0001, + 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0xa085, 0x0001, 0x0028, 0xa006, 0x0018, 0xa006, 0x080c, + 0x13fe, 0x009e, 0x008e, 0x0005, 0x2118, 0x2021, 0x0000, 0x2001, + 0x0007, 0xa39a, 0x0010, 0x0218, 0x8420, 0x8001, 0x0cd0, 0x2118, + 0x84ff, 0x0120, 0xa39a, 0x0010, 0x8421, 0x1de0, 0x2021, 0x0001, + 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8, 0xa238, 0x2704, 0xa42c, + 0x11b0, 0xa405, 0x203a, 0x714e, 0xa1a0, 0x2719, 0x242d, 0xa5ac, + 0x00ff, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x2435, 0x001e, + 0x60e7, 0x0000, 0x65ea, 0x7077, 0x0001, 0xa084, 0x0000, 0x0005, + 0x00e6, 0x2071, 0x9200, 0x707b, 0x0000, 0x00ee, 0x0005, 0x00e6, + 0x00f6, 0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x6f1e, 0x7004, + 0xa084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, + 0x4dcd, 0x01b0, 0x080c, 0x4deb, 0x1198, 0x2001, 0x94d7, 0x2003, + 0xaaaa, 0x2001, 0x0204, 0x2004, 0x0016, 0x2009, 0x94c8, 0x200a, + 0x001e, 0x2001, 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0080, + 0x0126, 0x2091, 0x8000, 0x2071, 0x9222, 0x2073, 0x0000, 0x7840, + 0x0026, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42, 0x002e, + 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x2011, + 0x94ef, 0x2013, 0x0000, 0x7083, 0x0000, 0x012e, 0x20e1, 0x9080, + 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x6f15, 0x2009, 0x07d0, + 0x2011, 0x40af, 0x080c, 0x57b3, 0x0005, 0x0016, 0x0026, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x2009, 0x00f7, 0x080c, 0x4186, 0x2061, + 0x94f8, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x9200, 0x6003, + 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, + 0x001e, 0x2011, 0x412a, 0x080c, 0x5725, 0x012e, 0x00ce, 0x002e, + 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x0100, 0x080c, 0x6f1e, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, + 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x4dcd, 0x01b0, + 0x080c, 0x4deb, 0x1198, 0x2001, 0x94d7, 0x2003, 0xaaaa, 0x2001, + 0x0204, 0x2004, 0x0016, 0x2009, 0x94c8, 0x200a, 0x001e, 0x2001, + 0x94d8, 0x2003, 0x0000, 0x080c, 0x4d10, 0x0030, 0x2001, 0x0001, + 0x080c, 0x23ba, 0x080c, 0x4105, 0x012e, 0x000e, 0x00ee, 0x0005, + 0x20a9, 0x0040, 0x20a1, 0x98c0, 0x2099, 0x978e, 0x3304, 0x8007, + 0x20a2, 0x9398, 0x94a0, 0x1f04, 0x4166, 0x0005, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x2099, 0x9700, 0x20a1, 0x020b, 0x20a9, 0x000c, + 0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0x9780, + 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, 0x0006, + 0x2061, 0x0100, 0x810f, 0x2001, 0x922f, 0x2004, 0xa005, 0x1138, + 0x2001, 0x9214, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, 0xa185, + 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001, + 0x9252, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, + 0x080c, 0x90d7, 0x2001, 0x920c, 0x200c, 0xc195, 0x2102, 0x2019, + 0x002a, 0x080c, 0x264b, 0x004e, 0x001e, 0x0005, 0x080c, 0x4105, + 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006, 0x2001, 0x920c, + 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, 0x0016, 0x0126, + 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, + 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, 0x20a9, 0x00ff, 0x2009, + 0x936e, 0xa006, 0x200a, 0x8108, 0x1f04, 0x41da, 0x015e, 0x0005, + 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, 0x2069, 0x9251, 0xa006, + 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x2719, + 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, + 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, + 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, + 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, + 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x61a2, + 0x00d6, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x1493, 0x60a7, 0x0000, + 0x60a8, 0xa06d, 0x0110, 0x080c, 0x1493, 0x60ab, 0x0000, 0x00de, + 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0xa006, 0x60b2, + 0x60ae, 0x60b6, 0x60bb, 0x0520, 0x6814, 0xa084, 0x00ff, 0x6042, + 0x014e, 0x013e, 0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, + 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, + 0x42cf, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x1a04, 0x42d4, + 0x2001, 0x920c, 0x2004, 0xa084, 0x0003, 0x1904, 0x42bd, 0xa188, + 0x936e, 0x2104, 0xa065, 0x0904, 0x42a9, 0x6004, 0xa084, 0x00ff, + 0xa08e, 0x0006, 0x1904, 0x42ae, 0x60a4, 0xa00d, 0x0118, 0x080c, + 0x4630, 0x05d0, 0x60a8, 0xa00d, 0x0188, 0x080c, 0x467a, 0x1170, + 0x694c, 0xd1fc, 0x1118, 0x080c, 0x43c4, 0x0448, 0x080c, 0x4386, + 0x694c, 0xd1ec, 0x1520, 0x080c, 0x452b, 0x0408, 0x694c, 0xa184, + 0xa000, 0x0178, 0xd1ec, 0x0140, 0xd1fc, 0x0118, 0x080c, 0x453a, + 0x0028, 0x080c, 0x453a, 0x0028, 0xd1fc, 0x0118, 0x080c, 0x4386, + 0x0070, 0x6050, 0xa00d, 0x0130, 0x2d00, 0x200a, 0x6803, 0x0000, + 0x6052, 0x0028, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x080c, + 0x6015, 0xa006, 0x012e, 0x0005, 0x2001, 0x0005, 0x2009, 0x0000, + 0x0478, 0x2001, 0x0028, 0x2009, 0x0000, 0x0450, 0xa082, 0x0006, + 0x1260, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1120, 0x60a0, 0xd0bc, + 0x0904, 0x4264, 0x2001, 0x0028, 0x0078, 0x2009, 0x920c, 0x210c, + 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0010, 0x2001, 0x0029, 0x2009, 0x0000, 0x0048, 0x2001, + 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, + 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, 0x2091, 0x8000, 0x6844, + 0x0006, 0x000e, 0x0006, 0x000e, 0xa084, 0xff00, 0xa08e, 0xff00, + 0x1120, 0x2001, 0x94c6, 0x2064, 0x0098, 0x6844, 0x8007, 0xa084, + 0x00ff, 0x2008, 0xa182, 0x00ff, 0x16c8, 0xa188, 0x936e, 0x2104, + 0xa065, 0x01f0, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11d8, + 0x2c70, 0x080c, 0x749c, 0x0580, 0x2e00, 0x601a, 0x2d00, 0x6012, + 0x601f, 0x0009, 0x600b, 0x0000, 0x6844, 0xa08e, 0xff00, 0x1110, + 0x600b, 0x8000, 0x2009, 0x0100, 0x080c, 0x7518, 0xa006, 0x00c8, + 0x2001, 0x0028, 0x00a8, 0xa082, 0x0006, 0x0e10, 0x2009, 0x920c, + 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, + 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, + 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, 0x002c, 0x0cc8, 0x6944, + 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1678, 0xa18c, 0xff00, + 0x810f, 0xa182, 0x00ff, 0x12e0, 0xa188, 0x936e, 0x2104, 0xa065, + 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11b0, 0x684c, + 0xd0ec, 0x0120, 0x080c, 0x453a, 0x0489, 0x0030, 0x0479, 0x684c, + 0xd0fc, 0x0110, 0x080c, 0x452b, 0x080c, 0x4578, 0xa006, 0x0088, + 0x2001, 0x0028, 0x2009, 0x0000, 0x0060, 0xa082, 0x0006, 0x0e38, + 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, + 0x0000, 0xa005, 0x0005, 0x0126, 0x2091, 0x8000, 0x6050, 0xa00d, + 0x0138, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x012e, 0x0005, + 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, 0x0126, 0x2091, + 0x8000, 0x604c, 0xa005, 0x0170, 0x00e6, 0x2071, 0x94e5, 0x7004, + 0xa086, 0x0002, 0x0168, 0x00ee, 0x604c, 0x6802, 0x2d00, 0x604e, + 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, + 0x701c, 0xac06, 0x1d80, 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, + 0x7002, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x604c, + 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, + 0x012e, 0x0005, 0x604c, 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, + 0x6052, 0x604e, 0xad05, 0x0005, 0x6803, 0x0000, 0x6084, 0xa00d, + 0x0120, 0x2d00, 0x200a, 0x6086, 0x0005, 0x2d00, 0x6086, 0x6082, + 0x0cd8, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, 0x6218, 0x2260, + 0x6200, 0xa005, 0x0110, 0xc285, 0x0008, 0xc284, 0x6202, 0x002e, + 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, + 0x2260, 0x6204, 0xa294, 0xff00, 0xa215, 0x6206, 0x00ce, 0x012e, + 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, + 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, + 0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, + 0x936e, 0x2204, 0xa065, 0x1180, 0x0016, 0x00d6, 0x080c, 0x145f, + 0x2d60, 0x00de, 0x001e, 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, + 0x60ab, 0x0000, 0x080c, 0x41e0, 0xa006, 0x002e, 0x0005, 0x0026, + 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0060, 0x00d6, 0xa190, + 0x936e, 0x2204, 0xa06d, 0x0120, 0x2013, 0x0000, 0x080c, 0x1493, + 0x00de, 0xa006, 0x002e, 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, + 0xa085, 0x0001, 0x0030, 0xa188, 0x936e, 0x2104, 0xa065, 0x0dc0, + 0xa006, 0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, + 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x080c, 0x4dc5, + 0x1520, 0x60a0, 0xa086, 0x007e, 0x2069, 0x9790, 0x0130, 0x2001, + 0x9232, 0x2004, 0xd0ac, 0x11c8, 0x0098, 0x2d04, 0xd0e4, 0x01a8, + 0x00d6, 0x2069, 0x978e, 0x00c6, 0x2061, 0x94d9, 0x6810, 0x2062, + 0x6814, 0x6006, 0x6818, 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, + 0x8d69, 0x2d04, 0x2069, 0x0140, 0x6886, 0x2069, 0x978e, 0x6808, + 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0208, 0x603a, 0x6814, + 0x6066, 0x2099, 0x9796, 0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2099, 0x979a, 0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, + 0x53a3, 0x2069, 0x97ae, 0x6808, 0x606a, 0x690c, 0x616e, 0x6810, + 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, 0x1218, 0x2009, 0x0008, + 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0xa182, + 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, 0x1218, + 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, 0x0004, + 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, + 0x0002, 0x6192, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x00e6, + 0x2071, 0x978d, 0x2e04, 0x6896, 0x2071, 0x978e, 0x7004, 0x689a, + 0x701c, 0x689e, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff, 0x1540, 0x6a04, 0xa282, + 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, + 0xffff, 0x0128, 0x8108, 0x1f04, 0x44e6, 0x080c, 0x13fe, 0x260a, + 0x8210, 0x6a06, 0x0098, 0x080c, 0x145f, 0x01a8, 0x2d00, 0x60a6, + 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, + 0x8108, 0x1f04, 0x44fe, 0x6807, 0x0001, 0x6e12, 0xa085, 0x0001, + 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, + 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168, 0x6800, 0xa005, 0x1160, + 0x080c, 0x4630, 0x1168, 0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, + 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, 0x1493, 0x60a7, 0x0000, + 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x468d, + 0x0010, 0x080c, 0x4373, 0x080c, 0x45af, 0x1dd8, 0x080c, 0x4578, + 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a8, 0xa06d, + 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54, 0xa282, 0x0010, 0x1670, + 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0128, + 0x8108, 0x1f04, 0x454c, 0x080c, 0x13fe, 0x260a, 0x8210, 0x6a56, + 0x0098, 0x080c, 0x145f, 0x01d0, 0x2d00, 0x60aa, 0x6853, 0x0000, + 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, + 0x4564, 0x6857, 0x0001, 0x6e62, 0x0010, 0x080c, 0x43c4, 0x0089, + 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6015, 0x012e, 0x0005, 0xa01e, + 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126, 0x2091, 0x8000, 0x604c, + 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff, 0x01e8, 0x83ff, 0x0120, + 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, + 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x604c, + 0xad06, 0x1110, 0x624e, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, + 0x1110, 0x6152, 0x8dff, 0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, + 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x01e8, 0x83ff, 0x0120, + 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, 0x1118, 0x6840, + 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, 0x6a00, 0x6080, + 0xad06, 0x1110, 0x6282, 0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, + 0x1110, 0x6186, 0x8dff, 0x0005, 0xa016, 0x080c, 0x462a, 0x1110, + 0x2011, 0x0001, 0x080c, 0x4674, 0x1110, 0xa295, 0x0002, 0x0005, + 0x080c, 0x46a5, 0x0118, 0x080c, 0x83ab, 0x0010, 0xa085, 0x0001, + 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x8338, 0x0010, 0xa085, + 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x837e, 0x0010, + 0xa085, 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, 0x8352, + 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x46a5, 0x0118, 0x080c, + 0x83d8, 0x0010, 0xa085, 0x0001, 0x0005, 0x0126, 0x0006, 0x00d6, + 0x2091, 0x8000, 0x6080, 0xa06d, 0x0168, 0x6800, 0x0006, 0x6837, + 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, + 0x000e, 0x0c88, 0x6083, 0x0000, 0x6087, 0x0000, 0x00de, 0x000e, + 0x012e, 0x0005, 0x60a4, 0xa00d, 0x1118, 0xa085, 0x0001, 0x0005, + 0x00e6, 0x2170, 0x7000, 0xa005, 0x1160, 0x20a9, 0x0010, 0xae88, + 0x0004, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x4639, 0xa085, + 0x0001, 0xa006, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x1128, 0x080c, 0x145f, 0x01a0, 0x2d00, 0x60a6, + 0x6803, 0x0001, 0x6807, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, + 0x200b, 0xffff, 0x8108, 0x1f04, 0x4658, 0xa085, 0x0001, 0x012e, + 0x00de, 0x0005, 0xa006, 0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, + 0x60a4, 0xa06d, 0x0130, 0x60a7, 0x0000, 0x080c, 0x1493, 0xa085, + 0x0001, 0x012e, 0x00de, 0x0005, 0x60a8, 0xa00d, 0x1118, 0xa085, + 0x0001, 0x0005, 0x00e6, 0x2170, 0x7050, 0xa005, 0x1160, 0x20a9, + 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, + 0x4683, 0xa085, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, + 0x0c19, 0x1188, 0x200b, 0xffff, 0x00d6, 0x60a8, 0x2068, 0x6854, + 0xa08a, 0x0002, 0x0218, 0x8001, 0x6856, 0x0020, 0x080c, 0x1493, + 0x60ab, 0x0000, 0x00de, 0x012e, 0x0005, 0x609c, 0xd0a4, 0x0005, + 0x00f6, 0x2079, 0x9251, 0x7804, 0xd0a4, 0x0518, 0x0156, 0x00c6, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1168, + 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, 0x0118, 0xa086, + 0x0006, 0x1118, 0x6000, 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, + 0x46b4, 0x00ce, 0x015e, 0x2009, 0x07d0, 0x2011, 0x46d3, 0x080c, + 0x57b3, 0x00fe, 0x0005, 0x2011, 0x46d3, 0x080c, 0x5731, 0x0156, + 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, + 0x1530, 0x6000, 0xd0ec, 0x0518, 0x0046, 0x62a0, 0xa294, 0x00ff, + 0x8227, 0xa006, 0x2009, 0x0029, 0x080c, 0x90d7, 0x6000, 0xc0e5, + 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, 0x6006, + 0x2019, 0x0029, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, + 0x606d, 0x2009, 0x0000, 0x080c, 0x8ee4, 0x008e, 0x004e, 0x001e, + 0x8108, 0x1f04, 0x46dd, 0x00ce, 0x015e, 0x0005, 0x00c6, 0x6018, + 0x2060, 0x6000, 0xc0ec, 0x6002, 0x00ce, 0x0005, 0x00c6, 0x00d6, + 0x080c, 0x145f, 0x2d60, 0x090c, 0x13fe, 0x2009, 0x00ff, 0x080c, + 0x41e0, 0x6007, 0x0006, 0x6013, 0x00ff, 0x6017, 0xffff, 0x606f, + 0x0200, 0x606c, 0x6093, 0x0002, 0x60bb, 0x0520, 0x60a3, 0x00ff, + 0x60b7, 0x0000, 0x60af, 0x0000, 0x2c08, 0x2001, 0x94c6, 0x2102, + 0x00de, 0x00ce, 0x0005, 0x0156, 0x00e6, 0x00d6, 0x00c6, 0x20a9, + 0x00ff, 0x2009, 0x0000, 0x0016, 0x080c, 0x4434, 0x1138, 0x2c70, + 0x70ac, 0xa005, 0x0118, 0x2060, 0x080c, 0x5cf4, 0x001e, 0x8108, + 0x1f04, 0x4743, 0x00ce, 0x00de, 0x00ee, 0x015e, 0x0005, 0x2071, + 0x9328, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, + 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x704b, 0x0001, 0x704f, + 0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, + 0x94b6, 0x7003, 0x9328, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, + 0x9496, 0x7013, 0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x0005, + 0x0016, 0x00e6, 0x2071, 0x946e, 0xa00e, 0x7186, 0x718a, 0x7097, + 0x0001, 0x2001, 0x9252, 0x2004, 0xd0fc, 0x1148, 0x2001, 0x9252, + 0x2004, 0xa00e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x04f0, 0x2001, + 0x9271, 0x200c, 0xa184, 0x000f, 0x2009, 0x9272, 0x210c, 0x0002, + 0x478e, 0x47b0, 0x47b7, 0x47c1, 0x47c6, 0x478e, 0x478e, 0x478e, + 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, 0x478e, + 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, 0x0030, 0x708f, + 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, 0x7097, 0x0001, + 0x0088, 0x7007, 0x0122, 0x2001, 0x0002, 0x0020, 0x7007, 0x0121, + 0x2001, 0x0003, 0x7002, 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, + 0x8007, 0x709a, 0xa184, 0x00ff, 0x7092, 0x00ee, 0x001e, 0x0005, + 0x00e6, 0x2071, 0x9328, 0x684c, 0xa005, 0x1130, 0x7028, 0xc085, + 0x702a, 0xa085, 0x0001, 0x0418, 0x6a60, 0x7236, 0x6b64, 0x733a, + 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, + 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x8007, 0x8006, 0x8006, + 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, + 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, 0x00ee, + 0x0005, 0x0156, 0x00e6, 0x0026, 0x6838, 0xd0fc, 0x1904, 0x4861, + 0x6804, 0xa00d, 0x0188, 0x00d6, 0x2071, 0x9200, 0xa016, 0x702c, + 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, + 0x70ac, 0xa200, 0x70ae, 0x00de, 0x2071, 0x9328, 0x701c, 0xa005, + 0x1904, 0x4871, 0x20a9, 0x0032, 0x0f04, 0x486f, 0x0e04, 0x482c, + 0x2071, 0x946e, 0x7200, 0x82ff, 0x05d0, 0x6934, 0xa186, 0x0103, + 0x1904, 0x487f, 0x6948, 0x6844, 0xa105, 0x1538, 0x2009, 0x8020, + 0x2200, 0x0002, 0x486f, 0x4846, 0x48e6, 0x48f3, 0x2071, 0x0000, + 0x20a9, 0x0032, 0x0f04, 0x486f, 0x7018, 0xd084, 0x1dd8, 0x7122, + 0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, + 0x2071, 0x9200, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000, + 0x70ae, 0x002e, 0x00ee, 0x015e, 0x0005, 0x6844, 0xa086, 0x0100, + 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, 0x0888, 0x2071, + 0x9328, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, 0x7018, + 0xa06d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x0c10, 0xa18c, + 0x00ff, 0xa186, 0x0013, 0x01e0, 0xa186, 0x001b, 0x01c8, 0xa186, + 0x0023, 0x01e8, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, + 0xa18e, 0x001f, 0x19e0, 0x684c, 0xd0cc, 0x09c8, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x1998, 0x2009, 0x8021, 0x0804, 0x4840, + 0x6848, 0xa005, 0x1960, 0x2009, 0x8022, 0x0804, 0x4840, 0x2071, + 0x0000, 0x7018, 0xd084, 0x1918, 0x00e6, 0x2071, 0x9281, 0x7140, + 0x00ee, 0x6838, 0xa102, 0x0a04, 0x486f, 0x684c, 0xa005, 0x1158, + 0x00e6, 0x2071, 0x9281, 0x7004, 0x00ee, 0xd08c, 0x1904, 0x486f, + 0x2001, 0x8024, 0x0040, 0x6848, 0xd084, 0x1118, 0x2001, 0x8023, + 0x0010, 0x2001, 0x8027, 0x7022, 0x6840, 0x7026, 0x683c, 0x702a, + 0x6850, 0x702e, 0x0026, 0x0036, 0x6b38, 0x2e10, 0xa290, 0x0072, + 0x2d00, 0xa080, 0x0015, 0x200c, 0x2112, 0x8000, 0x200c, 0x8210, + 0x8319, 0x1dd0, 0x003e, 0x002e, 0x0804, 0x4854, 0x7084, 0x8008, + 0xa092, 0x001e, 0x1a04, 0x486f, 0x7186, 0xae90, 0x0003, 0xa210, + 0x683c, 0x2012, 0x0080, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, + 0x486f, 0x7186, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, + 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, 0x0a04, 0x4858, 0x718c, + 0x7084, 0xa10a, 0x0a04, 0x4858, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x4858, 0x2071, 0x946e, 0x7000, 0xa086, 0x0002, 0x1150, + 0x080c, 0x4b12, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, + 0x0804, 0x4858, 0x080c, 0x4b3c, 0x2071, 0x0000, 0x701b, 0x0001, + 0x2091, 0x4080, 0x0804, 0x4858, 0x0006, 0x6837, 0x0103, 0x20a9, + 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x000e, + 0x684a, 0x6952, 0x0005, 0x2071, 0x9328, 0x7004, 0x0002, 0x4948, + 0x4958, 0x4afd, 0x4afe, 0x4b0b, 0x4b11, 0x4949, 0x4aee, 0x4a9a, + 0x0005, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4956, 0x2009, 0x000d, + 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, 0x012e, 0x0005, + 0x2069, 0x94f8, 0x683c, 0xa005, 0x03f8, 0x11f0, 0x0126, 0x2091, + 0x8000, 0x2069, 0x0000, 0x6934, 0x2001, 0x9334, 0x2004, 0xa10a, + 0x0170, 0x0e04, 0x497c, 0x2069, 0x0000, 0x6818, 0xd084, 0x1158, + 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x2069, + 0x94f8, 0x683f, 0xffff, 0x012e, 0x2069, 0x9200, 0x6844, 0x6964, + 0xa102, 0x2069, 0x946e, 0x688a, 0x6984, 0x701c, 0xa06d, 0x0120, + 0x81ff, 0x0904, 0x49d1, 0x00a0, 0x81ff, 0x0904, 0x4a6f, 0x2071, + 0x946e, 0x7184, 0x7088, 0xa10a, 0x1258, 0x7190, 0x2071, 0x94f8, + 0x7038, 0xa005, 0x0128, 0x1b04, 0x4a6f, 0x713a, 0x0804, 0x4a6f, + 0x2071, 0x946e, 0x718c, 0x0126, 0x2091, 0x8000, 0x7084, 0xa10a, + 0x0a04, 0x4a70, 0x0e04, 0x4a2d, 0x2071, 0x0000, 0x7018, 0xd084, + 0x1904, 0x4a2d, 0x2001, 0xffff, 0x2071, 0x94f8, 0x703a, 0x2071, + 0x946e, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x4b12, 0x2071, + 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x4a2d, 0x080c, + 0x4b3c, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, + 0x4a2d, 0x2071, 0x946e, 0x7000, 0xa005, 0x0904, 0x4a51, 0x6934, + 0xa186, 0x0103, 0x1904, 0x4a30, 0x6948, 0x6844, 0xa105, 0x1904, + 0x4a47, 0x2071, 0x946e, 0x7000, 0x0002, 0x4a51, 0x4a11, 0x49e9, + 0x49fb, 0x7084, 0x8008, 0xa092, 0x001e, 0x1a04, 0x4a6f, 0xae90, + 0x0003, 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0x9328, 0x080c, + 0x4b95, 0x0804, 0x4a6f, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, + 0x4a6f, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, + 0x6840, 0x2012, 0x7186, 0x2071, 0x9328, 0x080c, 0x4b95, 0x0804, + 0x4a6f, 0x2009, 0x8020, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4a2d, + 0x2071, 0x0000, 0x7018, 0xd084, 0x1180, 0x7122, 0x683c, 0x7026, + 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x012e, 0x2071, + 0x9328, 0x080c, 0x4b95, 0x0804, 0x4a6f, 0x012e, 0x0804, 0x4a6f, + 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, + 0xa18e, 0x001f, 0x11b0, 0x684c, 0xd0cc, 0x0198, 0x6850, 0xa084, + 0x00ff, 0xa086, 0x0001, 0x1168, 0x2009, 0x8021, 0x0860, 0x6844, + 0xa086, 0x0100, 0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, + 0x0810, 0x2071, 0x9328, 0x080c, 0x4ba7, 0x01c8, 0x2071, 0x9328, + 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x1130, + 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x7007, 0x0003, + 0x080c, 0x4bc0, 0x7050, 0xa086, 0x0100, 0x0904, 0x4afe, 0x0005, + 0x2071, 0x9328, 0x080c, 0x4ba7, 0x0518, 0x2071, 0x946e, 0x7084, + 0x700a, 0x20a9, 0x0020, 0x2099, 0x946f, 0x20a1, 0x9496, 0x53a3, + 0x7087, 0x0000, 0x2071, 0x9328, 0x2069, 0x94b6, 0x706c, 0x6826, + 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x080c, + 0x14c7, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0x94f8, 0x703a, + 0x012e, 0x08a8, 0x2069, 0x94b6, 0x6808, 0xa08e, 0x0000, 0x0904, + 0x4aed, 0xa08e, 0x0200, 0x0904, 0x4aeb, 0xa08e, 0x0100, 0x1904, + 0x4aed, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4ae9, 0x2069, 0x0000, + 0x6818, 0xd084, 0x15b0, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, + 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, + 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, + 0x6936, 0x2001, 0x9493, 0x2004, 0xa005, 0x1190, 0x6934, 0x2069, + 0x946e, 0x689c, 0x699e, 0x2069, 0x94f8, 0xa102, 0x1118, 0x683c, + 0xa005, 0x1368, 0x2001, 0x9494, 0x200c, 0x810d, 0x693e, 0x0038, + 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x7007, + 0x0001, 0x012e, 0x0010, 0x7007, 0x0005, 0x0005, 0x701c, 0xa06d, + 0x0158, 0x080c, 0x4ba7, 0x0140, 0x7007, 0x0003, 0x080c, 0x4bc0, + 0x7050, 0xa086, 0x0100, 0x0110, 0x0005, 0x0005, 0x7050, 0xa09e, + 0x0100, 0x1118, 0x7007, 0x0004, 0x0030, 0xa086, 0x0200, 0x1110, + 0x7007, 0x0005, 0x0005, 0x080c, 0x4b61, 0x7006, 0x080c, 0x4b95, + 0x0005, 0x0005, 0x00e6, 0x0156, 0x2071, 0x946e, 0x7184, 0x81ff, + 0x0500, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, + 0x2014, 0x7226, 0x8000, 0x0f04, 0x4b36, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x4b36, 0x2014, 0x722e, 0x8000, 0x0f04, 0x4b36, 0x2014, + 0x723a, 0x8000, 0x0f04, 0x4b36, 0x2014, 0x723e, 0xa180, 0x8030, + 0x7022, 0x015e, 0x00ee, 0x0005, 0x00e6, 0x0156, 0x2071, 0x946e, + 0x7184, 0x81ff, 0x01d8, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, + 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, 0x722a, 0x8000, + 0x0f04, 0x4b58, 0x2014, 0x723a, 0x8000, 0x2014, 0x723e, 0x0018, + 0x2001, 0x8020, 0x0010, 0xa180, 0x8042, 0x7022, 0x015e, 0x00ee, + 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, + 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e, + 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, + 0x700e, 0x11a0, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4b91, 0x2001, + 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x012e, 0x0005, + 0x2001, 0x000d, 0x2102, 0x2001, 0x0001, 0x0005, 0x2001, 0x0007, + 0x0005, 0x2001, 0x0006, 0x012e, 0x0005, 0x701c, 0xa06d, 0x0170, + 0x0126, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, + 0xa005, 0x1108, 0x701a, 0x012e, 0x080c, 0x1493, 0x0005, 0x2019, + 0x000d, 0x2304, 0x230c, 0xa10e, 0x0130, 0x2304, 0x230c, 0xa10e, + 0x0110, 0xa006, 0x0060, 0x732c, 0x8319, 0x7130, 0xa102, 0x1118, + 0x2300, 0xa005, 0x0020, 0x0210, 0xa302, 0x0008, 0x8002, 0x0005, + 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x0126, + 0x2091, 0x8000, 0x2009, 0x9508, 0x2104, 0xc08d, 0x200a, 0x012e, + 0x080c, 0x14df, 0x0005, 0x7088, 0xa08a, 0x0027, 0x1220, 0xa082, + 0x001d, 0x0033, 0x0010, 0x080c, 0x13fe, 0x6027, 0x1e00, 0x0005, + 0x4c57, 0x4be9, 0x4bff, 0x4c27, 0x4c4a, 0x4c7c, 0x4c8e, 0x4bff, + 0x4c68, 0x6803, 0x0010, 0x6124, 0xd1e4, 0x1180, 0x080c, 0x4cd7, + 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140, 0x708b, 0x0020, + 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, + 0x0008, 0x6124, 0xd1cc, 0x11e8, 0xd1dc, 0x11c0, 0xd1e4, 0x1198, + 0xa184, 0x1e00, 0x11d8, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, + 0x080c, 0x4df5, 0x6803, 0x0000, 0x708b, 0x0026, 0x2001, 0x9225, + 0x2003, 0x0000, 0x0058, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, + 0x0028, 0x708b, 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x60e3, + 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x4df5, 0x6803, 0x0000, + 0x6124, 0xd1d4, 0x11a0, 0xd1dc, 0x1178, 0xd1e4, 0x1150, 0xa184, + 0x1e00, 0x1178, 0x708b, 0x0026, 0x2001, 0x9225, 0x2003, 0x0000, + 0x0040, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, + 0x001f, 0x0005, 0x6803, 0x0020, 0x6124, 0xd1dc, 0x1128, 0xd1e4, + 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001d, 0x0005, 0x080c, + 0x4d03, 0x6124, 0xd1dc, 0x1158, 0x080c, 0x4cd7, 0xd1d4, 0x1128, + 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001f, 0x0005, + 0x6803, 0x0020, 0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, + 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, + 0x0010, 0x708b, 0x0021, 0x0005, 0x080c, 0x4d03, 0x6124, 0xd1d4, + 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, + 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x0010, + 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, + 0x0158, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, + 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x00c6, 0x00d6, 0x00e6, + 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x9200, 0x2091, + 0x8000, 0x080c, 0x4de1, 0x0150, 0x080c, 0x4dd7, 0x1138, 0x2001, + 0x0001, 0x080c, 0x23ba, 0x080c, 0x4d9a, 0x00a0, 0x080c, 0x4d00, + 0x0178, 0x2001, 0x0001, 0x080c, 0x23ba, 0x7088, 0xa086, 0x001e, + 0x0120, 0x7088, 0xa086, 0x0022, 0x1118, 0x708b, 0x0025, 0x0010, + 0x708b, 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0016, + 0x0026, 0x2009, 0x0064, 0x2011, 0x4ce2, 0x080c, 0x57b3, 0x002e, + 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, 0x6f1e, 0x2071, + 0x9200, 0x080c, 0x4ca5, 0x001e, 0x00fe, 0x00ee, 0x0005, 0x0026, + 0x00e6, 0x2011, 0x4ce2, 0x2071, 0x94f8, 0x701c, 0xa206, 0x1118, + 0x7018, 0xa005, 0x0110, 0xa085, 0x0001, 0x00ee, 0x002e, 0x0005, + 0x6020, 0xd09c, 0x0005, 0x6803, 0x0040, 0x0156, 0x20a9, 0x002d, + 0x1d04, 0x4d08, 0x2091, 0x6000, 0x1f04, 0x4d08, 0x015e, 0x0005, + 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, + 0x9200, 0x2001, 0x94d8, 0x200c, 0xa186, 0x0000, 0x0158, 0xa186, + 0x0001, 0x0158, 0xa186, 0x0002, 0x0158, 0xa186, 0x0003, 0x0158, + 0x0804, 0x4d88, 0x708b, 0x0022, 0x0048, 0x708b, 0x0021, 0x0030, + 0x708b, 0x0023, 0x0038, 0x708b, 0x0024, 0x0020, 0xa085, 0x0001, + 0x080c, 0x4e05, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, + 0x080c, 0x2460, 0x0026, 0x2011, 0x0003, 0x080c, 0x718f, 0x002e, + 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b, + 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024, + 0xd0ac, 0x0118, 0x012e, 0x015e, 0x04c8, 0x6803, 0x0080, 0x6803, + 0x0000, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100, 0x1f04, 0x4d57, + 0x080c, 0x4e12, 0x012e, 0x015e, 0x080c, 0x4dd7, 0x01a8, 0x6044, + 0xa005, 0x0168, 0x6050, 0x0006, 0xa085, 0x0020, 0x6052, 0x080c, + 0x4e12, 0xa006, 0x8001, 0x1df0, 0x000e, 0x6052, 0x0028, 0x6804, + 0xd0d4, 0x1110, 0x080c, 0x4e12, 0x2001, 0x94d8, 0x2003, 0x0004, + 0x080c, 0x4bd3, 0x080c, 0x4dd7, 0x0148, 0x6804, 0xd0d4, 0x1130, + 0xd0dc, 0x1100, 0x2001, 0x94d8, 0x2003, 0x0000, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, + 0x0140, 0x2071, 0x9200, 0x2001, 0x94d7, 0x2003, 0x0000, 0x2001, + 0x94c8, 0x2003, 0x0000, 0x708b, 0x0000, 0x60e3, 0x0000, 0x6887, + 0x0000, 0x2001, 0x0000, 0x080c, 0x2460, 0x6803, 0x0000, 0x6043, + 0x0090, 0x6027, 0xffff, 0x602b, 0x002f, 0x2001, 0x9225, 0x2003, + 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0x94d7, + 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x2001, 0x9271, + 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e, 0x0005, 0x0006, + 0x2001, 0x9271, 0x2004, 0xa084, 0x0030, 0xa086, 0x0030, 0x000e, + 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xa084, 0x0030, 0xa086, + 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0x9271, 0x2004, 0xa084, + 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001, 0x920c, 0x2004, + 0xd0a4, 0x0150, 0x080c, 0x2480, 0x0036, 0x2019, 0x0028, 0x080c, + 0x264b, 0x003e, 0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0x920c, + 0x2e04, 0x0118, 0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, + 0x00ee, 0x0005, 0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, + 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, + 0x602f, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x000e, 0x602a, + 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, + 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2460, + 0x6803, 0x0080, 0x6803, 0x0000, 0x6803, 0x0020, 0x000e, 0x6052, + 0x6050, 0x0005, 0x2071, 0x92f6, 0x7003, 0x0000, 0x7007, 0x0000, + 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, + 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, + 0x708f, 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0x92f6, + 0x6848, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, + 0x0428, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, + 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, + 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, + 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, + 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005, + 0x2b78, 0x2071, 0x92f6, 0x7004, 0x0043, 0x700c, 0x0002, 0x4e9c, + 0x4e93, 0x4e93, 0x4e93, 0x4e93, 0x0005, 0x4ef2, 0x4ef3, 0x4f25, + 0x4f26, 0x4ef0, 0x4f5a, 0x4f5f, 0x4f90, 0x4f91, 0x4fac, 0x4fad, + 0x4fae, 0x4faf, 0x4fb0, 0x4fb1, 0x502d, 0x5054, 0x700c, 0x0002, + 0x4eb5, 0x4ef0, 0x4ef0, 0x4ef1, 0x4ef1, 0x7830, 0x7930, 0xa106, + 0x0120, 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8, + 0x1210, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x145f, + 0x01b0, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, + 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0x9508, 0x2104, + 0xc085, 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x14df, 0x0005, + 0x080c, 0x145f, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x145f, 0x1108, + 0x0c10, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8, + 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, 0x4efa, 0x4efd, 0x4f0b, + 0x4f24, 0x4f24, 0x080c, 0x4eae, 0x0005, 0x0126, 0x8001, 0x700e, + 0x7058, 0x0006, 0x080c, 0x5311, 0x0120, 0x2091, 0x8000, 0x080c, + 0x4eae, 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x5311, + 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, + 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, 0x1218, 0x00db, 0x012e, + 0x0005, 0x012e, 0x080c, 0x4fb2, 0x0005, 0x0005, 0x0005, 0x00e6, + 0x2071, 0x92f6, 0x700c, 0x0002, 0x4f31, 0x4f31, 0x4f31, 0x4f33, + 0x4f36, 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002, + 0x00ee, 0x0005, 0x4fb2, 0x4fb2, 0x4fce, 0x4fb2, 0x50e0, 0x4fb2, + 0x4fb2, 0x4fb2, 0x4fb2, 0x4fb2, 0x4fce, 0x5119, 0x515c, 0x51a5, + 0x51b9, 0x4fb2, 0x4fb2, 0x4fea, 0x4fce, 0x4ffe, 0x4fb2, 0x5013, + 0x5243, 0x525e, 0x4fb2, 0x4fea, 0x4fb2, 0x4ffe, 0x4fb2, 0x4fb2, + 0x5013, 0x525e, 0x7020, 0x2068, 0x080c, 0x1493, 0x0005, 0x700c, + 0x0002, 0x4f66, 0x4f69, 0x4f77, 0x4f8f, 0x4f8f, 0x080c, 0x4eae, + 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006, 0x080c, 0x5311, + 0x0120, 0x2091, 0x8000, 0x080c, 0x4eae, 0x00de, 0x0048, 0x0126, + 0x8001, 0x700e, 0x080c, 0x5311, 0x7058, 0x2068, 0x7084, 0x705a, + 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, + 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e, 0x0419, 0x0005, + 0x0005, 0x0005, 0x4fb2, 0x4fce, 0x50cc, 0x4fb2, 0x4fce, 0x4fb2, + 0x4fce, 0x4fce, 0x4fb2, 0x4fce, 0x50cc, 0x4fce, 0x4fce, 0x4fce, + 0x4fce, 0x4fce, 0x4fb2, 0x4fce, 0x50cc, 0x4fb2, 0x4fb2, 0x4fce, + 0x4fb2, 0x4fb2, 0x4fb2, 0x4fce, 0x0005, 0x0005, 0x0005, 0x0005, + 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, + 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, + 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, 0x7007, 0x0001, + 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126, 0x2091, 0x8000, + 0x080c, 0x4809, 0x012e, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, + 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x4809, + 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0988, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0804, 0x508d, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x508d, 0x0005, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x0904, 0x4fc0, 0x8001, 0x1120, 0x7007, 0x0001, + 0x0804, 0x50ac, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, + 0x704b, 0x50ac, 0x0005, 0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, + 0xa080, 0x0024, 0x2098, 0x20a1, 0x9321, 0x53a3, 0x6858, 0x7012, + 0xa082, 0x0401, 0x1a04, 0x4fdc, 0x6884, 0xa08a, 0x0003, 0x1a04, + 0x4fdc, 0xa080, 0x507e, 0x2005, 0x70c6, 0x7010, 0xa015, 0x0904, + 0x5072, 0x080c, 0x145f, 0x1118, 0x7007, 0x000f, 0x0005, 0x2d00, + 0x7022, 0x70c4, 0x2060, 0x2c05, 0x6836, 0xe004, 0xad00, 0x7096, + 0xe008, 0xa20a, 0x1210, 0xa00e, 0x2200, 0x7112, 0xe20c, 0x8003, + 0x800b, 0xa296, 0x0004, 0x0108, 0xa108, 0x719a, 0x810b, 0x719e, + 0xae90, 0x0022, 0x080c, 0x14c7, 0x7090, 0xa08e, 0x0100, 0x0170, + 0xa086, 0x0200, 0x0118, 0x7007, 0x0010, 0x0005, 0x7020, 0x2068, + 0x080c, 0x1493, 0x7014, 0x2068, 0x0804, 0x4fdc, 0x7020, 0x2068, + 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, + 0x0804, 0x502d, 0x7014, 0x2068, 0x7007, 0x0001, 0x6834, 0xa084, + 0x00ff, 0xa086, 0x001e, 0x0904, 0x5276, 0x0078, 0x5081, 0x5085, + 0x5089, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, + 0x0006, 0x0012, 0x000f, 0x0005, 0x0006, 0x2009, 0x922f, 0x210c, + 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a, 0x6853, 0x0000, + 0x080c, 0x423e, 0x1108, 0x0005, 0x080c, 0x492c, 0x0126, 0x2091, + 0x8000, 0x080c, 0x8527, 0x080c, 0x4809, 0x012e, 0x0ca0, 0x2001, + 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0x922f, 0x210c, 0x81ff, + 0x11a8, 0x6858, 0xa005, 0x01a8, 0x6838, 0xa084, 0x00ff, 0x683a, + 0x6853, 0x0000, 0x080c, 0x42db, 0x1108, 0x0005, 0x684a, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0cb8, 0x2001, 0x0028, + 0x0ca8, 0x2001, 0x0000, 0x0c90, 0x7018, 0x6802, 0x2d08, 0x2068, + 0x6906, 0x711a, 0x7010, 0x8001, 0x7012, 0x0118, 0x7007, 0x0006, + 0x0030, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x080f, 0x0005, + 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, + 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x01b0, 0x2009, 0x0000, + 0x20a9, 0x007e, 0xa096, 0x0002, 0x0178, 0xa005, 0x11f8, 0x6944, + 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4434, 0x11c0, 0x0066, 0x6e50, + 0x080c, 0x450d, 0x006e, 0x0090, 0x0046, 0x2011, 0x920c, 0x2224, + 0xc484, 0xc48c, 0x2412, 0x004e, 0x00c6, 0x080c, 0x4434, 0x1110, + 0x080c, 0x4664, 0x8108, 0x1f04, 0x510d, 0x00ce, 0x080c, 0x1493, + 0x0005, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0x9252, + 0x2004, 0xd0a4, 0x0580, 0x2061, 0x9566, 0x6100, 0xd184, 0x0178, + 0x6858, 0xa084, 0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, + 0xa005, 0x1538, 0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, + 0x0001, 0x6860, 0xa005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, + 0x6858, 0xa084, 0x00ff, 0x0178, 0x6006, 0x6858, 0x8007, 0xa084, + 0x00ff, 0x0148, 0x600a, 0x6858, 0x8000, 0x1108, 0xc28d, 0x6202, + 0x012e, 0x0804, 0x5300, 0x012e, 0x0804, 0x52fa, 0x012e, 0x0804, + 0x52f4, 0x012e, 0x0804, 0x52f7, 0x0126, 0x2091, 0x8000, 0x7007, + 0x0001, 0x2001, 0x9252, 0x2004, 0xd0a4, 0x05e0, 0x2061, 0x9566, + 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c48, + 0xa484, 0x0003, 0x0170, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x1120, + 0x2100, 0xa210, 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0xa212, + 0x02f0, 0xa484, 0x000c, 0x0188, 0x6958, 0x810f, 0xa18c, 0x00ff, + 0xa082, 0x0004, 0x1120, 0x2100, 0xa318, 0x0288, 0x0030, 0xa082, + 0x0004, 0x1168, 0x2100, 0xa31a, 0x0250, 0x6860, 0xa005, 0x0110, + 0x8000, 0x6016, 0x6206, 0x630a, 0x012e, 0x0804, 0x5300, 0x012e, + 0x0804, 0x52fd, 0x012e, 0x0804, 0x52fa, 0x0126, 0x2091, 0x8000, + 0x7007, 0x0001, 0x2061, 0x9566, 0x6300, 0xd38c, 0x1120, 0x6308, + 0x8318, 0x0220, 0x630a, 0x012e, 0x0804, 0x530e, 0x012e, 0x0804, + 0x52fd, 0x0126, 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, + 0xd0ac, 0x0148, 0x00c6, 0x2061, 0x9566, 0x6000, 0xa084, 0xfcff, + 0x6002, 0x00ce, 0x04d8, 0x6858, 0xa005, 0x0904, 0x521a, 0x685c, + 0xa065, 0x0904, 0x5216, 0x2001, 0x922f, 0x2004, 0xa005, 0x0118, + 0x080c, 0x849b, 0x0030, 0x6013, 0x0400, 0x2009, 0x0041, 0x080c, + 0x7518, 0x6958, 0xa18c, 0xf600, 0xa186, 0x2000, 0x01b8, 0xa186, + 0x0400, 0x01a0, 0xa186, 0x1000, 0x0140, 0xa186, 0x4000, 0x01b0, + 0x6118, 0x2104, 0xc0fc, 0x200a, 0x0088, 0x00c6, 0x2061, 0x9566, + 0x6000, 0xa084, 0xfdff, 0x6002, 0x00ce, 0x0040, 0x0026, 0x2009, + 0x0000, 0x2011, 0xfdff, 0x080c, 0x585b, 0x002e, 0x684c, 0xd0c4, + 0x0148, 0x2061, 0x9566, 0x6000, 0xd08c, 0x1120, 0x6008, 0x8000, + 0x0208, 0x600a, 0x00ce, 0x012e, 0x0804, 0x5300, 0x00ce, 0x012e, + 0x0804, 0x52fa, 0x6954, 0xa186, 0x002e, 0x0d40, 0xa186, 0x002d, + 0x0d28, 0xa186, 0x002a, 0x1130, 0x2001, 0x920c, 0x200c, 0xc194, + 0x2102, 0x08e0, 0xa186, 0x0020, 0x0170, 0xa186, 0x0029, 0x1d30, + 0x6944, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4434, 0x1978, 0x6000, + 0xc0e4, 0x6002, 0x0858, 0x685c, 0xa065, 0x09c0, 0x2001, 0x94dd, + 0x2004, 0x6016, 0x0818, 0x2061, 0x9566, 0x6000, 0xd084, 0x0190, + 0xd08c, 0x1904, 0x530e, 0x0126, 0x2091, 0x8000, 0x6204, 0x8210, + 0x0220, 0x6206, 0x012e, 0x0804, 0x530e, 0x012e, 0x6853, 0x0016, + 0x0804, 0x5307, 0x6853, 0x0007, 0x0804, 0x5307, 0x6834, 0x8007, + 0xa084, 0x00ff, 0x1118, 0x080c, 0x4fc0, 0x0078, 0x2030, 0x8001, + 0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007, 0x0006, 0x7012, + 0x2d00, 0x7016, 0x701a, 0x704b, 0x5276, 0x0005, 0x00e6, 0x0126, + 0x2091, 0x8000, 0x2009, 0x922f, 0x210c, 0x81ff, 0x1904, 0x52e9, + 0x2009, 0x920c, 0x210c, 0xd194, 0x1904, 0x52f1, 0x6848, 0x2070, + 0xae82, 0x9900, 0x0a04, 0x52dd, 0x2001, 0x9216, 0x2004, 0xae02, + 0x1a04, 0x52dd, 0x2061, 0x9566, 0x6100, 0xa184, 0x0001, 0x0578, + 0xa184, 0x0100, 0x1904, 0x52e0, 0xa184, 0x0200, 0x1904, 0x52e3, + 0x601c, 0xa005, 0x1904, 0x52e6, 0x711c, 0xa186, 0x0006, 0x1520, + 0x7018, 0xa005, 0x05f0, 0x2004, 0xd0e4, 0x15f0, 0xd0fc, 0x1598, + 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x1138, + 0x7112, 0x2e60, 0x080c, 0x57ca, 0x012e, 0x00ee, 0x0005, 0x2068, + 0x6800, 0xa005, 0x1de0, 0x6902, 0x012e, 0x00ee, 0x0005, 0x012e, + 0x00ee, 0x6853, 0x0006, 0x04d8, 0x6944, 0xa18c, 0xff00, 0x810f, + 0x080c, 0x4434, 0x11c8, 0x6000, 0xd0e4, 0x11b0, 0x711c, 0xa186, + 0x0007, 0x1118, 0x6853, 0x0002, 0x0088, 0x6853, 0x0008, 0x0070, + 0x6853, 0x000e, 0x0058, 0x6853, 0x0017, 0x0040, 0x6853, 0x0035, + 0x0028, 0x6853, 0x0028, 0x0010, 0x6853, 0x0029, 0x012e, 0x00ee, + 0x00b0, 0x6853, 0x002a, 0x0cd0, 0x2009, 0x003e, 0x0058, 0x2009, + 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, + 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x0126, + 0x2091, 0x8000, 0x080c, 0x4809, 0x012e, 0x0005, 0x080c, 0x1493, + 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, + 0x7072, 0x7038, 0x7076, 0x0058, 0x7070, 0xa080, 0x0040, 0x7072, + 0x1230, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, + 0x7132, 0x0005, 0x00d6, 0x080c, 0x57c1, 0x00de, 0x0005, 0x00d6, + 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x00de, 0x0005, + 0x20e1, 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, + 0x0118, 0xa086, 0x1000, 0x1520, 0x20e1, 0x0004, 0x3d60, 0xd1bc, + 0x1170, 0x2100, 0xa084, 0xff00, 0xa086, 0x0500, 0x1140, 0x0026, + 0x2c10, 0x080c, 0x566e, 0x002e, 0x0198, 0x0070, 0x3e60, 0xac84, + 0x0003, 0x1170, 0xac82, 0x9900, 0x0258, 0x6858, 0xac02, 0x1240, + 0x2009, 0x0047, 0x080c, 0x7518, 0x7a1c, 0xd284, 0x1988, 0x0005, + 0xa016, 0x080c, 0x16c6, 0x0cc0, 0x0156, 0x0136, 0x0146, 0x20e1, + 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0070, 0x1528, 0xa484, 0x7000, + 0xa086, 0x1000, 0x11a0, 0x04a1, 0x01f0, 0x20e1, 0x3000, 0x7828, + 0x7828, 0x080c, 0x53cc, 0x014e, 0x013e, 0x015e, 0x2009, 0x94ed, + 0x2104, 0xa005, 0x1108, 0x0005, 0x080c, 0x6462, 0x0ce0, 0xa484, + 0x7000, 0x1148, 0x00e9, 0x0190, 0x7000, 0xa084, 0xff00, 0xa086, + 0x8100, 0x0d18, 0x0058, 0xd5a4, 0x0140, 0x080c, 0x1c26, 0x20e1, + 0x9010, 0x2001, 0x0138, 0x2202, 0x0038, 0x0051, 0x080c, 0x9157, + 0x20e1, 0x3000, 0x7828, 0x7828, 0x014e, 0x013e, 0x015e, 0x08d8, + 0xa484, 0x01ff, 0x6882, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, + 0x03f8, 0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, + 0x0005, 0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, + 0x53a5, 0xa085, 0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, + 0xf000, 0x8007, 0xa196, 0x0000, 0x1118, 0x0804, 0x5571, 0x0005, + 0xa196, 0x2000, 0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, + 0x3a6a, 0x0ca8, 0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, + 0x55f9, 0x0c68, 0x00c6, 0x6a80, 0x82ff, 0x0904, 0x5506, 0x7110, + 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, + 0x1904, 0x5506, 0xa08e, 0x0023, 0x1558, 0x080c, 0x565c, 0x0904, + 0x5506, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, + 0xa005, 0x1904, 0x5506, 0x2009, 0x0015, 0x080c, 0x7518, 0x0804, + 0x5506, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, 0x7518, + 0x0804, 0x5506, 0xa08e, 0x0100, 0x1904, 0x5506, 0x7034, 0xa005, + 0x1904, 0x5506, 0x2009, 0x0016, 0x080c, 0x7518, 0x0804, 0x5506, + 0xa08e, 0x0022, 0x1904, 0x5506, 0x7030, 0xa08e, 0x0300, 0x1568, + 0x68c8, 0xd0a4, 0x0510, 0xc0b5, 0x68ca, 0x7100, 0xa18c, 0x00ff, + 0x696e, 0x7004, 0x6872, 0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, + 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x2435, 0x7932, + 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x240b, 0x694e, 0x703c, + 0x00e6, 0x2071, 0x0140, 0x7086, 0x00ee, 0x7034, 0xa005, 0x1904, + 0x5506, 0x2009, 0x0017, 0x0804, 0x54d9, 0xa08e, 0x0400, 0x1158, + 0x7034, 0xa005, 0x1904, 0x5506, 0x68c8, 0xc0a5, 0x68ca, 0x2009, + 0x0030, 0x0804, 0x54d9, 0xa08e, 0x0500, 0x1140, 0x7034, 0xa005, + 0x1904, 0x5506, 0x2009, 0x0018, 0x0804, 0x54d9, 0xa08e, 0x2010, + 0x1120, 0x2009, 0x0019, 0x0804, 0x54d9, 0xa08e, 0x2110, 0x1120, + 0x2009, 0x001a, 0x0804, 0x54d9, 0xa08e, 0x5200, 0x1140, 0x7034, + 0xa005, 0x1904, 0x5506, 0x2009, 0x001b, 0x0804, 0x54d9, 0xa08e, + 0x5000, 0x1140, 0x7034, 0xa005, 0x1904, 0x5506, 0x2009, 0x001c, + 0x0804, 0x54d9, 0xa08e, 0x1200, 0x1138, 0x7034, 0xa005, 0x1904, + 0x5506, 0x2009, 0x0024, 0x04a8, 0xa08c, 0xff00, 0xa18e, 0x2400, + 0x1118, 0x2009, 0x002d, 0x0468, 0xa08c, 0xff00, 0xa18e, 0x5300, + 0x1118, 0x2009, 0x002a, 0x0428, 0xa08e, 0x0f00, 0x1118, 0x2009, + 0x0020, 0x00f8, 0xa08e, 0x5300, 0x1108, 0x00c8, 0xa08e, 0x6104, + 0x11b0, 0x2011, 0x978d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, + 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x2124, 0x080c, + 0x3698, 0x8108, 0x1f04, 0x54ca, 0x2009, 0x0023, 0x0010, 0x2009, + 0x001d, 0x0016, 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, + 0x240b, 0x1530, 0x080c, 0x4400, 0x1518, 0x6612, 0x6516, 0x86ff, + 0x0180, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158, 0x686c, 0xa606, + 0x1140, 0x6870, 0xa506, 0xa084, 0xff00, 0x1118, 0x6000, 0xc0f5, + 0x6002, 0x00c6, 0x080c, 0x749c, 0x0168, 0x001e, 0x611a, 0x601f, + 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x7518, 0x00ce, 0x0005, + 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x00e6, 0x00d6, 0x2028, 0x2130, + 0xa696, 0x00ff, 0x1518, 0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, + 0x0804, 0x556d, 0xa596, 0xfffe, 0x1120, 0x2009, 0x007e, 0x0804, + 0x556d, 0xa596, 0xfffc, 0x1120, 0x2009, 0x0080, 0x0804, 0x556d, + 0xa594, 0xff00, 0xa296, 0xfc00, 0x1148, 0x2011, 0x0000, 0x2021, + 0x0081, 0x20a9, 0x007e, 0x2071, 0x93ef, 0x00a0, 0x2011, 0x0000, + 0x2019, 0x9232, 0x231c, 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, + 0x00ff, 0x2071, 0x936e, 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, + 0x2071, 0x93ef, 0x2e1c, 0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, + 0xc2fd, 0x0080, 0x2368, 0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, + 0x6b14, 0x1120, 0xa346, 0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, + 0x83ff, 0x0d58, 0x8420, 0x8e70, 0x1f04, 0x554a, 0x82ff, 0x1118, + 0xa085, 0x0001, 0x0018, 0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, + 0x0005, 0xa084, 0x0007, 0x000a, 0x0005, 0x557d, 0x557d, 0x557d, + 0x557d, 0x557d, 0x557e, 0x5593, 0x55e6, 0x0005, 0x7110, 0xd1bc, + 0x0188, 0x7120, 0x2160, 0xac8c, 0x0003, 0x1160, 0xac8a, 0x9900, + 0x0248, 0x6858, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, + 0x080c, 0x7518, 0x0005, 0x00c6, 0x7110, 0xd1bc, 0x1904, 0x55e4, + 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, 0x240b, 0x1904, + 0x55e4, 0x080c, 0x4434, 0x1904, 0x55e4, 0x6000, 0xd0ec, 0x15e0, + 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0160, 0x080c, + 0x4dc5, 0x11d0, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x11a0, + 0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0520, + 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6122, 0x2009, + 0x0044, 0x080c, 0x7518, 0x00c0, 0x00c6, 0x080c, 0x749c, 0x001e, + 0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, + 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, + 0x080c, 0x603e, 0x080c, 0x6462, 0x00ce, 0x0005, 0x7110, 0xd1bc, + 0x0178, 0x7020, 0x2060, 0xac84, 0x0003, 0x1150, 0xac82, 0x9900, + 0x0238, 0x6858, 0xac02, 0x1220, 0x2009, 0x0045, 0x080c, 0x7518, + 0x0005, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x1138, + 0xa084, 0x000f, 0xa08a, 0x0006, 0x1a0c, 0x13fe, 0x000b, 0x0005, + 0x560e, 0x560f, 0x560e, 0x560e, 0x5644, 0x5650, 0x0005, 0x7110, + 0xd1bc, 0x1588, 0x700c, 0x7108, 0x080c, 0x240b, 0x1560, 0x080c, + 0x4400, 0x1548, 0x6612, 0x6516, 0x6204, 0xa294, 0xff00, 0x8217, + 0xa286, 0x0004, 0x0118, 0xa286, 0x0006, 0x1178, 0x00c6, 0x080c, + 0x749c, 0x001e, 0x01c0, 0x611a, 0x601f, 0x0005, 0x7120, 0x610a, + 0x2009, 0x0088, 0x080c, 0x7518, 0x0070, 0x00c6, 0x080c, 0x749c, + 0x001e, 0x0148, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009, + 0x0001, 0x080c, 0x7518, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x00a1, + 0x0130, 0x7124, 0x610a, 0x2009, 0x0089, 0x080c, 0x7518, 0x0005, + 0x7110, 0xd1bc, 0x0140, 0x0041, 0x0130, 0x7124, 0x610a, 0x2009, + 0x008a, 0x080c, 0x7518, 0x0005, 0x7020, 0x2060, 0xac84, 0x0003, + 0x1158, 0xac82, 0x9900, 0x0240, 0x2001, 0x9216, 0x2004, 0xac02, + 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x00c6, 0x00d6, + 0x00e6, 0x20e1, 0x0000, 0x3d08, 0xa18c, 0x00ff, 0xa18e, 0x00ff, + 0x1150, 0x3e00, 0xa086, 0xffff, 0x1130, 0x2001, 0x94c6, 0x2064, + 0x2009, 0x00ff, 0x0060, 0x20e1, 0x0001, 0x3d08, 0x3e00, 0x0156, + 0x080c, 0x240b, 0x015e, 0x1578, 0x080c, 0x4434, 0x1560, 0x2138, + 0x873f, 0x2c00, 0x2070, 0x20e1, 0x0003, 0x3d18, 0x831f, 0xa39c, + 0x00ff, 0x0036, 0x0036, 0x003e, 0x003e, 0x20e1, 0x2000, 0x3d00, + 0xa084, 0x7000, 0xa086, 0x1000, 0x0120, 0x080c, 0x5cc0, 0x1198, + 0x0040, 0x080c, 0x749c, 0x0178, 0x2e00, 0x601a, 0x620a, 0x601f, + 0x0009, 0x2009, 0x0101, 0x080c, 0x7518, 0xa085, 0x0001, 0x00ee, + 0x00de, 0x00ce, 0x0005, 0xa006, 0x00ee, 0x00de, 0x00ce, 0x0005, + 0x2071, 0x94f8, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, + 0x7012, 0x7017, 0x9900, 0x7007, 0x0000, 0x7026, 0x702b, 0x6f2b, + 0x7032, 0x7037, 0x6f69, 0x703b, 0xffff, 0x703f, 0xffff, 0x0005, + 0x2071, 0x94f8, 0x1d04, 0x5720, 0x2091, 0x6000, 0x700c, 0x8001, + 0x700e, 0x1120, 0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, + 0x8000, 0x7024, 0xa00d, 0x0158, 0x7020, 0x8001, 0x7022, 0x1138, + 0x7023, 0x0009, 0x8109, 0x7126, 0x1110, 0x7028, 0x080f, 0x7030, + 0xa00d, 0x0158, 0x702c, 0x8001, 0x702e, 0x1138, 0x702f, 0x0009, + 0x8109, 0x7132, 0x1110, 0x7034, 0x080f, 0x7038, 0xa005, 0x0118, + 0x0310, 0x8001, 0x703a, 0x703c, 0xa005, 0x0118, 0x0310, 0x8001, + 0x703e, 0x7018, 0xa00d, 0x0158, 0x7008, 0x8001, 0x700a, 0x1138, + 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, 0x012e, + 0x7004, 0x0002, 0x5746, 0x5747, 0x575f, 0x00e6, 0x2071, 0x94f8, + 0x7018, 0xa005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee, + 0x0005, 0x00e6, 0x0006, 0x2071, 0x94f8, 0x701c, 0xa206, 0x1110, + 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x94f8, + 0x6088, 0xa102, 0x0208, 0x618a, 0x00ee, 0x0005, 0x0005, 0x7110, + 0x080c, 0x4434, 0x1158, 0x6088, 0x8001, 0x0240, 0x608a, 0x1130, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x8108, 0xa182, + 0x00ff, 0x0218, 0xa00e, 0x7007, 0x0002, 0x7112, 0x0005, 0x7014, + 0x2060, 0x0126, 0x2091, 0x8000, 0x6014, 0xa005, 0x0518, 0x8001, + 0x6016, 0x1500, 0x611c, 0xa186, 0x0003, 0x0130, 0xa186, 0x0006, + 0x0118, 0xa186, 0x0009, 0x11a0, 0x6010, 0x2068, 0x6854, 0xa08a, + 0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0210, + 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0010, + 0x080c, 0x8185, 0x012e, 0xac88, 0x000c, 0x7116, 0x2001, 0x9217, + 0x2004, 0xa102, 0x0220, 0x7017, 0x9900, 0x7007, 0x0000, 0x0005, + 0x00e6, 0x2071, 0x94f8, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, + 0x0005, 0x2001, 0x9501, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, + 0x94f8, 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0x9504, + 0x2013, 0x0000, 0x0005, 0x00e6, 0x2071, 0x94f8, 0x711a, 0x721e, + 0x700b, 0x0009, 0x00ee, 0x0005, 0x00c6, 0x2061, 0x9566, 0x00ce, + 0x0005, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x9566, + 0x2060, 0x0005, 0x6854, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, + 0xa005, 0x1150, 0x00c6, 0x2061, 0x9566, 0x6014, 0x00ce, 0xa005, + 0x1138, 0x2001, 0x001e, 0x0020, 0xa08e, 0xffff, 0x1108, 0xa006, + 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, 0x00c0, + 0xa18e, 0x00c0, 0x0588, 0xd0b4, 0x1138, 0xd0bc, 0x11f0, 0x2009, + 0x0006, 0x080c, 0x5838, 0x0005, 0xd0fc, 0x0140, 0xa084, 0x0003, + 0xa08e, 0x0003, 0x05b8, 0xa08e, 0x0000, 0x15a0, 0x2009, 0x9273, + 0x2104, 0xd084, 0x0128, 0x2009, 0x0042, 0x080c, 0x7518, 0x0005, + 0x2009, 0x0043, 0x080c, 0x7518, 0x0005, 0xd0fc, 0x0140, 0xa084, + 0x0003, 0xa08e, 0x0003, 0x01f0, 0xa08e, 0x0000, 0x11d8, 0x2009, + 0x0042, 0x080c, 0x7518, 0x0005, 0xd0fc, 0x0168, 0xa084, 0x0003, + 0xa08e, 0x0003, 0x0178, 0xa08e, 0x0002, 0x0138, 0x2009, 0x0041, + 0x080c, 0x7518, 0x0005, 0x0051, 0x0ce8, 0x2009, 0x0043, 0x080c, + 0x7518, 0x0cc0, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001, + 0x6010, 0xa0ec, 0xf000, 0x01f0, 0x2068, 0x6952, 0x6800, 0x6012, + 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, + 0x1158, 0x00c6, 0x2061, 0x9566, 0x6200, 0xd28c, 0x1120, 0x6204, + 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x4809, 0x6010, 0xa06d, + 0x190c, 0x57ca, 0x0005, 0x0156, 0x00c6, 0x2061, 0x9566, 0x6000, + 0x81ff, 0x0110, 0xa205, 0x0008, 0xa204, 0x6002, 0x00ce, 0x015e, + 0x0005, 0x6800, 0xd08c, 0x1138, 0x6808, 0xa005, 0x0120, 0x8001, + 0x680a, 0xa085, 0x0001, 0x0005, 0x2071, 0x9349, 0x7003, 0x0006, + 0x7007, 0x0000, 0x700f, 0x0000, 0x7013, 0x0001, 0x702f, 0x0006, + 0x7033, 0x0001, 0x7063, 0x0000, 0x0005, 0x00e6, 0x2071, 0x9349, + 0x6a2c, 0x721e, 0x6b30, 0x7322, 0x6834, 0x7026, 0x705a, 0x6838, + 0x702a, 0x705e, 0x6824, 0x7016, 0x683c, 0x701a, 0x2009, 0x0070, + 0x200a, 0xa005, 0x0150, 0x2009, 0x0000, 0xa188, 0x000c, 0x8001, + 0x1de0, 0x2100, 0xa210, 0x1208, 0x8318, 0x7252, 0x7356, 0x7010, + 0xc084, 0x7012, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, + 0x0005, 0x2b78, 0x2071, 0x9349, 0x7004, 0x004b, 0x700c, 0x0002, + 0x58bb, 0x58b4, 0x58b4, 0x0005, 0x58c5, 0x5913, 0x5914, 0x5915, + 0x5916, 0x5929, 0x592a, 0x700c, 0x0cba, 0x2f00, 0xa080, 0x0070, + 0x2004, 0x2f08, 0xa188, 0x0070, 0x210c, 0xa106, 0x0150, 0x2f00, + 0xa080, 0x0070, 0x2004, 0x2f08, 0xa188, 0x0070, 0x210c, 0xa106, + 0x15c8, 0x7018, 0xa10a, 0x05b0, 0x1210, 0x7114, 0xa10a, 0xa192, + 0x000a, 0x0210, 0x2009, 0x000a, 0x00d6, 0x0016, 0x2001, 0x9281, + 0xa080, 0x0011, 0x2014, 0x2001, 0x9363, 0xa080, 0x0005, 0x2004, + 0xa100, 0xa202, 0x001e, 0x00de, 0x02e8, 0x080c, 0x5976, 0x2200, + 0xa102, 0x0208, 0x2208, 0x713a, 0x080c, 0x5a67, 0x2100, 0x7042, + 0x2001, 0x0002, 0x7037, 0x0000, 0x0126, 0x0006, 0x2091, 0x8000, + 0x2009, 0x9508, 0x2104, 0xc095, 0x200a, 0x000e, 0x700e, 0x012e, + 0x080c, 0x14df, 0x0005, 0x0005, 0x0005, 0x0005, 0x700c, 0x0002, + 0x591b, 0x591e, 0x5928, 0x080c, 0x58c3, 0x0005, 0x0126, 0x8001, + 0x700e, 0x7138, 0x0041, 0x2091, 0x8000, 0x080c, 0x58c3, 0x012e, + 0x0005, 0x0005, 0x0005, 0x7018, 0xa100, 0x7214, 0xa21a, 0x1130, + 0x701c, 0x7052, 0x7020, 0x7056, 0xa006, 0x0068, 0x0006, 0x080c, + 0x5a67, 0x2100, 0x7250, 0xa210, 0x7252, 0x1220, 0x7054, 0xa081, + 0x0000, 0x7056, 0x000e, 0x2f08, 0xa188, 0x0070, 0x200a, 0x701a, + 0x0005, 0x00e6, 0x2071, 0x9349, 0x700c, 0x0002, 0x5951, 0x5951, + 0x5953, 0x00ee, 0x0005, 0x700f, 0x0001, 0x00ee, 0x0005, 0x00d6, + 0x00e6, 0x2071, 0x9363, 0xa006, 0x7006, 0x700e, 0x701a, 0x701e, + 0x7022, 0x702a, 0x7026, 0x080c, 0x5b1b, 0x0170, 0x080c, 0x5b4d, + 0x0158, 0x2d00, 0x7002, 0x700a, 0x701a, 0x7013, 0x0001, 0x701f, + 0x0007, 0x00ee, 0x00de, 0x0005, 0xa00e, 0x0cd8, 0x00e6, 0x00d6, + 0x00c6, 0x2071, 0x9363, 0x721c, 0x2100, 0xa202, 0x1618, 0x080c, + 0x5b4d, 0x090c, 0x13fe, 0x7018, 0xa005, 0x1160, 0x2d00, 0x7002, + 0x700a, 0x701a, 0xa006, 0x7006, 0x700e, 0x6806, 0x6802, 0x7012, + 0x701e, 0x0038, 0x2060, 0x6806, 0x2d00, 0x6002, 0x701a, 0x6803, + 0x0000, 0x7010, 0x8000, 0x7012, 0x701c, 0xa080, 0x0007, 0x701e, + 0x721c, 0x08d0, 0x721c, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x0156, + 0x0136, 0x0146, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x9363, + 0x7300, 0xa398, 0x0003, 0x7104, 0x080c, 0x5a67, 0x810c, 0x2100, + 0xa318, 0x8003, 0x2228, 0x2021, 0x0054, 0xa402, 0xa532, 0x0208, + 0x2028, 0x2500, 0x8004, 0x20a8, 0x23a0, 0xe000, 0xe000, 0xe000, + 0x53a5, 0x2508, 0x080c, 0x5a70, 0x2130, 0x7014, 0xa600, 0x7016, + 0x2600, 0x711c, 0xa102, 0x701e, 0x7004, 0xa600, 0x2008, 0xa082, + 0x0007, 0x1180, 0x7000, 0x2004, 0xa005, 0x1140, 0x2009, 0x0001, + 0x0026, 0x080c, 0x5976, 0x002e, 0x7000, 0x2004, 0x7002, 0x7007, + 0x0000, 0x0008, 0x7106, 0x2500, 0xa212, 0x1910, 0x012e, 0x00ee, + 0x014e, 0x013e, 0x015e, 0x0005, 0x0016, 0x0026, 0x00e6, 0x00d6, + 0x04e9, 0x15c8, 0x2170, 0x2805, 0xac68, 0x2900, 0x0002, 0x5a0f, + 0x5a0f, 0x5a13, 0x5a0f, 0x5a13, 0x5a0f, 0x5a0f, 0x5a0f, 0x5a0f, + 0x5a0f, 0x5a1c, 0x5a0f, 0x5a1c, 0x5a0f, 0x5a0f, 0x5a0f, 0x080c, + 0x13fe, 0xa005, 0x00d8, 0x7000, 0x6802, 0x7004, 0x6806, 0x7010, + 0x680a, 0x680f, 0x0000, 0x0060, 0x7010, 0x6812, 0x6817, 0x0000, + 0x7000, 0x6802, 0x7004, 0x6806, 0x7008, 0x680a, 0x700c, 0x680e, + 0x00de, 0x685c, 0x8000, 0x685e, 0x00d6, 0xa006, 0x00de, 0x00ee, + 0x002e, 0x001e, 0x0005, 0xa085, 0x0001, 0x0cc0, 0x00e6, 0x0036, + 0x2071, 0x9363, 0x7014, 0xa005, 0x0538, 0x8001, 0x7016, 0x7008, + 0xa080, 0x0003, 0x710c, 0x2110, 0x0411, 0x810c, 0xa118, 0x8210, + 0xa282, 0x0007, 0x11b0, 0x7008, 0x2004, 0xa005, 0x0178, 0x00d6, + 0x0006, 0x7008, 0x2068, 0x080c, 0x5b5c, 0x000e, 0x2068, 0x6807, + 0x0000, 0x700a, 0x00de, 0x7010, 0x8001, 0x7012, 0x700f, 0x0000, + 0x0008, 0x720e, 0x2308, 0xa006, 0x003e, 0x00ee, 0x0005, 0x0006, + 0x810b, 0x810b, 0x2100, 0x810b, 0xa100, 0x2008, 0x000e, 0x0005, + 0x0006, 0x0026, 0x2100, 0xa005, 0x0160, 0xa092, 0x000c, 0x0248, + 0x2009, 0x0000, 0x8108, 0xa082, 0x000c, 0x1de0, 0x002e, 0x000e, + 0x0005, 0x2009, 0x0000, 0x0cd0, 0x2d00, 0xa0b8, 0x0008, 0x690c, + 0x6810, 0x2019, 0x0001, 0x2031, 0x5ab2, 0xa112, 0x0220, 0x0118, + 0x8318, 0x2208, 0x0cd0, 0x6808, 0xa005, 0x0108, 0x8318, 0x233a, + 0x6804, 0xd084, 0x2300, 0x2021, 0x0001, 0x1150, 0xa082, 0x0003, + 0x0967, 0x0a67, 0x8420, 0xa082, 0x0007, 0x0967, 0x0a67, 0x0cd0, + 0xa082, 0x0002, 0x0967, 0x0a67, 0x8420, 0xa082, 0x0005, 0x0967, + 0x0a67, 0x0cd0, 0x6c1a, 0x2d00, 0xa0b8, 0x0007, 0x00e6, 0x2071, + 0x9200, 0x7128, 0x6810, 0x2019, 0x0001, 0xa10a, 0x0118, 0x0210, + 0x8318, 0x0cd8, 0x2031, 0x5ac5, 0x0870, 0x6c16, 0x00ee, 0x0005, + 0x00e6, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2e00, 0x2060, 0x2071, + 0x9363, 0x2009, 0x0001, 0x0026, 0x080c, 0x5976, 0x002e, 0x7300, + 0xa398, 0x0003, 0x7104, 0x080c, 0x5a67, 0x810c, 0x2100, 0xa318, + 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, 0x00d6, 0x2368, 0x1138, + 0x6000, 0x6802, 0x6004, 0x6806, 0x6008, 0x6812, 0x0050, 0x6000, + 0x6802, 0x6004, 0x6806, 0x6008, 0x680a, 0x600c, 0x680e, 0x6010, + 0x6812, 0x00de, 0x7014, 0x8000, 0x7016, 0x711c, 0x8109, 0x711e, + 0x7004, 0x8000, 0x2008, 0xa082, 0x0007, 0x1180, 0x7000, 0x2004, + 0xa005, 0x1140, 0x2009, 0x0001, 0x0026, 0x080c, 0x5976, 0x002e, + 0x7000, 0x2004, 0x7002, 0x7007, 0x0000, 0x0008, 0x7106, 0x012e, + 0x00ce, 0x00ee, 0x0005, 0x00d6, 0x0046, 0x0126, 0x2091, 0x8000, + 0x2001, 0x9281, 0xa080, 0x0011, 0x2004, 0x8003, 0x2020, 0x080c, + 0x145f, 0x01d0, 0x2d00, 0x7026, 0x6803, 0x0000, 0x6807, 0x0000, + 0x080c, 0x145f, 0x0188, 0x7024, 0x6802, 0x6807, 0x0000, 0x2d00, + 0x7026, 0xa4a2, 0x0007, 0x0110, 0x0208, 0x0c90, 0xa085, 0x0001, + 0x012e, 0x004e, 0x00de, 0x0005, 0x7024, 0xa005, 0x0dc8, 0x2068, + 0x2024, 0x080c, 0x1493, 0x2400, 0x0cc0, 0x0126, 0x2091, 0x8000, + 0x7024, 0x2068, 0xa005, 0x0130, 0x2004, 0x7026, 0x6803, 0x0000, + 0x6807, 0x0000, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7024, + 0x6802, 0x2d00, 0x7026, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0086, 0x0046, 0x0056, 0x0026, 0x2031, 0x0000, 0x2001, + 0x934a, 0x2004, 0xa005, 0x0904, 0x5bee, 0x2071, 0x9281, 0x20e1, + 0x0002, 0x3d08, 0xd19c, 0x0140, 0x2069, 0x9200, 0x6a28, 0x761c, + 0x7114, 0x2041, 0x0000, 0x0028, 0x7118, 0x720c, 0x7620, 0x7008, + 0x2040, 0x080c, 0x5d03, 0x0904, 0x5bee, 0x7004, 0xd084, 0x1128, + 0x2021, 0x0024, 0x2029, 0x0002, 0x0020, 0x2021, 0x002c, 0x2029, + 0x000a, 0x080c, 0x147c, 0x0904, 0x5bee, 0x2d00, 0x2060, 0x6436, + 0x0016, 0x20e1, 0x0001, 0x3d08, 0x3e00, 0xa18c, 0x00ff, 0x6142, + 0x603e, 0x001e, 0x6746, 0x2700, 0xa086, 0xff00, 0x1118, 0x6063, + 0x0000, 0x0010, 0x6063, 0x0003, 0xa006, 0x6002, 0x602a, 0x602e, + 0x6006, 0x603a, 0x604a, 0x6052, 0x6056, 0x605e, 0x6066, 0x604e, + 0x2800, 0x606a, 0x604c, 0xc0ad, 0x604e, 0x665a, 0x2c00, 0x2078, + 0x0479, 0x607f, 0xffff, 0x6083, 0x0000, 0x8109, 0x0180, 0x080c, + 0x147c, 0x01c0, 0x2d00, 0x7806, 0x2f00, 0x6802, 0x6d36, 0xa006, + 0x2d00, 0x2520, 0x00e9, 0x2d00, 0x2078, 0x8109, 0x1d80, 0x2c00, + 0xa005, 0x002e, 0x005e, 0x004e, 0x008e, 0x00ce, 0x00de, 0x00ee, + 0x00fe, 0x0005, 0x2c00, 0x2068, 0x080c, 0x14a3, 0x2600, 0x2071, + 0x9363, 0x7120, 0xa102, 0x0a0c, 0x13fe, 0x7022, 0xa006, 0x0c48, + 0x00d6, 0x00c6, 0x0136, 0x0146, 0x0156, 0x0016, 0x2068, 0x2400, + 0xa084, 0x000f, 0xa080, 0x1f59, 0x2005, 0x2005, 0xad60, 0x2c00, + 0x2d08, 0xa188, 0x0030, 0xa102, 0x20a8, 0x2c00, 0x20a0, 0x2001, + 0xffff, 0x40a4, 0x001e, 0x015e, 0x014e, 0x013e, 0x00ce, 0x00de, + 0x0005, 0x00c6, 0x00e6, 0x00f6, 0x6858, 0x2071, 0x9363, 0x7120, + 0xa102, 0x0a0c, 0x13fe, 0x7022, 0x6960, 0x694e, 0x697c, 0x2009, + 0xffff, 0x7818, 0xa102, 0xe000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x6852, 0x684b, + 0x0000, 0x6868, 0xa005, 0x0118, 0x6848, 0xc085, 0x684a, 0x2d00, + 0xa080, 0x0015, 0x2038, 0x2031, 0x0018, 0x6864, 0x2020, 0x683a, + 0x685c, 0xa08a, 0x00ff, 0x1a0c, 0x13fe, 0x2028, 0x2d00, 0x2060, + 0x2078, 0x6934, 0xa18c, 0x000f, 0xa188, 0x1f59, 0x2145, 0x685c, + 0x2050, 0xa005, 0x0530, 0x2805, 0xac70, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x0024, 0x1110, 0x7008, 0x0040, 0x6834, 0xa084, 0x00ff, + 0xa086, 0x002c, 0x190c, 0x13fe, 0x7010, 0x0006, 0x2400, 0xa005, + 0x000e, 0x0168, 0x203a, 0x8738, 0x8631, 0x090c, 0x13fe, 0x8421, + 0x8529, 0x0138, 0x080c, 0x1f1b, 0x090c, 0x13fe, 0x08e0, 0x080c, + 0x5ac8, 0x6837, 0x0023, 0x00fe, 0x00ee, 0x00ce, 0x0005, 0x00e6, + 0x00c6, 0x00a6, 0x0086, 0x0056, 0x6858, 0x2071, 0x9363, 0x7120, + 0xa102, 0x0a0c, 0x13fe, 0x7022, 0x2d00, 0x2060, 0x6934, 0xa18c, + 0x000f, 0xa188, 0x1f59, 0x2145, 0x685c, 0x2050, 0xa005, 0x01d0, + 0x2028, 0x2805, 0xac70, 0x6834, 0xa084, 0x00ff, 0xa086, 0x0024, + 0x1110, 0x7008, 0x0008, 0x7010, 0x0006, 0xa086, 0xffff, 0x000e, + 0x0110, 0x080c, 0x5ac8, 0x8529, 0x0128, 0x080c, 0x1f1b, 0x090c, + 0x13fe, 0x0c38, 0x005e, 0x008e, 0x00ae, 0x00ce, 0x00ee, 0x0005, + 0x70ac, 0xa005, 0x0138, 0x2060, 0x6008, 0xa306, 0x0110, 0x600c, + 0x0cc0, 0x0005, 0xa085, 0x0001, 0x0ce0, 0x70ac, 0x600e, 0x2c00, + 0x70ae, 0x0005, 0x00f6, 0x00d6, 0x0036, 0x70ac, 0xa005, 0x090c, + 0x13fe, 0x2068, 0x2079, 0x0000, 0x2c08, 0xa11e, 0x1118, 0x680c, + 0x70ae, 0x0060, 0xa106, 0x0140, 0x2d00, 0x2078, 0x680c, 0xa005, + 0x090c, 0x13fe, 0x2068, 0x0cb0, 0x6b0c, 0x7b0e, 0x600f, 0x0000, + 0x003e, 0x00de, 0x00fe, 0x0005, 0x00e6, 0x080c, 0x5c87, 0x6018, + 0x2070, 0xa006, 0x70b2, 0x70b6, 0x080c, 0x14a3, 0x0899, 0x080c, + 0x74f2, 0x00ee, 0x0005, 0x00d6, 0x0026, 0x0016, 0x2061, 0x9363, + 0x6020, 0x6414, 0xa600, 0xa42a, 0x02c8, 0x6022, 0x2069, 0x9281, + 0x6828, 0x6114, 0xa102, 0x1260, 0x2011, 0x8025, 0x080c, 0x3698, + 0xa080, 0x0013, 0x2004, 0xa080, 0x0000, 0x200c, 0x8108, 0x2102, + 0xa085, 0x0001, 0x001e, 0x002e, 0x00de, 0x0005, 0x2069, 0x9281, + 0x6804, 0xd09c, 0x0120, 0x2011, 0x8026, 0x080c, 0x3698, 0x2001, + 0x9281, 0xa080, 0x0013, 0x2004, 0xa080, 0x0001, 0x200c, 0x8108, + 0x2102, 0xa006, 0x2031, 0x0000, 0x0c28, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x5d56, 0x5d56, + 0x5d56, 0x5d58, 0x5db1, 0x5d56, 0x5d56, 0x5d56, 0x5de6, 0x5d56, + 0x5e34, 0x5d56, 0x5d56, 0x5d56, 0x5d56, 0x5d56, 0x080c, 0x13fe, + 0xa182, 0x0100, 0x0002, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6c, 0x5d85, + 0x5d9d, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, 0x5d6a, + 0x5d6a, 0x5d6a, 0x080c, 0x13fe, 0x00d6, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x684b, 0x0000, 0x00d6, 0x6018, 0x2068, + 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x080c, 0x641b, 0x00f6, + 0x00d6, 0x6110, 0x2178, 0x080c, 0x82ee, 0x0140, 0x784b, 0x0006, + 0xa006, 0x70b2, 0x70b6, 0x2f68, 0x080c, 0x4809, 0x00de, 0x00fe, + 0x080c, 0x74f2, 0x080c, 0x651c, 0x0005, 0x080c, 0x641b, 0x080c, + 0x266c, 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0120, 0x684b, + 0x0029, 0x080c, 0x4809, 0x00de, 0x080c, 0x74f2, 0x080c, 0x651c, + 0x0005, 0xa182, 0x0100, 0x0002, 0x5dc3, 0x5dc5, 0x5dcd, 0x5dc3, + 0x5dc3, 0x5dc3, 0x5de1, 0x5dc3, 0x5dc3, 0x5dc3, 0x5dc3, 0x5dc3, + 0x5dc3, 0x5dc3, 0x5dc3, 0x080c, 0x13fe, 0x20e1, 0x0005, 0x3d18, + 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00d6, 0x00e6, 0x6110, + 0x2168, 0x080c, 0x5c19, 0x080c, 0x4809, 0x6018, 0x2070, 0xa006, + 0x70b2, 0x70b6, 0x080c, 0x5cd2, 0x00ee, 0x00de, 0x080c, 0x74f2, + 0x0005, 0x080c, 0x5cf4, 0x080c, 0x473b, 0x0005, 0xa182, 0x0100, + 0x0002, 0x5dfb, 0x5e16, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, + 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, 0x5df9, + 0x5df9, 0x080c, 0x13fe, 0x00d6, 0x6003, 0x0003, 0x6106, 0x6010, + 0x2068, 0x687c, 0x680a, 0x6880, 0x680e, 0x6813, 0x0000, 0x6817, + 0x0000, 0x00de, 0x2c10, 0x080c, 0x1c88, 0x080c, 0x605b, 0x0126, + 0x2091, 0x8000, 0x080c, 0x651c, 0x012e, 0x0005, 0x6003, 0x0004, + 0x630a, 0x080c, 0x5b65, 0x0168, 0x6012, 0x600f, 0x0000, 0x080c, + 0x5ccd, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, + 0x0005, 0x2011, 0x0000, 0x080c, 0x16c6, 0x70b3, 0x0000, 0x70b7, + 0x0000, 0x080c, 0x74f2, 0x0005, 0x00d6, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x684b, 0x0000, 0x00d6, 0x6018, 0x2068, + 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x6000, 0xa08a, 0x0010, + 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x5e64, 0x5e64, 0x5e64, 0x5e66, + 0x5e7f, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x5e64, + 0x5e64, 0x5e64, 0x5e64, 0x5e64, 0x080c, 0x13fe, 0x080c, 0x7366, + 0x190c, 0x13fe, 0x6110, 0x2168, 0x684b, 0x0006, 0x00d6, 0x6018, + 0x2068, 0x6008, 0x68b6, 0x68bb, 0x0500, 0xa006, 0x68b2, 0x00de, + 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x0005, 0x0005, + 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x5e97, + 0x5e97, 0x5e97, 0x5e99, 0x5e9b, 0x5e97, 0x5e97, 0x5e97, 0x5e97, + 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x5e97, 0x080c, + 0x13fe, 0x080c, 0x13fe, 0x00d6, 0x6010, 0x2068, 0x080c, 0x5cf4, + 0x00de, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x1208, 0xa200, 0x1f04, 0x5ea6, 0x8086, 0x818e, 0x0005, 0x0156, + 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, + 0x0228, 0xa11a, 0x1220, 0x1f04, 0x5eb6, 0x0028, 0xa11a, 0x2308, + 0x8210, 0x1f04, 0x5eb6, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, + 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, + 0x0126, 0x2091, 0x2400, 0x2079, 0x94e5, 0x012e, 0x00d6, 0x2069, + 0x94e5, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, + 0x206a, 0x00de, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, 0xa084, + 0x0007, 0x0002, 0x5ef4, 0x5f15, 0x5f68, 0x5efa, 0x5f15, 0x5ef4, + 0x5ef2, 0x5ef2, 0x080c, 0x13fe, 0x080c, 0x57a1, 0x080c, 0x6462, + 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, 0x2011, + 0x40af, 0x080c, 0x5731, 0x7828, 0xa092, 0x0002, 0x1228, 0x8000, + 0x782a, 0x080c, 0x40fc, 0x0c88, 0x080c, 0x40af, 0x7807, 0x0003, + 0x7827, 0x0000, 0x782b, 0x0000, 0x0c40, 0x080c, 0x57a1, 0x3c00, + 0x0006, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x000e, 0x20e0, + 0x82ff, 0x0178, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, + 0xa065, 0x090c, 0x13fe, 0x2009, 0x0013, 0x080c, 0x7518, 0x00ce, + 0x0005, 0x3900, 0xa082, 0x9606, 0x1210, 0x080c, 0x7432, 0x00c6, + 0x7824, 0xa065, 0x090c, 0x13fe, 0x7804, 0xa086, 0x0004, 0x0904, + 0x5fa8, 0x7828, 0xa092, 0x2710, 0x1230, 0x8000, 0x782a, 0x00ce, + 0x080c, 0x6f11, 0x0c20, 0x6104, 0xa186, 0x0003, 0x1188, 0x00e6, + 0x2071, 0x9200, 0x70d4, 0x00ee, 0xd08c, 0x0150, 0x00c6, 0x00e6, + 0x2061, 0x0100, 0x2071, 0x9200, 0x080c, 0x4105, 0x00ee, 0x00ce, + 0x080c, 0x91a0, 0x2009, 0x0014, 0x080c, 0x7518, 0x00ce, 0x0838, + 0x2001, 0x9501, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, + 0x0000, 0x7824, 0xa065, 0x090c, 0x13fe, 0x2009, 0x0013, 0x080c, + 0x7563, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082, 0x9606, + 0x1210, 0x080c, 0x7432, 0x7824, 0xa005, 0x090c, 0x13fe, 0x781c, + 0xa06d, 0x090c, 0x13fe, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, + 0x080c, 0x74f2, 0x693c, 0x81ff, 0x090c, 0x13fe, 0x8109, 0x693e, + 0x6854, 0xa015, 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, 0x7807, + 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, 0x080c, 0x6462, 0x0888, + 0x6104, 0xa186, 0x0002, 0x0128, 0xa186, 0x0004, 0x0110, 0x0804, + 0x5f41, 0x7808, 0xac06, 0x0904, 0x5f41, 0x080c, 0x6389, 0x080c, + 0x603e, 0x00ce, 0x080c, 0x6462, 0x0804, 0x5f2f, 0x00c6, 0x6027, + 0x0002, 0x62c8, 0x60c4, 0xa205, 0x11a0, 0x793c, 0xa1e5, 0x0000, + 0x0150, 0x2009, 0x0049, 0x601c, 0xa086, 0x0009, 0x1110, 0x2009, + 0x0103, 0x080c, 0x7518, 0x2011, 0x9504, 0x2013, 0x0000, 0x00ce, + 0x0005, 0x3908, 0xa192, 0x9606, 0x1210, 0x080c, 0x7432, 0x6017, + 0x0010, 0x793c, 0x81ff, 0x0d78, 0x793c, 0xa188, 0x0007, 0x210c, + 0xa18e, 0x0006, 0x1118, 0x6017, 0x0012, 0x0c48, 0x793c, 0xa188, + 0x0007, 0x210c, 0xa18e, 0x0009, 0x0db0, 0x6017, 0x0016, 0x08f8, + 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, + 0x2c08, 0x2061, 0x94e5, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, + 0x0148, 0xa080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, + 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0x94e5, + 0x6000, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, + 0x1110, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0804, 0x646f, + 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0158, 0x6056, 0x605b, 0x0000, + 0x0006, 0x2c00, 0x681a, 0x00de, 0x685a, 0x2069, 0x94e5, 0x0c18, + 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x94e5, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0148, 0xa080, + 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, + 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, + 0x94e5, 0x6034, 0xa005, 0x0130, 0xa080, 0x0003, 0x2102, 0x6136, + 0x00ce, 0x0005, 0x613a, 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, + 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, 0x2071, 0x94e5, + 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, 0x60cb, + 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x60c6, 0x88ff, + 0x0118, 0x6020, 0xa106, 0x15d0, 0x703c, 0xac06, 0x1120, 0x6003, + 0x000a, 0x630a, 0x0498, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, + 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, + 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x82ee, 0x0188, + 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x00ce, 0x0804, 0x607d, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x607d, 0x012e, 0x000e, 0x001e, 0x002e, 0x006e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, + 0x19e8, 0x080c, 0x9097, 0x0c28, 0x0006, 0x0066, 0x00c6, 0x00d6, + 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, 0x94e5, + 0x7838, 0xa065, 0x0510, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, + 0xac06, 0x1128, 0x6003, 0x000a, 0x630a, 0x2c30, 0x00a0, 0x080c, + 0x82ee, 0x0178, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x11b0, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x000e, 0x08e0, 0x7e3a, 0x7e36, 0x012e, + 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, 0xa086, + 0x0006, 0x0150, 0x601c, 0xa086, 0x0009, 0x1d10, 0x6b4a, 0x080c, + 0x4809, 0x080c, 0x74f2, 0x0c38, 0x080c, 0x9097, 0x0c10, 0x0016, + 0x0026, 0x0086, 0x2041, 0x0000, 0x0099, 0x080c, 0x61d3, 0x008e, + 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, 0x2079, 0x94e5, 0x2091, + 0x8000, 0x080c, 0x625e, 0x080c, 0x62be, 0x012e, 0x00fe, 0x0005, + 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2071, 0x94e5, 0x7614, 0x2660, 0x2678, 0x8cff, + 0x0904, 0x61c3, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, + 0x61be, 0x88ff, 0x0120, 0x6020, 0xa106, 0x1904, 0x61be, 0x7024, + 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, + 0x57a1, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, 0x7027, + 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, + 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, + 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, + 0x04a8, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, + 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, + 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0178, + 0x601c, 0xa086, 0x0003, 0x1500, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, 0x848f, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x0804, 0x614f, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x614f, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19e0, + 0x080c, 0x9097, 0x0c20, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, + 0xa280, 0x936e, 0x2004, 0xa065, 0x0904, 0x625a, 0x00f6, 0x00e6, + 0x00d6, 0x0066, 0x2071, 0x94e5, 0x6654, 0x7018, 0xac06, 0x1108, + 0x761a, 0x701c, 0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, + 0x0008, 0x761e, 0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000, + 0x0110, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, + 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x43ba, 0x0904, 0x6256, 0x7624, + 0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, + 0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x57a1, 0x080c, + 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, 0x7027, 0x0000, 0x0036, + 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, + 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, + 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, + 0x603e, 0x2660, 0x080c, 0x849b, 0x00ce, 0x0048, 0x00de, 0x00c6, + 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6203, 0x8dff, + 0x0148, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x8527, + 0x080c, 0x4809, 0x080c, 0x7238, 0x0804, 0x6203, 0x006e, 0x00de, + 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005, 0x0006, 0x0066, + 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065, 0x0904, 0x62b0, + 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06, 0x1540, 0x2069, + 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x57a1, 0x080c, 0x6f1e, + 0x68c3, 0x0000, 0x080c, 0x7356, 0x7827, 0x0000, 0x0036, 0x2069, + 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, + 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, + 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00b0, 0x6010, + 0x2068, 0x080c, 0x82ee, 0x0168, 0x601c, 0xa086, 0x0003, 0x11b8, + 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, + 0x848f, 0x080c, 0x849b, 0x080c, 0x7238, 0x000e, 0x0804, 0x6265, + 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, + 0xa086, 0x0006, 0x1d28, 0x080c, 0x9097, 0x0c58, 0x0006, 0x0066, + 0x00c6, 0x00d6, 0x7818, 0xa065, 0x0904, 0x6324, 0x6054, 0x0006, + 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, + 0x080c, 0x43ba, 0x0904, 0x6321, 0x7e24, 0x86ff, 0x05e8, 0xa680, + 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x0548, 0x080c, 0x57a1, 0x080c, 0x6f1e, 0x68c3, 0x0000, + 0x080c, 0x7356, 0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, + 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, + 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, + 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, 0x080c, + 0x849b, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x0804, 0x62d0, 0x8dff, 0x0138, 0x6837, 0x0103, + 0x6b4a, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x7238, 0x0804, + 0x62d0, 0x000e, 0x0804, 0x62c3, 0x781e, 0x781a, 0x00de, 0x00ce, + 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6, 0x0066, 0x6000, 0xd0dc, + 0x0188, 0x604c, 0xa06d, 0x0170, 0x6848, 0xa606, 0x1158, 0x2071, + 0x94e5, 0x7024, 0xa035, 0x0130, 0xa080, 0x0004, 0x2004, 0xad06, + 0x1108, 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, + 0x0100, 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, + 0x630a, 0x00ce, 0x04a0, 0x080c, 0x6f1e, 0x78c3, 0x0000, 0x080c, + 0x7356, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0xa384, + 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, + 0x7824, 0xd084, 0x0110, 0x7827, 0x0001, 0x080c, 0x7356, 0x003e, + 0x080c, 0x43ba, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, + 0x2660, 0x080c, 0x74f2, 0x00ce, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x8527, 0x080c, 0x4809, 0x080c, 0x7238, 0x00fe, + 0x0005, 0x00e6, 0x00c6, 0x2071, 0x94e5, 0x7004, 0xa084, 0x0007, + 0x0002, 0x639b, 0x639e, 0x63b4, 0x63cd, 0x6406, 0x639b, 0x6399, + 0x6399, 0x080c, 0x13fe, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0150, 0x7216, + 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, + 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, 0x080c, 0x43ba, + 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0120, 0x6054, + 0xa015, 0x0140, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, + 0x00ee, 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, 0xa065, 0x0598, + 0x700c, 0xac06, 0x1160, 0x080c, 0x7238, 0x600c, 0xa015, 0x0120, + 0x720e, 0x600f, 0x0000, 0x0428, 0x720e, 0x720a, 0x0410, 0x7014, + 0xac06, 0x1160, 0x080c, 0x7238, 0x600c, 0xa015, 0x0120, 0x7216, + 0x600f, 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098, 0x6018, 0x2060, + 0x080c, 0x43ba, 0x6000, 0xc0dc, 0x6002, 0x080c, 0x7238, 0x701c, + 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, 0x721e, 0x0010, 0x7218, + 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, + 0x0140, 0x080c, 0x7238, 0x600c, 0xa015, 0x0150, 0x720e, 0x600f, + 0x0000, 0x080c, 0x7356, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, + 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, 0x94e5, 0x6830, 0xa084, + 0x0003, 0x0002, 0x6428, 0x642a, 0x644a, 0x6426, 0x080c, 0x13fe, + 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, 0x0001, 0x0198, 0x683c, + 0xa065, 0x0130, 0x600c, 0xa015, 0x0150, 0x6a3a, 0x600f, 0x0000, + 0x6833, 0x0000, 0x683f, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, + 0x6836, 0x0cb0, 0x6843, 0x0000, 0x6838, 0xa065, 0x0d88, 0x6003, + 0x0003, 0x0c70, 0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, + 0xa065, 0x0168, 0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f, 0x0000, + 0x683f, 0x0000, 0x0020, 0x683f, 0x0000, 0x683a, 0x6836, 0x00ce, + 0x00de, 0x0005, 0x00d6, 0x2001, 0x9295, 0x2004, 0xd084, 0x0110, + 0x00de, 0x0005, 0x2069, 0x94e5, 0x6804, 0xa084, 0x0007, 0x0002, + 0x647a, 0x650c, 0x650c, 0x650c, 0x650c, 0x650e, 0x6478, 0x6478, + 0x080c, 0x13fe, 0x6820, 0xa005, 0x1110, 0x00de, 0x0005, 0x00c6, + 0x680c, 0xa065, 0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, + 0x080c, 0x656d, 0x00ce, 0x00de, 0x0005, 0x6814, 0xa065, 0x0150, + 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x656d, 0x00ce, + 0x00de, 0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5, 0x0000, 0x0904, + 0x6508, 0x704c, 0xa00d, 0x0118, 0x7088, 0xa005, 0x01a0, 0x7054, + 0xa075, 0x0120, 0xa20e, 0x0904, 0x6508, 0x0028, 0x6818, 0xa20e, + 0x0904, 0x6508, 0x2070, 0x704c, 0xa00d, 0x0d88, 0x7088, 0xa005, + 0x1d70, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, 0x1e40, 0x080c, + 0x74c9, 0x0904, 0x6508, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, + 0xa180, 0x0015, 0x2004, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, + 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x00f6, 0x2c78, + 0x71a0, 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1110, 0xd1bc, 0x0150, + 0x7100, 0xd1f4, 0x0120, 0x7114, 0xa18c, 0x00ff, 0x0040, 0x2009, + 0x0000, 0x0028, 0xa1e0, 0x2719, 0x2c0d, 0xa18c, 0x00ff, 0x2061, + 0x0100, 0x619a, 0x080c, 0x6a46, 0x7300, 0xc3dd, 0x7302, 0x6807, + 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, + 0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00ce, 0x00de, 0x0005, + 0x003e, 0x00ee, 0x00ce, 0x0cd0, 0x00de, 0x0005, 0x00c6, 0x680c, + 0xa065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, + 0x656d, 0x00ce, 0x00de, 0x0005, 0x00f6, 0x00d6, 0x2069, 0x94e5, + 0x6830, 0xa086, 0x0000, 0x1590, 0x6838, 0xa07d, 0x0578, 0x781c, + 0xa086, 0x0009, 0x1140, 0x7808, 0xd0fc, 0x0128, 0x2001, 0x94e6, + 0x2004, 0xa005, 0x1518, 0x2f00, 0x6833, 0x0001, 0x683e, 0x6847, + 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1d0f, + 0x11c0, 0x012e, 0xe000, 0xe000, 0xe000, 0x6a3c, 0x2278, 0x781c, + 0xa086, 0x0009, 0x1148, 0x7808, 0xd0fc, 0x0118, 0x080c, 0x6cf9, + 0x0028, 0x080c, 0x6d75, 0x0010, 0x080c, 0x6dec, 0x00de, 0x00fe, + 0x0005, 0x012e, 0xe000, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, + 0xa015, 0x0140, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, + 0x0000, 0x0c60, 0x683a, 0x6836, 0x0cc0, 0x601c, 0xa084, 0x000f, + 0x000b, 0x0005, 0x657b, 0x6580, 0x68f8, 0x6a03, 0x6580, 0x68f8, + 0x6a03, 0x657b, 0x6580, 0x080c, 0x6389, 0x080c, 0x6462, 0x0005, + 0x0156, 0x0136, 0x0146, 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x003e, + 0x1a0c, 0x13fe, 0x6118, 0x2178, 0x79a0, 0x2011, 0x9232, 0x2214, + 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, + 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, 0x2719, + 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0x0033, + 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x65f5, 0x662d, + 0x6647, 0x66fa, 0x6725, 0x672d, 0x674e, 0x675f, 0x6770, 0x6778, + 0x6789, 0x6778, 0x67ce, 0x675f, 0x67ef, 0x67f7, 0x6770, 0x67f7, + 0x6808, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, + 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x6fda, 0x6fef, 0x7012, + 0x7036, 0x674e, 0x65ec, 0x674e, 0x6778, 0x65ec, 0x6647, 0x66fa, + 0x65ec, 0x744f, 0x6778, 0x65ec, 0x746f, 0x6778, 0x65ec, 0x6770, + 0x65ee, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, 0x65ec, + 0x65ec, 0x65ec, 0x65ec, 0x704b, 0x080c, 0x13fe, 0x2001, 0x9214, + 0x2004, 0x609a, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x5200, 0x20a3, 0x0000, 0x00d6, 0x2069, 0x9251, + 0x6804, 0xd084, 0x0150, 0x6828, 0x20a3, 0x0000, 0x0016, 0x080c, + 0x241f, 0x21a2, 0x001e, 0x00de, 0x0028, 0x00de, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x9205, 0x53a6, 0x20a9, + 0x0004, 0x2099, 0x9201, 0x53a6, 0x20a3, 0x0000, 0x2001, 0x9214, + 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x001c, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x2001, 0x921b, 0x2004, + 0x20a2, 0x2001, 0x921c, 0x2004, 0x20a2, 0x20a9, 0x0004, 0x2099, + 0x9205, 0x53a6, 0x60c3, 0x0010, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x681d, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, + 0x007e, 0x1130, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0010, + 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, + 0xa086, 0x007e, 0x1904, 0x66bc, 0x2001, 0x9232, 0x2004, 0xd0a4, + 0x01c8, 0x2099, 0x94c7, 0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, + 0x3304, 0xa084, 0x2000, 0x20a2, 0x9398, 0x33a6, 0x9398, 0x20a3, + 0x0000, 0x9398, 0x2001, 0x2710, 0x20a2, 0x9398, 0x33a6, 0x9398, + 0x33a6, 0x00d0, 0x2099, 0x94c7, 0x33a6, 0x9398, 0x33a6, 0x9398, + 0x3304, 0x080c, 0x4dc5, 0x1118, 0xa084, 0x37ff, 0x0010, 0xa084, + 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0x9205, + 0x53a6, 0x20a9, 0x0004, 0x2099, 0x9201, 0x53a6, 0x20a9, 0x0008, + 0x20a3, 0x0000, 0x1f04, 0x66a8, 0x20a9, 0x0008, 0x20a3, 0x0000, + 0x1f04, 0x66ae, 0x2099, 0x94cf, 0x33a6, 0x20a9, 0x0007, 0x20a3, + 0x0000, 0x1f04, 0x66b7, 0x0468, 0x2001, 0x9232, 0x2004, 0xd0a4, + 0x0140, 0x2001, 0x94c8, 0x2004, 0x60e3, 0x0000, 0x080c, 0x2460, + 0x60e2, 0x2099, 0x94c7, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, + 0x2099, 0x9205, 0x53a6, 0x20a9, 0x0004, 0x2099, 0x9201, 0x53a6, + 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x66da, 0x20a9, 0x0008, + 0x20a3, 0x0000, 0x1f04, 0x66e0, 0x2099, 0x94cf, 0x20a9, 0x0008, + 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x66eb, 0x20a9, + 0x000a, 0x20a3, 0x0000, 0x1f04, 0x66f1, 0x60c3, 0x0074, 0x080c, + 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, 0x681d, 0x20a3, 0x2010, + 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0x9251, 0x7904, + 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, + 0x0010, 0xa085, 0x0002, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x5000, 0x0804, 0x665a, 0x20a1, 0x020b, 0x080c, + 0x681d, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x0804, 0x665a, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, + 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x6f0b, + 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0210, + 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, 0x2068, 0x6894, 0xa086, + 0x0014, 0x1178, 0x6998, 0xa184, 0xc000, 0x1140, 0xd1ec, 0x0118, + 0x20a3, 0x2100, 0x0040, 0x20a3, 0x0100, 0x0028, 0x20a3, 0x0400, + 0x0010, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, + 0x20a2, 0x00f6, 0x2079, 0x9251, 0x7904, 0x00fe, 0xd1ac, 0x1110, + 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0x2009, 0x9273, + 0x210c, 0xd184, 0x1110, 0xa085, 0x0002, 0x20a2, 0x20a2, 0x20a2, + 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x00de, 0x0005, 0x20a1, 0x020b, + 0x080c, 0x68a0, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0000, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x6f0b, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x0804, 0x65fb, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, + 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x080c, 0x68a0, + 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, 0x0000, + 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x0005, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, + 0x1198, 0x20a3, 0x22ff, 0x20a3, 0xfffe, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x2001, 0x94d7, 0x2004, 0xa005, 0x0118, 0x2011, + 0x921c, 0x2214, 0x22a2, 0x0498, 0xa286, 0x007f, 0x1130, 0x00d6, + 0x20a3, 0x22ff, 0x20a3, 0xfffd, 0x00c8, 0x2001, 0x9232, 0x2004, + 0xd0ac, 0x1110, 0xd2bc, 0x01c8, 0xa286, 0x0080, 0x00d6, 0x1128, + 0x20a3, 0x22ff, 0x20a3, 0xfffc, 0x0048, 0xa2e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x2200, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x2200, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, + 0x0129, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, + 0x2011, 0xfffc, 0x22a2, 0x00d6, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x08e0, 0x20a3, + 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x0005, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, + 0x02e0, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x2300, + 0x20a2, 0x6814, 0x20a2, 0x6810, 0xa005, 0x1140, 0x6814, 0xa005, + 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x2300, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, + 0x0198, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, + 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, + 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x13fe, 0xa08a, + 0x008c, 0x1a0c, 0x13fe, 0x6118, 0x2178, 0x79a0, 0x2011, 0x9232, + 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, + 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, + 0x2719, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, + 0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x692f, 0x6939, + 0x6954, 0x692d, 0x692d, 0x692d, 0x692f, 0x080c, 0x13fe, 0x0146, + 0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000, 0x080c, 0x6f0b, 0x014e, + 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6999, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, + 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, + 0x080c, 0x6f0b, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, + 0x69d1, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x60c3, 0x0004, 0x080c, 0x6f0b, 0x014e, 0x0005, 0x0026, + 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, + 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, + 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0050, 0x20a3, 0x8100, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0804, + 0x6873, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, + 0x007e, 0x0288, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, + 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0050, 0x20a3, 0x8400, 0x6298, 0x22a2, 0x20a3, + 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x080c, 0x4dc5, 0x1118, + 0x20a3, 0x0099, 0x0010, 0x20a3, 0x00d1, 0x20a3, 0x0000, 0x0804, + 0x68e9, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, + 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1118, 0xa092, + 0x007e, 0x0288, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, + 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, + 0x2da6, 0x00de, 0x0050, 0x20a3, 0x8500, 0x6298, 0x22a2, 0x20a3, + 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0099, 0x20a3, + 0x0000, 0x0804, 0x68e9, 0x00c6, 0x00f6, 0x2c78, 0x7804, 0xa08a, + 0x0040, 0x0a0c, 0x13fe, 0xa08a, 0x0053, 0x1a0c, 0x13fe, 0x7918, + 0x2160, 0x61a0, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1110, 0xd1bc, + 0x0150, 0x6100, 0xd1f4, 0x0120, 0x6114, 0xa18c, 0x00ff, 0x0040, + 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2719, 0x2c0d, 0xa18c, 0x00ff, + 0x2061, 0x0100, 0x619a, 0xa082, 0x0040, 0x001b, 0x00fe, 0x00ce, + 0x0005, 0x6a46, 0x6b3a, 0x6ade, 0x6c75, 0x6a44, 0x6a44, 0x6a44, + 0x6a44, 0x6a44, 0x6a44, 0x6a44, 0x71f1, 0x7201, 0x7211, 0x7221, + 0x6a44, 0x6a44, 0x6a44, 0x71e0, 0x080c, 0x13fe, 0x00d6, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7910, 0x2168, 0x6948, + 0x7922, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, + 0x000f, 0x1118, 0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, + 0x0004, 0x0018, 0xa084, 0x0006, 0x8004, 0x20a2, 0xd1ac, 0x0118, + 0x20a3, 0x0002, 0x0048, 0xd1b4, 0x0118, 0x20a3, 0x0001, 0x0020, + 0x20a3, 0x0000, 0x2230, 0x0010, 0x6a80, 0x6e7c, 0x20a9, 0x0008, + 0x0136, 0xad88, 0x0017, 0x2198, 0x20a1, 0x021b, 0x53a6, 0x013e, + 0x20a1, 0x020b, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, + 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0x9501, + 0x2003, 0x07d0, 0x2001, 0x9500, 0x2003, 0x0009, 0x080c, 0x165a, + 0x014e, 0x015e, 0x00de, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, + 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0x2019, 0x9232, 0x231c, + 0xd3ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0600, 0x6198, + 0x21a2, 0x20a3, 0x0000, 0x2009, 0x9214, 0x210c, 0x21a2, 0x20a3, + 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, + 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, 0x00d6, 0x0156, + 0x0136, 0x0146, 0x20a1, 0x020b, 0x00c1, 0x7810, 0x2068, 0x6860, + 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, + 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, 0x080c, 0x6f0b, + 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0026, 0x20e1, 0x9080, + 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0x9232, + 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, + 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, + 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0500, + 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, + 0x20a3, 0x0889, 0x20a3, 0x0000, 0x080c, 0x6efa, 0x22a2, 0x20a3, + 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, + 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1, 0x020b, + 0x080c, 0x6c38, 0x7810, 0x2068, 0xa016, 0x22a2, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000, 0x1130, 0x7810, 0xa084, + 0x0700, 0x8007, 0x0043, 0x0010, 0xa006, 0x002b, 0x014e, 0x013e, + 0x015e, 0x00de, 0x0005, 0x6b65, 0x6bde, 0x6be1, 0x6c04, 0x6c11, + 0x6c23, 0x6c26, 0x6b63, 0x080c, 0x13fe, 0x0016, 0x0036, 0x694c, + 0xa18c, 0x0003, 0xa186, 0x0000, 0x1150, 0x6b78, 0x23a2, 0x6868, + 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, 0x6c08, 0xa186, + 0x0001, 0x1904, 0x6bd9, 0x6b78, 0x23a2, 0x6868, 0x20a2, 0x6864, + 0x20a2, 0x22a2, 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, + 0x0018, 0xa384, 0x0300, 0x0904, 0x6bd8, 0xd3c4, 0x0110, 0x687c, + 0xa108, 0xd3cc, 0x0110, 0x6874, 0xa108, 0x0156, 0x20a9, 0x000d, + 0xad80, 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x1f04, 0x6b9a, + 0x015e, 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0588, 0x20a1, + 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, + 0x0028, 0x2004, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, + 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, + 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0700, 0x6298, + 0x22a2, 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x000e, + 0x20a3, 0x0898, 0x20a2, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x61c2, 0x003e, 0x001e, 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0008, + 0x0428, 0x20a3, 0x0302, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, + 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, + 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, + 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, + 0x0032, 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0028, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x080c, 0x6f0b, + 0x0005, 0x20a3, 0x0100, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, + 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, + 0x080c, 0x6f0b, 0x0005, 0x20a3, 0x0008, 0x0c00, 0x0036, 0x7b10, + 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x1118, 0x22a2, + 0x003e, 0x08a0, 0x20a3, 0x0800, 0x22a2, 0x20a2, 0x003e, 0x0880, + 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, + 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, + 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, + 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, 0x8d68, 0x2da6, 0x00de, + 0x0050, 0x20a3, 0x0700, 0x6298, 0x22a2, 0x20a3, 0x0000, 0x2011, + 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0898, 0x20a3, 0x0000, 0x080c, + 0x6efa, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, + 0x0146, 0x0016, 0x0036, 0x7810, 0xa084, 0x0700, 0x8007, 0x003b, + 0x003e, 0x001e, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x6c8f, + 0x6c8f, 0x6c91, 0x6c8f, 0x6c8f, 0x6c8f, 0x6cb3, 0x6c8f, 0x080c, + 0x13fe, 0x7910, 0xa18c, 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, + 0x020b, 0x2009, 0x0003, 0x00f9, 0x00d6, 0x2069, 0x9251, 0x6804, + 0xd0bc, 0x0130, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0010, + 0x20a3, 0x3f00, 0x00de, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, + 0x080c, 0x6f0b, 0x0005, 0x20a1, 0x020b, 0x2009, 0x0003, 0x0019, + 0x20a3, 0x7f00, 0x0c80, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, + 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0x9232, 0x2214, 0xd2ac, + 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0x936e, 0x2d6c, 0x6810, + 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0x921b, 0x2da6, + 0x8d68, 0x2da6, 0x00de, 0x0050, 0x20a3, 0x0100, 0x6298, 0x22a2, + 0x20a3, 0x0000, 0x2011, 0x9214, 0x2214, 0x22a2, 0x20a3, 0x0888, + 0xa18d, 0x0008, 0x21a2, 0x080c, 0x6efa, 0x22a2, 0x20a3, 0x0000, + 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, + 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, 0x0046, 0x0036, + 0x2061, 0x0100, 0x2071, 0x9200, 0x2009, 0x9214, 0x210c, 0x7818, + 0x2068, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x0110, 0x736c, + 0x7470, 0x2500, 0x2031, 0x9232, 0x2634, 0xa6b4, 0x0028, 0x0140, + 0x2001, 0x04ff, 0x6062, 0x6067, 0xffff, 0x636a, 0x646e, 0x0050, + 0x2001, 0x00ff, 0xa085, 0x0400, 0x6062, 0x6067, 0xffff, 0x606b, + 0x0000, 0x616e, 0x68b8, 0x6072, 0x6077, 0x0008, 0x688c, 0x8000, + 0xa084, 0x00ff, 0x688e, 0x8007, 0xa085, 0x0020, 0x607a, 0x68b4, + 0x607f, 0x0000, 0x2d00, 0x6082, 0x6087, 0xffff, 0x7810, 0x2070, + 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, + 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, + 0x2001, 0x9232, 0x2004, 0xd09c, 0x0128, 0x609f, 0x0000, 0x2001, + 0x0012, 0x0048, 0x6028, 0xc0bd, 0x602a, 0x609f, 0x00ff, 0x6027, + 0xffff, 0x2001, 0x0032, 0x6016, 0x2009, 0x07d0, 0x080c, 0x57a6, + 0x2001, 0x9295, 0x200c, 0xc185, 0x2102, 0x003e, 0x004e, 0x005e, + 0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, + 0x0066, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x9200, + 0x2009, 0x9214, 0x210c, 0x7818, 0x2068, 0x68a0, 0x2028, 0x2031, + 0x9232, 0x2634, 0xd6ac, 0x1140, 0xd0bc, 0x1130, 0xa080, 0x2719, + 0x2015, 0xa294, 0x00ff, 0x0020, 0x6910, 0x6a14, 0x736c, 0x7470, + 0x2001, 0x9232, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, + 0x0400, 0x6062, 0x6266, 0x636a, 0x646e, 0x0030, 0x6063, 0x0400, + 0x6266, 0x606b, 0x0000, 0x616e, 0x68b8, 0x6072, 0x6077, 0x0008, + 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0xa085, 0x0020, + 0x607a, 0x68b4, 0x607f, 0x0000, 0x2d00, 0x6082, 0x6087, 0xffff, + 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, + 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, + 0x60d7, 0x0000, 0xa582, 0x0080, 0x0210, 0x2011, 0x0000, 0x629e, + 0x00f6, 0x2079, 0x0140, 0x7803, 0x0000, 0x00fe, 0x6017, 0x0012, + 0x2009, 0x07d0, 0x080c, 0x57a6, 0x003e, 0x004e, 0x005e, 0x006e, + 0x00ce, 0x00de, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0056, + 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x9200, 0x7150, 0x7818, + 0x2068, 0x68a0, 0x2028, 0x76c8, 0xd6ac, 0x1140, 0xd0bc, 0x1130, + 0xa080, 0x2719, 0x2015, 0xa294, 0x00ff, 0x0020, 0x6910, 0x6a14, + 0x736c, 0x7470, 0x781c, 0xa086, 0x0006, 0x0904, 0x6e65, 0x70c8, + 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, + 0x636a, 0x646e, 0x0030, 0x6063, 0x0100, 0x6266, 0x606b, 0x0000, + 0x616e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, + 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, + 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, + 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, + 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, + 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, + 0x629e, 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, + 0xa005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x57a6, 0x003e, 0x004e, + 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x7810, 0x2070, 0x704c, + 0xa084, 0x0003, 0xa086, 0x0002, 0x0904, 0x6eb4, 0x2001, 0x9232, + 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, + 0x6266, 0x636a, 0x646e, 0x0030, 0x6063, 0x0100, 0x6266, 0x606b, + 0x0000, 0x616e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, + 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, + 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, + 0x60c6, 0x707c, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, + 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, + 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, + 0x6017, 0x0012, 0x0804, 0x6e53, 0x2001, 0x9232, 0x2004, 0xd0ac, + 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, + 0x646e, 0x0030, 0x6063, 0x0700, 0x6266, 0x606b, 0x0000, 0x616e, + 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, + 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, + 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, + 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, + 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, + 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x6017, 0x0016, + 0x0804, 0x6e53, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, + 0x00ff, 0x2202, 0x8217, 0x0005, 0x00d6, 0x2069, 0x94e5, 0x6843, + 0x0001, 0x00de, 0x0005, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, + 0x9575, 0x0019, 0x080c, 0x5798, 0x0005, 0x0006, 0x6014, 0xa084, + 0x0004, 0xa085, 0x0009, 0x6016, 0x000e, 0x0005, 0x0006, 0x00c6, + 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, + 0x00ce, 0x000e, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x080c, + 0x57a1, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, 0x4000, + 0x0538, 0x0c21, 0x6803, 0x1000, 0x6803, 0x0000, 0x00c6, 0x2061, + 0x94e5, 0x6128, 0xa192, 0x0002, 0x1250, 0x8108, 0x612a, 0x6124, + 0x00ce, 0x81ff, 0x0180, 0x080c, 0x5798, 0x0839, 0x0060, 0x6124, + 0xa1e5, 0x0000, 0x0130, 0x080c, 0x91a0, 0x2009, 0x0014, 0x080c, + 0x7518, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, + 0x080c, 0x4dc5, 0x1118, 0x080c, 0x6f1e, 0x08c0, 0x080c, 0x4105, + 0x0c90, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x57ae, + 0x2071, 0x94e5, 0x713c, 0x81ff, 0x0578, 0x2061, 0x0100, 0x2069, + 0x0140, 0x6904, 0xa194, 0x4000, 0x0568, 0x6803, 0x1000, 0x6803, + 0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, 0x003e, 0x713c, + 0x2160, 0x080c, 0x91a0, 0x2009, 0x004a, 0x621c, 0xa296, 0x0009, + 0x1110, 0x2009, 0x0104, 0x080c, 0x7518, 0x080c, 0x4dc5, 0x1160, + 0x0006, 0x2001, 0x94d8, 0x2003, 0x0002, 0x2001, 0x9200, 0x2003, + 0x0001, 0x080c, 0x4d10, 0x000e, 0x002e, 0x001e, 0x00ee, 0x00de, + 0x00ce, 0x0005, 0x08b0, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, + 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, + 0x2071, 0x94e5, 0x7018, 0x2068, 0x8dff, 0x0198, 0x68a0, 0xa406, + 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6010, 0x2060, 0x643c, 0x6540, + 0x6e48, 0x2d60, 0x080c, 0x457f, 0x0120, 0x080c, 0x7238, 0xa085, + 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x681d, + 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, + 0x60c3, 0x0008, 0x080c, 0x6f0b, 0x014e, 0x015e, 0x0005, 0x0156, + 0x0146, 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, + 0x0000, 0x20a9, 0x0006, 0x2011, 0x9240, 0x2019, 0x9241, 0x23a6, + 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x6fff, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x6f0b, 0x014e, + 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, + 0x080c, 0x6881, 0x080c, 0x6897, 0x7810, 0x0006, 0xa080, 0x0015, + 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0xa080, 0x0004, + 0x8003, 0x60c2, 0x000e, 0xa080, 0x0001, 0x2004, 0x7812, 0x080c, + 0x6f0b, 0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, + 0x20a1, 0x020b, 0x080c, 0x681d, 0x20a3, 0x6200, 0x20a3, 0x0000, + 0x20a3, 0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x6f0b, + 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, + 0x020b, 0x080c, 0x681d, 0x7810, 0x0006, 0xa080, 0x0017, 0x2098, + 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x000e, + 0xa080, 0x0001, 0x2004, 0x7812, 0x080c, 0x6f0b, 0x002e, 0x001e, + 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126, 0x2091, + 0x8000, 0x2071, 0x94e5, 0x700c, 0x2060, 0x8cff, 0x0168, 0x080c, + 0x84c8, 0x1110, 0x080c, 0x7776, 0x600c, 0x0006, 0x080c, 0x74f2, + 0x080c, 0x7238, 0x00ce, 0x0c88, 0x700f, 0x0000, 0x700b, 0x0000, + 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0156, 0x00f6, + 0x00e6, 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, + 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x94e5, 0x7024, 0x2060, + 0x8cff, 0x05a0, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x57a1, + 0x2009, 0x0013, 0x080c, 0x7518, 0x20a9, 0x01f4, 0x6824, 0xd094, + 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, + 0x1000, 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, + 0x0010, 0x1f04, 0x70ae, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, + 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x2001, 0x9200, + 0x2004, 0xa096, 0x0001, 0x0550, 0xa096, 0x0004, 0x0538, 0x6817, + 0x0008, 0x68c3, 0x0000, 0x2011, 0x40af, 0x080c, 0x5731, 0x20a9, + 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, + 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd084, + 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x70e9, 0x7804, 0xa084, + 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x000e, 0x001e, + 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, + 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, 0x0016, + 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, + 0x94e5, 0x703c, 0x2060, 0x8cff, 0x0904, 0x7185, 0x6817, 0x0010, + 0x68c7, 0x0000, 0x68cb, 0x0000, 0x080c, 0x57ae, 0x080c, 0x1ef8, + 0x0046, 0x0056, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, 0x2021, + 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x11b0, 0x68c7, + 0x0000, 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0020, 0x2071, + 0x953b, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, 0x6816, 0x7803, + 0x0008, 0x7003, 0x0000, 0x00fe, 0x00ee, 0x250a, 0x005e, 0x004e, + 0xa39d, 0x0000, 0x1150, 0x2009, 0x0049, 0x601c, 0xa086, 0x0009, + 0x1110, 0x2009, 0x0103, 0x080c, 0x7518, 0x20a9, 0x03e8, 0x6824, + 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, + 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd094, 0x0118, 0x6827, + 0x0002, 0x0010, 0x1f04, 0x7167, 0x7804, 0xa084, 0x1000, 0x0120, + 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, + 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, + 0x0126, 0x2091, 0x8000, 0x2069, 0x94e5, 0x6a06, 0x012e, 0x00de, + 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0x94e5, 0x6a32, + 0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006, + 0x0126, 0x2071, 0x94e5, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000, + 0x8cff, 0x0538, 0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110, + 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060, + 0x08b8, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, + 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, 0x20a2, + 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804, + 0x7230, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, + 0x0478, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, + 0x00f8, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, + 0x0078, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x6a9c, 0x7810, + 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, + 0x0089, 0x60c3, 0x0020, 0x080c, 0x6f0b, 0x014e, 0x015e, 0x0005, + 0x00e6, 0x2071, 0x94e5, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022, + 0x00ee, 0x0005, 0x20a9, 0x0008, 0x20a2, 0x1f04, 0x7244, 0x20a2, + 0x20a2, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x7614, 0x2660, + 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0x72d2, 0x8cff, 0x0904, + 0x72d2, 0x601c, 0xa086, 0x0006, 0x1904, 0x72cd, 0x88ff, 0x0138, + 0x2800, 0xac06, 0x1904, 0x72cd, 0x2039, 0x0000, 0x0050, 0x6018, + 0xa206, 0x1904, 0x72cd, 0x85ff, 0x0120, 0x6020, 0xa106, 0x1904, + 0x72cd, 0x7024, 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, + 0x01f0, 0x080c, 0x57a1, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, + 0x7356, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, + 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, + 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, + 0x0009, 0x630a, 0x0450, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, + 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, + 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, + 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0110, 0x080c, 0x9097, 0x080c, 0x849b, 0x080c, 0x7238, + 0x88ff, 0x1190, 0x00ce, 0x0804, 0x725b, 0x2c78, 0x600c, 0x2060, + 0x0804, 0x725b, 0xa006, 0x012e, 0x000e, 0x006e, 0x007e, 0x00ce, + 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, 0x0000, 0x00ce, 0xa8c5, + 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, + 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x7638, 0x2660, + 0x2678, 0x8cff, 0x0904, 0x7346, 0x601c, 0xa086, 0x0006, 0x1904, + 0x7341, 0x88ff, 0x0128, 0x2800, 0xac06, 0x1904, 0x7341, 0x0040, + 0x6018, 0xa206, 0x15f0, 0x85ff, 0x0118, 0x6020, 0xa106, 0x15c8, + 0x703c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7110, + 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, + 0x003e, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, + 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, + 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0110, + 0x080c, 0x9097, 0x080c, 0x849b, 0x88ff, 0x1190, 0x00ce, 0x0804, + 0x72f1, 0x2c78, 0x600c, 0x2060, 0x0804, 0x72f1, 0xa006, 0x012e, + 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, + 0x6017, 0x0000, 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00e6, 0x2071, + 0x94e5, 0x2001, 0x9200, 0x2004, 0xa086, 0x0002, 0x1118, 0x7007, + 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, + 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, + 0x94e5, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, + 0xac06, 0x11e0, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, + 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, + 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, + 0x2678, 0x600f, 0x0000, 0xa085, 0x0001, 0x0020, 0x2c78, 0x600c, + 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, + 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, + 0x0126, 0x2091, 0x8000, 0x2071, 0x94e5, 0x760c, 0x2660, 0x2678, + 0x8cff, 0x0904, 0x7423, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, + 0x1904, 0x741e, 0x7024, 0xac06, 0x1500, 0x2069, 0x0100, 0x68c0, + 0xa005, 0x01d8, 0x080c, 0x6f1e, 0x68c3, 0x0000, 0x080c, 0x7356, + 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, + 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, + 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0xac36, 0x1110, + 0x660c, 0x760e, 0x7008, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, + 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, + 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, + 0x84b7, 0x1118, 0x080c, 0x2692, 0x00c0, 0x080c, 0x84c8, 0x1118, + 0x080c, 0x7776, 0x0090, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0168, + 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x6003, 0x0000, 0x080c, + 0x849b, 0x080c, 0x7238, 0x00ce, 0x0804, 0x73b0, 0x2c78, 0x600c, + 0x2060, 0x0804, 0x73b0, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00de, + 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19e8, 0x080c, + 0x9097, 0x0c18, 0x0036, 0x0156, 0x0136, 0x0146, 0x3908, 0xa006, + 0xa190, 0x0020, 0x221c, 0xa39e, 0x251b, 0x1118, 0x8210, 0x8000, + 0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0, + 0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e, 0x003e, 0x0005, 0x00d6, + 0x20a1, 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0200, 0x20a3, 0x0014, + 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2099, 0x94df, + 0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x080c, 0x6f0b, 0x00de, 0x0005, 0x20a1, + 0x020b, 0x080c, 0x68a0, 0x20a3, 0x0210, 0x20a3, 0x0018, 0x20a3, + 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, + 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, + 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, + 0x0018, 0x080c, 0x6f0b, 0x0005, 0x2061, 0x9900, 0x2a70, 0x7064, + 0x7046, 0x704b, 0x9900, 0x0005, 0x00e6, 0x0126, 0x2071, 0x9200, + 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, 0x0608, 0x7048, 0x2060, + 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x000c, 0x7058, 0xac02, + 0x1208, 0x0cb0, 0x2061, 0x9900, 0x0c98, 0x6003, 0x0008, 0x8529, + 0x7546, 0xaca8, 0x000c, 0x7058, 0xa502, 0x1230, 0x754a, 0xa085, + 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, 0x9900, 0x0cc0, 0xa006, + 0x0cc0, 0x00e6, 0x2071, 0x9200, 0x7544, 0xa582, 0x0001, 0x0600, + 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x000c, + 0x7058, 0xac02, 0x1208, 0x0cb0, 0x2061, 0x9900, 0x0c98, 0x6003, + 0x0008, 0x8529, 0x7546, 0xaca8, 0x000c, 0x7058, 0xa502, 0x1228, + 0x754a, 0xa085, 0x0001, 0x00ee, 0x0005, 0x704b, 0x9900, 0x0cc8, + 0xa006, 0x0cc8, 0xac82, 0x9900, 0x0a0c, 0x13fe, 0x2001, 0x9216, + 0x2004, 0xac02, 0x1a0c, 0x13fe, 0xa006, 0x6006, 0x600a, 0x600e, + 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x6022, + 0x2061, 0x9200, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0108, + 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0cc0, + 0x601c, 0xa084, 0x000f, 0x0002, 0x7526, 0x752d, 0x7548, 0x7563, + 0x8555, 0x8570, 0x858b, 0x7526, 0x752d, 0x5d3d, 0xa18e, 0x0047, + 0x1118, 0xa016, 0x080c, 0x16c6, 0x0005, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x7546, 0x7654, + 0x779c, 0x7546, 0x77eb, 0x7546, 0x7546, 0x7546, 0x75f6, 0x7b03, + 0x7546, 0x7546, 0x7546, 0x7546, 0x7546, 0x7546, 0x080c, 0x13fe, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, + 0x0005, 0x7561, 0x7fa1, 0x7561, 0x7561, 0x7561, 0x7561, 0x7561, + 0x7561, 0x7f89, 0x8078, 0x7561, 0x7fce, 0x8023, 0x7fce, 0x8023, + 0x7561, 0x080c, 0x13fe, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x13fe, 0x0013, 0x006e, 0x0005, 0x757c, 0x7b3f, 0x7bf0, 0x7cb4, + 0x7df4, 0x757c, 0x757c, 0x757c, 0x7b1b, 0x7f40, 0x7f43, 0x757c, + 0x757c, 0x757c, 0x757c, 0x7f66, 0x080c, 0x13fe, 0x20a9, 0x000e, + 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, + 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, + 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x758c, + 0x00e6, 0x080c, 0x82ee, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000, + 0x7037, 0x0103, 0x00ee, 0x080c, 0x74f2, 0x0005, 0x00d6, 0x0036, + 0x7330, 0xa386, 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff, + 0x6817, 0xfffd, 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000, + 0x6837, 0x0103, 0x6b32, 0x080c, 0x74f2, 0x003e, 0x00de, 0x0005, + 0x0016, 0x20a9, 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, + 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001, + 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004, + 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x74f2, 0x001e, 0x0005, + 0x00d6, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0, 0x53a3, 0xa1b6, + 0x0015, 0x1148, 0x6018, 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, + 0x6800, 0xc08d, 0x6802, 0x00de, 0x0804, 0x7598, 0x2100, 0xa1b2, + 0x003e, 0x1a0c, 0x13fe, 0x0002, 0x763c, 0x7648, 0x763c, 0x763c, + 0x763c, 0x763c, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, 0x763c, 0x763c, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763c, 0x763a, + 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, 0x763a, + 0x763a, 0x763c, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, + 0x603e, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, + 0x6003, 0x0001, 0x6106, 0x080c, 0x603e, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6462, 0x012e, 0x0005, 0x6004, 0xa0b2, 0x003e, 0x1a0c, + 0x13fe, 0xa1b6, 0x0013, 0x0904, 0x76f0, 0xa1b6, 0x0027, 0x1904, + 0x76b6, 0x080c, 0x6389, 0x6004, 0x080c, 0x84b7, 0x0178, 0x080c, + 0x84c8, 0x0904, 0x76b0, 0xa08e, 0x0021, 0x0904, 0x76b3, 0xa08e, + 0x0022, 0x05f0, 0xa08e, 0x003d, 0x05f0, 0x04a8, 0x080c, 0x2692, + 0x2001, 0x0007, 0x080c, 0x43e3, 0x6018, 0xa080, 0x0028, 0x200c, + 0x080c, 0x7776, 0xa186, 0x007e, 0x1148, 0x2001, 0x9232, 0x2014, + 0xc285, 0x080c, 0x4dc5, 0x1108, 0xc2ad, 0x2202, 0x0016, 0x0026, + 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x00c6, 0x6018, 0xa065, 0x0110, 0x080c, + 0x460d, 0x00ce, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x003e, 0x002e, + 0x001e, 0x080c, 0x441f, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x080c, 0x7776, 0x0cc0, 0x080c, 0x7790, 0x0ca8, 0xa186, 0x0014, + 0x1db0, 0x080c, 0x6389, 0x080c, 0x266c, 0x080c, 0x84b7, 0x1188, + 0x080c, 0x2692, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x7776, + 0xa186, 0x007e, 0x1128, 0x2001, 0x9232, 0x200c, 0xc185, 0x2102, + 0x08d0, 0x080c, 0x84c8, 0x1118, 0x080c, 0x7776, 0x08a0, 0x6004, + 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, 0x9296, 0x2079, + 0x0000, 0x080c, 0x2924, 0x00fe, 0x00ee, 0x0828, 0x6004, 0xa08e, + 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, 0x7790, 0x0804, 0x76ab, + 0x2008, 0x0002, 0x7732, 0x7733, 0x7736, 0x7739, 0x773c, 0x773f, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7742, 0x7747, 0x7730, 0x7750, 0x7747, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7747, 0x7747, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, + 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7730, 0x7747, + 0x080c, 0x13fe, 0x00a0, 0x2001, 0x000b, 0x0418, 0x2001, 0x0003, + 0x0400, 0x2001, 0x0005, 0x00e8, 0x2001, 0x0001, 0x00d0, 0x2001, + 0x0009, 0x00b8, 0x080c, 0x13fe, 0x0098, 0x080c, 0x43e3, 0x080c, + 0x6389, 0x6003, 0x0002, 0x6017, 0x0028, 0x080c, 0x6462, 0x0040, + 0x080c, 0x6389, 0x6003, 0x0004, 0x6017, 0x0028, 0x080c, 0x6462, + 0x0005, 0x080c, 0x43e3, 0x080c, 0x6389, 0x6003, 0x0002, 0x0036, + 0x2019, 0x925c, 0x2304, 0xa084, 0xff00, 0x1118, 0x2019, 0x0028, + 0x0040, 0x8007, 0xa09a, 0x0004, 0x0ec8, 0x8003, 0x801b, 0x831b, + 0xa318, 0x6316, 0x003e, 0x080c, 0x6462, 0x0c10, 0x00e6, 0x080c, + 0x82ee, 0x0188, 0x6010, 0x2070, 0x7007, 0x0000, 0x0016, 0x6004, + 0xa08e, 0x0021, 0x0150, 0xa08e, 0x003d, 0x0138, 0x001e, 0x7037, + 0x0103, 0x7033, 0x0100, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cd8, + 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, + 0x7023, 0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, + 0xa084, 0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x13fe, 0x6604, + 0xa6b6, 0x0028, 0x1118, 0x080c, 0x84f2, 0x0468, 0x6604, 0xa6b6, + 0x0029, 0x1118, 0x080c, 0x8509, 0x0430, 0x6604, 0xa6b6, 0x001f, + 0x1118, 0x080c, 0x757e, 0x00f8, 0x6604, 0xa6b6, 0x0000, 0x1118, + 0x080c, 0x75e0, 0x00c0, 0x6604, 0xa6b6, 0x0022, 0x1118, 0x080c, + 0x75a6, 0x0088, 0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x75c0, + 0x0050, 0xa1b6, 0x0015, 0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, + 0x1118, 0x0804, 0x7983, 0x0005, 0x080c, 0x7526, 0x0ce0, 0x7805, + 0x7808, 0x7805, 0x7844, 0x7805, 0x7923, 0x7805, 0x7805, 0x7805, + 0x795b, 0x7805, 0x7971, 0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, + 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00e6, 0xacf0, + 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, + 0x74f2, 0x0005, 0x080c, 0x74f2, 0x0005, 0xe000, 0xe000, 0x0005, + 0x00e6, 0x2071, 0x9200, 0x7080, 0xa086, 0x0074, 0x11f0, 0x080c, + 0x8ebb, 0x1170, 0x00d6, 0x6018, 0x2068, 0x00e9, 0x00de, 0x2001, + 0x0006, 0x080c, 0x43e3, 0x080c, 0x2692, 0x080c, 0x74f2, 0x0088, + 0x2001, 0x000a, 0x080c, 0x43e3, 0x080c, 0x2692, 0x6003, 0x0001, + 0x6007, 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, + 0x7910, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000, + 0x080c, 0x43d1, 0x2069, 0x9251, 0x6804, 0xd0a4, 0x0120, 0x2001, + 0x0006, 0x080c, 0x43f1, 0x0005, 0x00d6, 0x2011, 0x9220, 0x2204, + 0xa086, 0x0074, 0x1904, 0x790b, 0x080c, 0x7a64, 0x6018, 0x2068, + 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x0198, 0xa286, 0x0080, + 0x1904, 0x789c, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, + 0x0588, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, + 0x0448, 0x00d6, 0x00e6, 0x00f6, 0x6813, 0x00ff, 0x6817, 0xfffe, + 0x2071, 0x9232, 0x2e04, 0xa085, 0x0003, 0x2072, 0x2071, 0x9780, + 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0x921b, 0x206a, + 0x78e6, 0x8e70, 0x2e04, 0x2069, 0x921c, 0x206a, 0x78ea, 0x7832, + 0x7836, 0xa084, 0x00ff, 0x2008, 0x080c, 0x2435, 0x00fe, 0x00ee, + 0x00de, 0x00f8, 0x2001, 0x0006, 0x080c, 0x43e3, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0804, 0x790e, 0x6010, 0xa005, 0x0130, 0x2068, + 0x6838, 0xd0f4, 0x0110, 0x0804, 0x7862, 0x2001, 0x0004, 0x080c, + 0x43e3, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x603e, 0x0804, + 0x790e, 0x685c, 0xd0e4, 0x01c8, 0x080c, 0x8531, 0x080c, 0x4dc5, + 0x0110, 0xd0dc, 0x19b8, 0x2011, 0x9232, 0x2204, 0xc0ad, 0x2012, + 0x2001, 0x94c8, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, + 0x080c, 0x2460, 0x78e2, 0x00fe, 0x0828, 0x080c, 0x854a, 0x2011, + 0x9232, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0x8fa4, 0x000e, + 0x1904, 0x7892, 0xc0b5, 0x2012, 0x2001, 0x0000, 0x080c, 0x43d1, + 0x00c6, 0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, + 0x7936, 0x00fe, 0x080c, 0x2435, 0x2001, 0x9214, 0x2004, 0x2009, + 0x0000, 0x080c, 0x240b, 0x2001, 0x9213, 0x2102, 0x8108, 0x080c, + 0x4400, 0x2c00, 0x00ce, 0x1904, 0x7892, 0x601a, 0x2001, 0x0002, + 0x080c, 0x43e3, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x603e, 0x0018, 0x2001, 0x0001, 0x0011, 0x00de, 0x0005, + 0x0006, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, 0x000e, 0x0130, + 0xa005, 0x0120, 0x2001, 0x0007, 0x080c, 0x43e3, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0005, 0x00e6, 0x2071, 0x9200, 0x7080, 0xa086, + 0x0014, 0x1548, 0x7000, 0xa086, 0x0003, 0x1128, 0x6010, 0xa005, + 0x1110, 0x080c, 0x370a, 0x00d6, 0x6018, 0x2068, 0x080c, 0x44c7, + 0x080c, 0x7833, 0x00de, 0x080c, 0x7a6e, 0x11a8, 0x2001, 0x0006, + 0x080c, 0x43e3, 0x00e6, 0x6010, 0xa005, 0x0138, 0x2070, 0x7007, + 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x00ee, 0x080c, 0x2692, + 0x080c, 0x74f2, 0x0030, 0x080c, 0x7776, 0x2001, 0x0000, 0x080c, + 0x7910, 0x00ee, 0x0005, 0x2011, 0x9220, 0x2204, 0xa086, 0x0014, + 0x1158, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, 0x7910, + 0x0005, 0x2011, 0x9220, 0x2204, 0xa086, 0x0004, 0x1138, 0x2001, + 0x0007, 0x080c, 0x43e3, 0x080c, 0x74f2, 0x0020, 0x2001, 0x0001, + 0x080c, 0x7910, 0x0005, 0x000b, 0x0005, 0x7805, 0x7991, 0x7805, + 0x79b5, 0x7805, 0x7a1a, 0x7805, 0x7802, 0x7805, 0x7a2f, 0x7805, + 0x7a41, 0x00c6, 0x080c, 0x7a53, 0x1178, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0002, 0x080c, 0x603e, 0x0078, 0x2009, 0x978f, 0x2104, 0xa084, + 0xff00, 0xa086, 0x1900, 0x1118, 0x080c, 0x74f2, 0x0020, 0x2001, + 0x0001, 0x080c, 0x7910, 0x00ce, 0x0005, 0x080c, 0x7a61, 0x00d6, + 0x2069, 0x94d7, 0x2d04, 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, + 0xa086, 0x007e, 0x1138, 0x2069, 0x921c, 0x2d04, 0x8000, 0x206a, + 0x00de, 0x0010, 0x00de, 0x0078, 0x2001, 0x0000, 0x080c, 0x43d1, + 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, 0x0002, + 0x080c, 0x603e, 0x0400, 0x080c, 0x7776, 0x2009, 0x978e, 0x2134, + 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x01b8, 0x2009, 0x978f, 0x2104, + 0xa084, 0xff00, 0xa086, 0x1900, 0x1150, 0xa686, 0x0009, 0x0160, + 0x2001, 0x0004, 0x080c, 0x43e3, 0x080c, 0x74f2, 0x0020, 0x2001, + 0x0001, 0x080c, 0x7910, 0x0005, 0x00d6, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0128, 0x6838, 0xd0fc, 0x0110, 0x00de, 0x0c80, 0x6018, + 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0140, 0x8001, 0x6842, + 0x6017, 0x000a, 0x6007, 0x0016, 0x00de, 0x0c28, 0x080c, 0x266c, + 0x00de, 0x08e8, 0x080c, 0x7a61, 0x1158, 0x2001, 0x0004, 0x080c, + 0x43e3, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x603e, 0x0030, + 0x080c, 0x7776, 0x2001, 0x0000, 0x080c, 0x7910, 0x0005, 0x0489, + 0x1158, 0x2001, 0x0008, 0x080c, 0x43e3, 0x6003, 0x0001, 0x6007, + 0x0005, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, 0x080c, 0x7910, + 0x0005, 0x00f9, 0x1158, 0x2001, 0x000a, 0x080c, 0x43e3, 0x6003, + 0x0001, 0x6007, 0x0001, 0x080c, 0x603e, 0x0020, 0x2001, 0x0001, + 0x080c, 0x7910, 0x0005, 0x2009, 0x978e, 0x2104, 0xa086, 0x0003, + 0x1138, 0x2009, 0x978f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, + 0x0005, 0xa085, 0x0001, 0x0005, 0x00c6, 0x0016, 0xac88, 0x0006, + 0x2164, 0x080c, 0x4443, 0x001e, 0x00ce, 0x0005, 0x00e6, 0x2071, + 0x978c, 0x7004, 0xa086, 0x0014, 0x11a8, 0x7008, 0xa086, 0x0800, + 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, 0x0f00, 0xa086, 0x0100, + 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0xa006, 0x0010, + 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076, + 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, + 0x94ee, 0x252c, 0x2021, 0x94f4, 0x2424, 0x2061, 0x9900, 0x2071, + 0x9200, 0x7244, 0x7064, 0xa202, 0x1688, 0x080c, 0x90ee, 0x0540, + 0x671c, 0xa786, 0x0001, 0x0520, 0xa786, 0x0007, 0x0508, 0x2500, + 0xac06, 0x01f0, 0x2400, 0xac06, 0x01d8, 0x00c6, 0x6000, 0xa086, + 0x0004, 0x1110, 0x080c, 0x1788, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0160, 0xa786, 0x0003, 0x11e0, 0x6837, 0x0103, 0x6b4a, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x080c, 0x849b, 0x00ce, + 0xace0, 0x000c, 0x7058, 0xac02, 0x1208, 0x0858, 0x012e, 0x000e, + 0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, + 0xa786, 0x0006, 0x1118, 0x080c, 0x9097, 0x0c38, 0xa786, 0x0009, + 0x19d8, 0x2009, 0x0106, 0x080c, 0x7518, 0x0c08, 0x220c, 0x2304, + 0xa106, 0x1130, 0x8210, 0x8318, 0x1f04, 0x7aee, 0xa006, 0x0005, + 0x2304, 0xa102, 0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, + 0xa18d, 0x0001, 0x0005, 0x6004, 0xa08a, 0x003e, 0x1a0c, 0x13fe, + 0x080c, 0x84b7, 0x0120, 0x080c, 0x84c8, 0x0150, 0x0010, 0x080c, + 0x2692, 0x080c, 0x6389, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x080c, 0x7776, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x7b31, 0x7b31, + 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, 0x7b31, + 0x7b31, 0x7b33, 0x7b33, 0x7b33, 0x7b33, 0x7b31, 0x7b31, 0x7b31, + 0x7b33, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, 0x5ff8, + 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, 0xa186, + 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, 0x0804, 0x7bc5, 0xa186, + 0x0027, 0x11d0, 0x080c, 0x6389, 0x080c, 0x266c, 0x00d6, 0x6110, + 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, + 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, + 0x74f2, 0x080c, 0x6462, 0x0005, 0xa186, 0x0014, 0x1120, 0x6004, + 0xa082, 0x0040, 0x0428, 0xa186, 0x0046, 0x0138, 0xa186, 0x0045, + 0x0120, 0xa186, 0x0047, 0x190c, 0x13fe, 0x2001, 0x0109, 0x2004, + 0xd084, 0x0198, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, + 0x080c, 0x5ee3, 0x002e, 0x001e, 0x000e, 0x012e, 0xe000, 0x6000, + 0xa086, 0x0002, 0x1110, 0x0804, 0x7bf0, 0x080c, 0x7526, 0x0005, + 0x0002, 0x7ba6, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, + 0x7ba4, 0x7ba4, 0x7ba4, 0x7ba4, 0x7bbe, 0x7bbe, 0x7bbe, 0x7bbe, + 0x7ba4, 0x7ba4, 0x7ba4, 0x7bbe, 0x080c, 0x13fe, 0x080c, 0x6389, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, + 0x684b, 0x0006, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, + 0x00de, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, + 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x0002, 0x7bdb, 0x7bd9, + 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, 0x7bd9, + 0x7bd9, 0x7be9, 0x7be9, 0x7be9, 0x7be9, 0x7bd9, 0x7bd9, 0x7bd9, + 0x7be9, 0x080c, 0x13fe, 0x080c, 0x6389, 0x6003, 0x0002, 0x080c, + 0x6462, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, + 0x0005, 0x080c, 0x6389, 0x6003, 0x000f, 0x080c, 0x6462, 0x0005, + 0xa182, 0x0040, 0x0002, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, + 0x7c08, 0x7c8a, 0x7ca9, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, + 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x7c06, 0x080c, 0x13fe, + 0x00e6, 0x00d6, 0x2071, 0x978c, 0x6110, 0x2168, 0x7614, 0xa6b4, + 0x0fff, 0x86ff, 0x0904, 0x7c70, 0xa68c, 0x0c00, 0x0120, 0x7318, + 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0190, + 0xa186, 0x0028, 0x1128, 0x080c, 0x84a6, 0x684b, 0x001c, 0x0060, + 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, + 0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, + 0xd6c4, 0x01b0, 0xa686, 0x0100, 0x1138, 0x2001, 0x9799, 0x2004, + 0xa005, 0x1110, 0xc6c4, 0x0868, 0x7328, 0x732c, 0x6b56, 0x0036, + 0x2308, 0x2019, 0x9798, 0xad90, 0x0019, 0x080c, 0x80e6, 0x003e, + 0xd6cc, 0x0560, 0x7124, 0x695a, 0xa192, 0x0021, 0x1250, 0x2071, + 0x9798, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x80e6, + 0x00e8, 0x6838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x00f6, 0x2d78, 0x080c, 0x808b, 0x00fe, 0x080c, 0x80d6, 0x0080, + 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0130, + 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x7de6, 0x080c, 0x4809, + 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x00de, 0x00ee, 0x080c, + 0x74f2, 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, 0x978c, 0x7c04, + 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0120, + 0x6003, 0x0002, 0x00fe, 0x0005, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, + 0x00fe, 0x2c10, 0x080c, 0x1c88, 0x080c, 0x605b, 0x080c, 0x651c, + 0x0005, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x16c6, 0x0005, 0xa182, 0x0040, 0x0002, 0x7cca, + 0x7cca, 0x7cca, 0x7cca, 0x7cca, 0x7ccc, 0x7d54, 0x7cca, 0x7cca, + 0x7d6a, 0x7dc1, 0x7cca, 0x7cca, 0x7cca, 0x7cca, 0x7dcc, 0x7cca, + 0x7cca, 0x7cca, 0x080c, 0x13fe, 0x0076, 0x00f6, 0x00e6, 0x00d6, + 0x2071, 0x978c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0904, 0x7d4f, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, + 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x7d4f, + 0x080c, 0x147c, 0x090c, 0x13fe, 0x2d00, 0x784a, 0x7f4c, 0xc7cd, + 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, + 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318, 0x6b62, 0x731c, + 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180, 0xa186, 0x0028, + 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0x684b, 0x0015, + 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b, 0x0000, + 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0160, + 0x7328, 0x732c, 0x6b56, 0x0036, 0x2308, 0x2019, 0x9798, 0xad90, + 0x0019, 0x080c, 0x80e6, 0x003e, 0xd6cc, 0x01c8, 0x7124, 0x695a, + 0xa192, 0x0021, 0x1250, 0x2071, 0x9798, 0x831c, 0x2300, 0xae18, + 0xad90, 0x001d, 0x080c, 0x80e6, 0x0050, 0x7838, 0xd0fc, 0x0120, + 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78, 0x080c, 0x808b, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, + 0x978c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, + 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x2c10, 0x080c, 0x1c88, 0x080c, + 0x6f04, 0x0005, 0x00d6, 0x6003, 0x0002, 0x080c, 0x641b, 0x080c, + 0x651c, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0904, 0x7dbf, 0xd1cc, + 0x0540, 0x6948, 0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, + 0x6850, 0x0006, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0023, + 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x7d8a, + 0x015e, 0x000e, 0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, + 0x14a3, 0x0418, 0x0016, 0x080c, 0x14a3, 0x00de, 0x080c, 0x80d6, + 0x00e0, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, + 0x0180, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, + 0x0118, 0x684b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, + 0x0010, 0x684b, 0x0000, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, + 0x0005, 0x2019, 0x0001, 0x080c, 0x7110, 0x6003, 0x0002, 0x080c, + 0x641b, 0x080c, 0x651c, 0x0005, 0x080c, 0x641b, 0x080c, 0x266c, + 0x00d6, 0x6110, 0x2168, 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, + 0x684b, 0x0029, 0x6847, 0x0000, 0x080c, 0x4809, 0x080c, 0x848f, + 0x00de, 0x080c, 0x74f2, 0x080c, 0x651c, 0x0005, 0x684b, 0x0015, + 0xd1fc, 0x0138, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, + 0x0000, 0x6962, 0x685e, 0x0005, 0xa182, 0x0040, 0x0002, 0x7e0a, + 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0c, 0x7e0a, 0x7eac, 0x7eb4, + 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, 0x7e0a, + 0x7e0a, 0x7e0a, 0x080c, 0x13fe, 0x0076, 0x00f6, 0x00e6, 0x00d6, + 0x2071, 0x978c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, + 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, + 0x86ff, 0x0904, 0x7e9d, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, + 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x7e9b, + 0xa686, 0x0100, 0x1140, 0x2001, 0x9799, 0x2004, 0xa005, 0x1118, + 0xc6c4, 0x7e46, 0x0c28, 0x080c, 0x147c, 0x090c, 0x13fe, 0x2d00, + 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, + 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, + 0x0120, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, + 0x0002, 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, + 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, + 0x0007, 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, + 0x6856, 0xa01e, 0xd6c4, 0x0160, 0x7328, 0x732c, 0x6b56, 0x0036, + 0x2308, 0x2019, 0x9798, 0xad90, 0x0019, 0x080c, 0x80e6, 0x003e, + 0xd6cc, 0x01c8, 0x7124, 0x695a, 0xa192, 0x0021, 0x1250, 0x2071, + 0x9798, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x80e6, + 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, + 0x2d78, 0x080c, 0x808b, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001, + 0x0001, 0x2071, 0x978c, 0x7218, 0x731c, 0x080c, 0x1700, 0x00de, + 0x00ee, 0x00fe, 0x007e, 0x0005, 0x20e1, 0x0005, 0x3d18, 0x3e20, + 0x2c10, 0x080c, 0x16c6, 0x0005, 0x00d6, 0x6003, 0x0002, 0x6110, + 0x2168, 0x694c, 0xd1e4, 0x0904, 0x7f3e, 0xd1cc, 0x0904, 0x7f17, + 0x6948, 0x6838, 0xd0fc, 0x0590, 0x0016, 0x684c, 0x0006, 0x6850, + 0x0006, 0x684c, 0xd0ac, 0x0180, 0x6810, 0x6914, 0xa115, 0x0160, + 0x080c, 0x7de6, 0x00f6, 0x6948, 0x2178, 0x6848, 0x784a, 0x6860, + 0x7862, 0x685c, 0x785e, 0x00fe, 0x6948, 0xad90, 0x000d, 0xa198, + 0x000d, 0x2009, 0x0023, 0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, + 0x8210, 0x1f04, 0x7ee5, 0x015e, 0x000e, 0x6852, 0x000e, 0x684e, + 0x001e, 0x2168, 0x080c, 0x14a3, 0x0804, 0x7f3c, 0x0016, 0x684c, + 0xd0ac, 0x0190, 0x6810, 0x6914, 0xa115, 0x0170, 0x080c, 0x7de6, + 0x00f6, 0x6948, 0x2178, 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, + 0x785e, 0x684c, 0x784e, 0x00fe, 0x6948, 0xa188, 0x0013, 0x684c, + 0x200a, 0x080c, 0x14a3, 0x00de, 0x080c, 0x80d6, 0x0428, 0x6837, + 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, 0xa086, + 0x0028, 0x1118, 0x684b, 0x001c, 0x00a8, 0xd1dc, 0x0118, 0x684b, + 0x0015, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0058, 0x684b, + 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, + 0x080c, 0x7de6, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, + 0x080c, 0x6389, 0x0010, 0x080c, 0x641b, 0x080c, 0x82ee, 0x0198, + 0x00d6, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0x920c, 0x210c, + 0xd18c, 0x1188, 0xd184, 0x1160, 0x6108, 0x694a, 0x6847, 0x0000, + 0x080c, 0x4809, 0x00de, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, + 0x684b, 0x0004, 0x0c98, 0x684b, 0x0004, 0x0c80, 0xa182, 0x0040, + 0x0002, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7e, 0x7f7c, + 0x7f81, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, + 0x7f7c, 0x7f7c, 0x7f7c, 0x7f7c, 0x080c, 0x13fe, 0x080c, 0x74f2, + 0x0005, 0x0006, 0x0026, 0xa016, 0x080c, 0x16c6, 0x002e, 0x000e, + 0x0005, 0xa182, 0x0085, 0x0002, 0x7f95, 0x7f93, 0x7f93, 0x7f93, + 0x7f93, 0x7f93, 0x7f93, 0x080c, 0x13fe, 0x6003, 0x000b, 0x6106, + 0x080c, 0x5ff8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, + 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, + 0x13fe, 0xa08a, 0x008c, 0x1a0c, 0x13fe, 0xa082, 0x0085, 0x0072, + 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x13fe, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0x7fc5, 0x7fc7, + 0x7fc7, 0x7fc5, 0x7fc5, 0x7fc5, 0x7fc5, 0x080c, 0x13fe, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa186, 0x0013, + 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x0492, 0xa186, 0x0027, + 0x11e8, 0x080c, 0x6389, 0x080c, 0x266c, 0x00d6, 0x6010, 0x2068, + 0x080c, 0x82ee, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, + 0x0029, 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, 0x74f2, + 0x080c, 0x6462, 0x0005, 0x080c, 0x7526, 0x0ce0, 0xa186, 0x0014, + 0x1dd0, 0x080c, 0x6389, 0x00d6, 0x6010, 0x2068, 0x080c, 0x82ee, + 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006, 0x0c08, + 0x8011, 0x800f, 0x800f, 0x800f, 0x800f, 0x800f, 0x801a, 0x080c, + 0x13fe, 0x080c, 0x6389, 0x6017, 0x0014, 0x6003, 0x000c, 0x080c, + 0x6462, 0x0005, 0x080c, 0x6389, 0x6017, 0x0014, 0x6003, 0x000e, + 0x080c, 0x6462, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, 0x0085, + 0x0208, 0x001a, 0x080c, 0x7526, 0x0005, 0x8034, 0x8034, 0x8034, + 0x8034, 0x8036, 0x8057, 0x8034, 0x080c, 0x13fe, 0x00d6, 0x080c, + 0x848f, 0x080c, 0x82ee, 0x01b8, 0x6010, 0x2068, 0x6837, 0x0103, + 0x6850, 0xd0b4, 0x0118, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, + 0x684b, 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x852d, 0x6847, + 0x0000, 0x080c, 0x4809, 0x080c, 0x74f2, 0x00de, 0x0005, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x01b8, 0x6837, 0x0103, 0x6850, + 0xd0b4, 0x0118, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, + 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x852d, 0x6847, 0x0000, + 0x080c, 0x4809, 0x080c, 0x848f, 0x00de, 0x080c, 0x74f2, 0x0005, + 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, + 0x0118, 0x080c, 0x7526, 0x0030, 0x080c, 0x6389, 0x080c, 0x849b, + 0x080c, 0x6462, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, 0x2029, + 0x0001, 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, + 0x2069, 0x9798, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, + 0x001d, 0x080c, 0x80e6, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0110, + 0x080c, 0x14a3, 0x080c, 0x147c, 0x0500, 0x8528, 0x6837, 0x0110, + 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, 0x2608, + 0xad90, 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, 0x003c, + 0x2d78, 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, 0xa5ad, + 0x0003, 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, 0x8dff, + 0x0158, 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, 0x4809, + 0x2f68, 0x0cb8, 0x080c, 0x4809, 0x00fe, 0x0005, 0x0156, 0xa184, + 0x0001, 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, + 0x8318, 0x8210, 0x1f04, 0x80ed, 0x015e, 0x0005, 0x0126, 0x2091, + 0x8000, 0x601c, 0xa084, 0x000f, 0x0013, 0x012e, 0x0005, 0x8117, + 0x8109, 0x8112, 0x812e, 0x8109, 0x8112, 0x810b, 0x8112, 0x8109, + 0x5e80, 0x080c, 0x13fe, 0x0036, 0x2019, 0x0010, 0x080c, 0x8d4e, + 0x003e, 0x0005, 0xa006, 0x0005, 0xa085, 0x0001, 0x0005, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x0178, 0xa00e, 0x2001, 0x0005, + 0x080c, 0x492c, 0x080c, 0x852d, 0x080c, 0x4809, 0x080c, 0x74f2, + 0xa085, 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a, + 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x8145, 0x8160, 0x8147, + 0x816f, 0x815d, 0x8145, 0x8112, 0x8117, 0x8117, 0x8112, 0x8112, + 0x8112, 0x8112, 0x8112, 0x8112, 0x8112, 0x080c, 0x13fe, 0x00d6, + 0x6010, 0x2068, 0x080c, 0x82ee, 0x0110, 0x080c, 0x852d, 0x00de, + 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x5ff8, + 0x080c, 0x6462, 0xa085, 0x0001, 0x0005, 0x080c, 0x1788, 0x0c38, + 0x00e6, 0x2071, 0x94e5, 0x7024, 0xac06, 0x1110, 0x080c, 0x708d, + 0x080c, 0x6fab, 0x00ee, 0x19d8, 0x080c, 0x8112, 0x0005, 0x0036, + 0x00e6, 0x2071, 0x94e5, 0x703c, 0xac06, 0x1138, 0x2019, 0x0000, + 0x080c, 0x7110, 0x00ee, 0x003e, 0x0850, 0x080c, 0x7366, 0x00ee, + 0x003e, 0x1928, 0x080c, 0x8112, 0x0005, 0x00c6, 0x601c, 0xa084, + 0x000f, 0x0013, 0x00ce, 0x0005, 0x819a, 0x81f7, 0x829a, 0x819e, + 0x819a, 0x819a, 0x8d44, 0x74f2, 0x81f7, 0x080c, 0x84c8, 0x1110, + 0x080c, 0x7776, 0x0005, 0x6017, 0x0001, 0x0005, 0x6000, 0xa08a, + 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x81b5, 0x81b7, 0x81d5, + 0x81e7, 0x81f4, 0x81b5, 0x819a, 0x819a, 0x819a, 0x81e7, 0x81e7, + 0x81b5, 0x81b5, 0x81b5, 0x81b5, 0x81f1, 0x080c, 0x13fe, 0x00e6, + 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0x94e5, 0x7024, + 0xac06, 0x0180, 0x080c, 0x6fab, 0x6007, 0x0085, 0x6003, 0x000b, + 0x601f, 0x0002, 0x6017, 0x0014, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x00ee, 0x0005, 0x6017, 0x0001, 0x0cd8, 0x00d6, 0x6010, 0x2068, + 0x6850, 0xc0b5, 0x6852, 0x00de, 0x6007, 0x0085, 0x6003, 0x000b, + 0x601f, 0x0002, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0005, 0x00d6, + 0x6017, 0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de, + 0x0005, 0x080c, 0x74f2, 0x0005, 0x080c, 0x1788, 0x08f0, 0x6000, + 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x820e, 0x819b, + 0x8210, 0x820e, 0x8210, 0x820e, 0x820e, 0x820e, 0x8195, 0x8195, + 0x820e, 0x820e, 0x820e, 0x820e, 0x820e, 0x820e, 0x080c, 0x13fe, + 0x00d6, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x00de, 0xa08a, + 0x000c, 0x1a0c, 0x13fe, 0x000b, 0x0005, 0x8229, 0x824a, 0x8229, + 0x824a, 0x8229, 0x824a, 0x822b, 0x8232, 0x8229, 0x824a, 0x8229, + 0x8243, 0x080c, 0x13fe, 0x6004, 0xa08e, 0x0004, 0x01b0, 0xa08e, + 0x0002, 0x0198, 0x6004, 0x080c, 0x84c8, 0x0904, 0x8292, 0xa08e, + 0x0021, 0x0904, 0x8296, 0xa08e, 0x0022, 0x0904, 0x8292, 0xa08e, + 0x003d, 0x0904, 0x8296, 0x080c, 0x266c, 0x080c, 0x7776, 0x080c, + 0x74f2, 0x0005, 0x00c6, 0x00d6, 0x6104, 0xa186, 0x0016, 0x0598, + 0xa186, 0x0002, 0x11f8, 0x6018, 0x2068, 0x2001, 0x9232, 0x2004, + 0xd0ac, 0x11c0, 0x68a0, 0xd0bc, 0x11a8, 0x6840, 0xa084, 0x00ff, + 0xa005, 0x0180, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, + 0x6017, 0x0398, 0x080c, 0x749c, 0x0128, 0x2d00, 0x601a, 0x601f, + 0x0001, 0x0088, 0x00de, 0x00ce, 0x080c, 0x7776, 0x080c, 0x266c, + 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2692, 0x012e, 0x00ee, + 0x080c, 0x74f2, 0x0005, 0x2001, 0x0002, 0x080c, 0x43e3, 0x6003, + 0x0001, 0x6007, 0x0002, 0x080c, 0x603e, 0x080c, 0x6462, 0x00de, + 0x00ce, 0x0c80, 0x080c, 0x7776, 0x0804, 0x8247, 0x080c, 0x7790, + 0x0804, 0x8247, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x13fe, 0x000b, + 0x0005, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, 0x82b1, + 0x82b1, 0x82b1, 0x819a, 0x82b1, 0x819b, 0x82b3, 0x819b, 0x82bc, + 0x82b1, 0x080c, 0x13fe, 0x6007, 0x008b, 0x6003, 0x000d, 0x080c, + 0x5ff8, 0x080c, 0x6462, 0x0005, 0x080c, 0x848f, 0x0479, 0x01d8, + 0x080c, 0x266c, 0x00d6, 0x0451, 0x0150, 0x6010, 0x2068, 0x6837, + 0x0103, 0x684b, 0x0006, 0x6847, 0x0000, 0x080c, 0x4809, 0x00de, + 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x603e, + 0x080c, 0x6462, 0x0010, 0x080c, 0x74f2, 0x0005, 0xa284, 0x0003, + 0x1158, 0xa282, 0x9900, 0x0240, 0x2001, 0x9216, 0x2004, 0xa202, + 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x0026, 0x6210, + 0x82ff, 0x002e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, + 0x2091, 0x8000, 0x2061, 0x9900, 0x2071, 0x9200, 0x7344, 0x7064, + 0xa302, 0x1290, 0x601c, 0xa206, 0x1148, 0x080c, 0x84c8, 0x1110, + 0x080c, 0x7776, 0x00c6, 0x080c, 0x74f2, 0x00ce, 0xace0, 0x000c, + 0x7058, 0xac02, 0x1208, 0x0c50, 0x012e, 0x000e, 0x003e, 0x00ce, + 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0xa188, 0x936e, 0x210c, + 0x81ff, 0x0170, 0x2061, 0x9900, 0x2071, 0x9200, 0x0016, 0x080c, + 0x749c, 0x001e, 0x0138, 0x611a, 0x080c, 0x266c, 0x080c, 0x74f2, + 0xa006, 0x0010, 0xa085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, + 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, + 0x005e, 0x0170, 0x6612, 0x651a, 0x601f, 0x0003, 0x2009, 0x004b, + 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, + 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, + 0x00c6, 0x080c, 0x749c, 0x005e, 0x01f8, 0x6013, 0x0000, 0x651a, + 0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x460d, 0x00ce, 0x080c, + 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, + 0x8ee4, 0x008e, 0x2009, 0x004c, 0x080c, 0x7518, 0xa085, 0x0001, + 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, + 0x0126, 0x2091, 0x8000, 0x62a0, 0x00c6, 0x080c, 0x749c, 0x005e, + 0x0500, 0x6612, 0x651a, 0x601f, 0x0003, 0x2019, 0x0005, 0x00c6, + 0x2560, 0x080c, 0x460d, 0x00ce, 0x080c, 0x6127, 0x0086, 0x2041, + 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x2009, + 0x004d, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, + 0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, + 0x62a0, 0x00c6, 0x080c, 0x749c, 0x005e, 0x0500, 0x6612, 0x651a, + 0x601f, 0x0003, 0x2019, 0x0005, 0x00c6, 0x2560, 0x080c, 0x460d, + 0x00ce, 0x080c, 0x6127, 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, + 0x2c08, 0x080c, 0x8ee4, 0x008e, 0x2009, 0x004e, 0x080c, 0x7518, + 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, + 0x00c6, 0x0096, 0x0086, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, + 0x00c6, 0x080c, 0x749c, 0x005e, 0x0904, 0x8426, 0x6612, 0x651a, + 0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x45af, 0x0118, 0x2001, + 0x83ec, 0x0028, 0x080c, 0x4581, 0x0160, 0x2001, 0x83f2, 0x0006, + 0xa00e, 0x2001, 0x0004, 0x080c, 0x492c, 0x080c, 0x4809, 0x000e, + 0x0807, 0x2019, 0x0004, 0x080c, 0x632b, 0x0036, 0x003e, 0x00ce, + 0x2041, 0x0001, 0x2608, 0x080c, 0x6140, 0x080c, 0x606d, 0x2c08, + 0x2648, 0x080c, 0x8ee4, 0x6018, 0xa080, 0x000f, 0x200c, 0x81ff, + 0x090c, 0x61d3, 0x2009, 0x0052, 0x080c, 0x7518, 0xa085, 0x0001, + 0x012e, 0x005e, 0x008e, 0x009e, 0x00ce, 0x0005, 0xa006, 0x0cc0, + 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, + 0x0178, 0x660a, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, + 0x001f, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, + 0x749c, 0x001e, 0x0178, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, + 0x6012, 0x2009, 0x0021, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, + 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, + 0x00c6, 0x080c, 0x749c, 0x001e, 0x0178, 0x660a, 0x611a, 0x601f, + 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x080c, 0x7518, 0xa085, + 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, + 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0170, 0x611a, + 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x7518, + 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x0026, + 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, + 0x00de, 0x002e, 0x0005, 0x0006, 0x6013, 0x0000, 0x601f, 0x0007, + 0x2001, 0x94dd, 0x2004, 0x6016, 0x000e, 0x0005, 0x0066, 0x00c6, + 0x00d6, 0x2031, 0x9252, 0x2634, 0xd6e4, 0x0128, 0x6618, 0x2660, + 0x6e48, 0x080c, 0x453a, 0x00de, 0x00ce, 0x006e, 0x0005, 0x0006, + 0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, 0x0128, + 0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005, + 0x0006, 0x00d6, 0x6010, 0xa06d, 0x0128, 0x6838, 0xd0fc, 0x0110, + 0xa006, 0x0010, 0xa085, 0x0001, 0x00de, 0x000e, 0x0005, 0x00c6, + 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x749c, 0x001e, 0x0180, + 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x080c, 0x266c, 0x2009, + 0x0028, 0x080c, 0x7518, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, + 0xa006, 0x0cd8, 0xa186, 0x0015, 0x1178, 0x2011, 0x9220, 0x2204, + 0xa086, 0x0074, 0x1148, 0x080c, 0x7a64, 0x6003, 0x0001, 0x6007, + 0x0029, 0x080c, 0x603e, 0x0020, 0x080c, 0x7776, 0x080c, 0x74f2, + 0x0005, 0xa186, 0x0015, 0x11b0, 0x2011, 0x9220, 0x2204, 0xa086, + 0x0014, 0x1180, 0x00d6, 0x6018, 0x2068, 0x080c, 0x44c7, 0x00de, + 0x080c, 0x7a6e, 0x1138, 0x2001, 0x0006, 0x080c, 0x43e3, 0x080c, + 0x7598, 0x0020, 0x080c, 0x7776, 0x080c, 0x74f2, 0x0005, 0x6848, + 0xa086, 0x0005, 0x1108, 0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, + 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x2001, 0x94d9, 0x200c, + 0x8000, 0x2014, 0x2001, 0x0064, 0x080c, 0x5eaf, 0x2001, 0x94dd, + 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202, 0x003e, 0x002e, 0x001e, + 0x000e, 0x0005, 0x0006, 0x2001, 0x94dd, 0x2003, 0x0028, 0x2001, + 0x94de, 0x2003, 0x07d0, 0x000e, 0x0005, 0x0066, 0x6000, 0xa0b2, + 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, 0x0005, 0x856e, 0x881c, + 0x8907, 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x85a6, 0x8973, + 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x856e, 0x080c, 0x13fe, + 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x13fe, 0x0013, 0x006e, + 0x0005, 0x8589, 0x8ce9, 0x8589, 0x8589, 0x8589, 0x8589, 0x8589, + 0x8589, 0x8cad, 0x8d31, 0x8589, 0x9105, 0x9135, 0x9105, 0x9135, + 0x8589, 0x080c, 0x13fe, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, + 0x13fe, 0x0013, 0x006e, 0x0005, 0x85a4, 0x8ab9, 0x8b64, 0x8b88, + 0x8bd3, 0x85a4, 0x85a4, 0x8c44, 0x897f, 0x8c87, 0x8c9a, 0x85a4, + 0x85a4, 0x85a4, 0x85a4, 0x85a4, 0x080c, 0x13fe, 0xa1b2, 0x003e, + 0x1a0c, 0x13fe, 0x2100, 0x0002, 0x85df, 0x86f0, 0x85df, 0x85df, + 0x85df, 0x86f7, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, + 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, + 0x85df, 0x85df, 0x85df, 0x85e1, 0x860b, 0x8616, 0x865a, 0x8674, + 0x86aa, 0x86dd, 0x85df, 0x85df, 0x86fa, 0x85df, 0x85df, 0x8709, + 0x8710, 0x85df, 0x85df, 0x85df, 0x85df, 0x85df, 0x87ab, 0x85df, + 0x85df, 0x87b5, 0x85df, 0x85df, 0x875d, 0x85df, 0x85df, 0x080c, + 0x13fe, 0x080c, 0x470e, 0x6618, 0x00c6, 0x2660, 0x080c, 0x4443, + 0x00ce, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, + 0x0278, 0x080c, 0x8e28, 0x1904, 0x8654, 0x080c, 0x8dd3, 0x1120, + 0x6007, 0x0008, 0x0804, 0x86eb, 0x6007, 0x0009, 0x0804, 0x86eb, + 0x080c, 0x8fa4, 0x0128, 0x080c, 0x8e28, 0x0d78, 0x0804, 0x8654, + 0x6013, 0x1900, 0x0c88, 0x6106, 0x080c, 0x8d83, 0x6007, 0x0006, + 0x0804, 0x86eb, 0x6007, 0x0007, 0x0804, 0x86eb, 0x080c, 0x9150, + 0x1904, 0x87c6, 0x00d6, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x01a0, 0xa686, 0x0004, 0x0188, 0x080c, + 0x4dc5, 0x1160, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0140, + 0xa686, 0x0004, 0x0128, 0xa686, 0x0005, 0x0110, 0x00de, 0x00e0, + 0x080c, 0x8e86, 0x11a0, 0xa686, 0x0006, 0x1150, 0x0026, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x26b1, 0x002e, + 0x080c, 0x44c7, 0x6007, 0x000a, 0x00de, 0x0804, 0x86eb, 0x6007, + 0x000b, 0x00de, 0x0804, 0x86eb, 0x080c, 0x266c, 0x6007, 0x0001, + 0x0804, 0x86eb, 0x080c, 0x9150, 0x1904, 0x87c6, 0x6618, 0x00d6, + 0x2668, 0x6e04, 0x00de, 0xa686, 0x0707, 0x0d70, 0x0026, 0x6218, + 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x26b1, 0x002e, + 0x6007, 0x000c, 0x0804, 0x86eb, 0x080c, 0x470e, 0x6618, 0xa6b0, + 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x02b0, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0004, 0x0118, 0xa686, 0x0006, 0x1960, + 0x080c, 0x8e93, 0x1120, 0x6007, 0x000e, 0x0804, 0x86eb, 0x080c, + 0x266c, 0x6007, 0x000f, 0x0804, 0x86eb, 0x080c, 0x8fa4, 0x0160, + 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004, 0x0a04, 0x8654, 0xa682, + 0x0007, 0x0e30, 0x0804, 0x8654, 0x6013, 0x1900, 0x6007, 0x0009, + 0x0804, 0x86eb, 0x080c, 0x470e, 0x6618, 0xa6b0, 0x0001, 0x2634, + 0xa684, 0x00ff, 0xa082, 0x0006, 0x02c0, 0xa6b4, 0xff00, 0x8637, + 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0x8654, 0x080c, + 0x8ebb, 0x1130, 0x080c, 0x8dd3, 0x1118, 0x6007, 0x0010, 0x0418, + 0x080c, 0x266c, 0x6007, 0x0011, 0x00f0, 0x080c, 0x8fa4, 0x0140, + 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0d48, 0x0804, 0x8654, + 0x6013, 0x1900, 0x6007, 0x0009, 0x0070, 0x7030, 0xa086, 0x6000, + 0x0140, 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, 0x1904, + 0x8654, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x603e, 0x0005, + 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x603e, 0x0cc0, 0x6007, + 0x0005, 0x0cc0, 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, + 0x1904, 0x8654, 0x6007, 0x0020, 0x6003, 0x0001, 0x080c, 0x603e, + 0x0005, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x603e, 0x0005, + 0x080c, 0x9150, 0x1904, 0x87c6, 0x080c, 0x87c9, 0x1904, 0x8654, + 0x0016, 0x0026, 0x2011, 0x9791, 0x2214, 0xa286, 0xffff, 0x0190, + 0x2c08, 0x080c, 0x82de, 0x01d8, 0x2260, 0x2011, 0x9790, 0x2214, + 0x6008, 0xa206, 0x11a0, 0x6018, 0xa190, 0x0006, 0x2214, 0xa206, + 0x01e0, 0x0068, 0x2011, 0x9790, 0x2214, 0x2c08, 0x080c, 0x90ab, + 0x11a0, 0x2011, 0x9791, 0x2214, 0xa286, 0xffff, 0x01a0, 0x2160, + 0x6007, 0x0026, 0x6013, 0x1700, 0x2011, 0x9789, 0x2214, 0xa296, + 0xffff, 0x1160, 0x6007, 0x0025, 0x0048, 0x601c, 0xa086, 0x0007, + 0x1d70, 0x080c, 0x74f2, 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, + 0x080c, 0x603e, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, + 0x43d1, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, + 0x9205, 0x2011, 0x9796, 0x080c, 0x7aee, 0x003e, 0x002e, 0x001e, + 0x015e, 0x0120, 0x6007, 0x0031, 0x0804, 0x86eb, 0x080c, 0x7910, + 0x080c, 0x4dc5, 0x1578, 0x0006, 0x0026, 0x0036, 0x2011, 0x9223, + 0x2204, 0x8000, 0x2012, 0xa084, 0x0007, 0x0190, 0x2001, 0x94d7, + 0x2003, 0xaaaa, 0x2001, 0x94d8, 0x2003, 0x0001, 0x2001, 0x9200, + 0x2003, 0x0001, 0x080c, 0x4d10, 0x003e, 0x002e, 0x000e, 0x0005, + 0x2001, 0x0001, 0x080c, 0x23ba, 0x080c, 0x4dd7, 0x1110, 0x080c, + 0x4d9a, 0x2011, 0x8036, 0x2019, 0x0005, 0x080c, 0x3698, 0x003e, + 0x002e, 0x000e, 0x0005, 0x6106, 0x0479, 0x6007, 0x002b, 0x0804, + 0x86eb, 0x6007, 0x002c, 0x0804, 0x86eb, 0x080c, 0x9150, 0x1170, + 0x0081, 0x1904, 0x8654, 0x6106, 0x0419, 0x1120, 0x6007, 0x002e, + 0x0804, 0x86eb, 0x6007, 0x002f, 0x0804, 0x86eb, 0x080c, 0x74f2, + 0x0005, 0x00d6, 0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, + 0x8637, 0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, + 0x0001, 0x006e, 0x00de, 0x0005, 0x00d6, 0x0439, 0x00de, 0x0005, + 0x00d6, 0x0481, 0x11e0, 0x680c, 0xa08c, 0xff00, 0x6824, 0xa084, + 0x00ff, 0xa115, 0x6212, 0xd1e4, 0x0118, 0x2009, 0x0001, 0x0060, + 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x080c, 0x240b, + 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x26b1, 0x0018, 0xa085, + 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, 0x978d, 0x6800, + 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, 0x0001, 0x0008, + 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0x978c, 0x6808, 0xa084, + 0xff00, 0xa086, 0x0800, 0x0005, 0x6004, 0xa0b2, 0x003e, 0x1a0c, + 0x13fe, 0xa1b6, 0x0013, 0x1110, 0x2008, 0x0092, 0xa1b6, 0x0027, + 0x0120, 0xa1b6, 0x0014, 0x190c, 0x13fe, 0x2001, 0x0007, 0x080c, + 0x43f1, 0x080c, 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, + 0x8875, 0x8877, 0x8875, 0x8875, 0x8875, 0x8877, 0x8885, 0x88e7, + 0x88b2, 0x88e7, 0x88c3, 0x88e7, 0x8885, 0x88e7, 0x88df, 0x88e7, + 0x88df, 0x88e7, 0x88e7, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x88e7, 0x8875, 0x8875, 0x88e7, 0x8875, 0x88e7, 0x88e7, 0x8875, + 0x8875, 0x8875, 0x8875, 0x88e7, 0x88e7, 0x8875, 0x88e7, 0x88e7, + 0x8875, 0x887f, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, + 0x8875, 0x8875, 0x8875, 0x8875, 0x8875, 0x080c, 0x13fe, 0x080c, + 0x6389, 0x6003, 0x0002, 0x080c, 0x6462, 0x0804, 0x88ed, 0x2001, + 0x0000, 0x080c, 0x43d1, 0x0804, 0x88e7, 0x00f6, 0x2079, 0x9251, + 0x7804, 0x00fe, 0xd0ac, 0x1904, 0x88e7, 0x2001, 0x0000, 0x080c, + 0x43d1, 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0904, + 0x88e7, 0x2001, 0x0002, 0x080c, 0x43e3, 0x080c, 0x6389, 0x601f, + 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x603e, 0x080c, + 0x6462, 0x00c6, 0x6118, 0x2160, 0x2009, 0x0001, 0x080c, 0x573d, + 0x00ce, 0x04d8, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, + 0xff00, 0x8637, 0xa686, 0x0006, 0x0550, 0xa686, 0x0004, 0x0538, + 0x2001, 0x0004, 0x0410, 0x2001, 0x9200, 0x2004, 0xa086, 0x0003, + 0x1110, 0x080c, 0x370a, 0x2001, 0x0006, 0x0401, 0x6618, 0x00d6, + 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, + 0x0170, 0x2001, 0x0006, 0x0048, 0x2001, 0x0004, 0x0030, 0x2001, + 0x0006, 0x0061, 0x0020, 0x0018, 0x0010, 0x080c, 0x43f1, 0x080c, + 0x6389, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x0016, 0x00d6, + 0x6118, 0x2168, 0x6900, 0xd184, 0x0178, 0x6104, 0xa18e, 0x000a, + 0x1128, 0x699c, 0xd1a4, 0x1110, 0x2001, 0x0007, 0x2001, 0x0000, + 0x080c, 0x43d1, 0x080c, 0x2692, 0x00de, 0x001e, 0x0005, 0x00d6, + 0x6618, 0x2668, 0x6804, 0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2, + 0x000c, 0x1a0c, 0x13fe, 0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028, + 0xa1b6, 0x0016, 0x190c, 0x13fe, 0x04eb, 0x0005, 0x7805, 0x7805, + 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, 0x892a, 0x7805, 0x7805, + 0x7805, 0x7805, 0x00f6, 0x2079, 0x9251, 0x7804, 0x00fe, 0xd0ac, + 0x1198, 0x2001, 0x0000, 0x080c, 0x43d1, 0x2001, 0x0002, 0x080c, + 0x43e3, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, + 0x603e, 0x080c, 0x6462, 0x00a8, 0x2011, 0x9783, 0x2204, 0x8211, + 0x220c, 0x080c, 0x240b, 0x1168, 0x00c6, 0x080c, 0x4434, 0x0120, + 0x00ce, 0x080c, 0x74f2, 0x0028, 0x080c, 0x41e0, 0x00ce, 0x080c, + 0x74f2, 0x0005, 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, 0x7805, + 0x7805, 0x8966, 0x7805, 0x7805, 0x7805, 0x7805, 0x080c, 0x7a61, + 0x1138, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x603e, 0x0010, + 0x080c, 0x74f2, 0x0005, 0x6004, 0xa08a, 0x003e, 0x1a0c, 0x13fe, + 0x080c, 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa182, + 0x0040, 0x0002, 0x8995, 0x8995, 0x8995, 0x8995, 0x8997, 0x8995, + 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, + 0x8995, 0x8995, 0x8995, 0x8995, 0x8995, 0x080c, 0x13fe, 0x00d6, + 0x00e6, 0x00f6, 0x0156, 0x0046, 0x0026, 0x6106, 0x2071, 0x9780, + 0x7444, 0xa4a4, 0xf600, 0x0904, 0x8a0d, 0xa486, 0x2000, 0x01f0, + 0xa486, 0x0400, 0x01d8, 0xa486, 0x1000, 0x0178, 0xa486, 0x4000, + 0x01d8, 0xa486, 0x0200, 0x0120, 0x080c, 0x74f2, 0x0804, 0x8a67, + 0x6118, 0x2104, 0xc0fd, 0x200a, 0x0078, 0x2069, 0x9566, 0x6a00, + 0xd284, 0x0904, 0x8a79, 0xc2cd, 0x6a02, 0x0030, 0x2009, 0x0001, + 0x2011, 0x0200, 0x080c, 0x585b, 0x080c, 0x147c, 0x090c, 0x13fe, + 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, + 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, 0x6018, 0x2078, + 0x78a0, 0x8007, 0x7130, 0x694a, 0x0016, 0xa084, 0xff00, 0x6846, + 0x684f, 0x0000, 0x6857, 0x0036, 0x080c, 0x4809, 0x001e, 0xa486, + 0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0x9071, 0x0804, 0x8a67, + 0xa486, 0x0400, 0x1130, 0x2019, 0x0002, 0x080c, 0x9033, 0x0804, + 0x8a67, 0xa486, 0x0200, 0x1110, 0x080c, 0x9020, 0xa486, 0x1000, + 0x1110, 0x080c, 0x905e, 0x0804, 0x8a67, 0x2069, 0x9566, 0x6a00, + 0xd284, 0x0904, 0x8ab6, 0xa284, 0x0300, 0x1904, 0x8ab0, 0x6804, + 0xa005, 0x0904, 0x8aa1, 0x2d78, 0x6003, 0x0007, 0x6018, 0x2004, + 0xd0fc, 0x1904, 0x8ab0, 0x080c, 0x145f, 0x0904, 0x8a6e, 0x7800, + 0xd08c, 0x1118, 0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, + 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, + 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, + 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, + 0x684f, 0x0040, 0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, + 0x0010, 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0x9790, 0xad90, + 0x0015, 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0x8a59, + 0x200c, 0x6982, 0x8000, 0x200c, 0x697e, 0x080c, 0x4809, 0x002e, + 0x004e, 0x015e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x6013, 0x0100, + 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x0c70, 0x2069, 0x9792, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, + 0x11a8, 0x2069, 0x9780, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, + 0xa18c, 0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, + 0x0043, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0888, 0x6013, 0x0200, + 0x6003, 0x0001, 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, + 0x0830, 0x6013, 0x0300, 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, + 0x6007, 0x0041, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x0804, 0x8a67, + 0x6013, 0x0500, 0x0c98, 0x6013, 0x0600, 0x0818, 0x6013, 0x0200, + 0x0800, 0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, + 0x13fe, 0xa08a, 0x0053, 0x1a0c, 0x13fe, 0xa082, 0x0040, 0x2008, + 0x0804, 0x8b24, 0xa186, 0x0047, 0x11b8, 0x2001, 0x0109, 0x2004, + 0xd084, 0x01f0, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x0026, + 0x080c, 0x5ee3, 0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, + 0x0002, 0x1170, 0x0804, 0x8b64, 0xa186, 0x0027, 0x0120, 0xa186, + 0x0014, 0x190c, 0x13fe, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, + 0x080c, 0x7526, 0x0005, 0x8b06, 0x8b08, 0x8b08, 0x8b06, 0x8b06, + 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, + 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x8b06, 0x080c, 0x13fe, + 0x080c, 0x6389, 0x080c, 0x6462, 0x0036, 0x00d6, 0x6010, 0xa06d, + 0x0180, 0xad84, 0xf000, 0x0168, 0x2019, 0x0004, 0x080c, 0x9097, + 0x6013, 0x0000, 0x6014, 0xa005, 0x1110, 0x6017, 0x0014, 0x6003, + 0x0007, 0x00de, 0x003e, 0x0005, 0x0002, 0x8b38, 0x8b55, 0x8b41, + 0x8b5e, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, + 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, 0x8b38, + 0x080c, 0x13fe, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, + 0x200a, 0x080c, 0x6389, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, + 0x0138, 0x6003, 0x0007, 0x2009, 0x0043, 0x080c, 0x7518, 0x0010, + 0x6003, 0x0002, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, 0x080c, + 0x5836, 0x080c, 0x74f2, 0x080c, 0x6462, 0x0005, 0x080c, 0x6389, + 0x2009, 0x0041, 0x0804, 0x8c44, 0xa182, 0x0040, 0x0002, 0x8b7a, + 0x8b7c, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7d, 0x8b7a, + 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, 0x8b7a, + 0x8b7a, 0x8b7a, 0x080c, 0x13fe, 0x0005, 0x6003, 0x0004, 0x6110, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x0005, + 0xa182, 0x0040, 0x0002, 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, + 0x8b9e, 0x8b9e, 0x8b9e, 0x8b9e, 0x8ba0, 0x8bc0, 0x8b9e, 0x8b9e, + 0x8b9e, 0x8b9e, 0x8bc0, 0x8b9e, 0x8b9e, 0x8b9e, 0x080c, 0x13fe, + 0x080c, 0x641b, 0x080c, 0x651c, 0x6010, 0x00d6, 0x2068, 0x684c, + 0xd0fc, 0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0158, 0x2009, + 0x0041, 0x00de, 0x0804, 0x8c44, 0x6003, 0x0007, 0x080c, 0x5836, + 0x00de, 0x0005, 0x080c, 0x5836, 0x080c, 0x74f2, 0x00de, 0x0cc8, + 0x0036, 0x080c, 0x641b, 0x080c, 0x651c, 0x6010, 0x00d6, 0x2068, + 0x2019, 0x0004, 0x080c, 0x9097, 0x080c, 0x849b, 0x6017, 0x0028, + 0x00de, 0x003e, 0x0005, 0xa186, 0x0013, 0x1150, 0x6004, 0xa086, + 0x0042, 0x190c, 0x13fe, 0x080c, 0x6389, 0x080c, 0x6462, 0x0005, + 0xa186, 0x0027, 0x0118, 0xa186, 0x0014, 0x1180, 0x6004, 0xa086, + 0x0042, 0x190c, 0x13fe, 0x2001, 0x0007, 0x080c, 0x43f1, 0x080c, + 0x6389, 0x080c, 0x849b, 0x080c, 0x6462, 0x0005, 0xa182, 0x0040, + 0x0002, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, + 0x8c0e, 0x8c1a, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, + 0x8c0c, 0x8c0c, 0x8c0c, 0x8c0c, 0x080c, 0x13fe, 0x0036, 0x0046, + 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x16c6, 0x004e, + 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068, 0x6810, 0x6a14, 0xa20d, + 0x1168, 0x684c, 0xd0fc, 0x0120, 0x2009, 0x0041, 0x00de, 0x00e0, + 0x6003, 0x0007, 0x080c, 0x5836, 0x00de, 0x0005, 0x6003, 0x0007, + 0x0021, 0x080c, 0x5838, 0x00de, 0x0005, 0xd2fc, 0x0140, 0x8002, + 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, 0x0010, 0x2009, + 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040, 0x0002, 0x8c5a, + 0x8c5c, 0x8c68, 0x8c74, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c83, 0x8c5a, + 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, 0x8c5a, + 0x8c5a, 0x8c5a, 0x080c, 0x13fe, 0x6003, 0x0001, 0x6106, 0x080c, + 0x5ff8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, + 0x6003, 0x0001, 0x6106, 0x080c, 0x5ff8, 0x0126, 0x2091, 0x8000, + 0x080c, 0x6462, 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10, + 0x080c, 0x1c88, 0x0126, 0x2091, 0x8000, 0x080c, 0x605b, 0x080c, + 0x651c, 0x012e, 0x0005, 0xa016, 0x080c, 0x16c6, 0x0005, 0x080c, + 0x6389, 0x6110, 0x81ff, 0x0148, 0x00d6, 0x2168, 0x0036, 0x2019, + 0x0029, 0x080c, 0x9097, 0x003e, 0x00de, 0x080c, 0x849b, 0x080c, + 0x6462, 0x0005, 0x080c, 0x641b, 0x6110, 0x81ff, 0x0148, 0x00d6, + 0x2168, 0x0036, 0x2019, 0x0029, 0x080c, 0x9097, 0x003e, 0x00de, + 0x080c, 0x849b, 0x080c, 0x651c, 0x0005, 0xa182, 0x0085, 0x0002, + 0x8cb9, 0x8cb7, 0x8cb7, 0x8cc5, 0x8cb7, 0x8cb7, 0x8cb7, 0x080c, + 0x13fe, 0x6003, 0x000b, 0x6106, 0x080c, 0x5ff8, 0x0126, 0x2091, + 0x8000, 0x080c, 0x6462, 0x012e, 0x0005, 0x0026, 0x00e6, 0x080c, + 0x9150, 0x0118, 0x080c, 0x74f2, 0x00c8, 0x2071, 0x9780, 0x7224, + 0x6212, 0x7220, 0x080c, 0x8f71, 0x0118, 0x6007, 0x0086, 0x0040, + 0x6007, 0x0087, 0x7224, 0xa296, 0xffff, 0x1110, 0x6007, 0x0086, + 0x6003, 0x0001, 0x080c, 0x5ff8, 0x080c, 0x6462, 0x00ee, 0x002e, + 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, + 0x13fe, 0xa08a, 0x008c, 0x1a0c, 0x13fe, 0xa082, 0x0085, 0x00a2, + 0xa186, 0x0027, 0x0130, 0xa186, 0x0014, 0x0118, 0x080c, 0x7526, + 0x0050, 0x2001, 0x0007, 0x080c, 0x43f1, 0x080c, 0x6389, 0x080c, + 0x849b, 0x080c, 0x6462, 0x0005, 0x8d13, 0x8d15, 0x8d15, 0x8d13, + 0x8d13, 0x8d13, 0x8d13, 0x080c, 0x13fe, 0x080c, 0x6389, 0x080c, + 0x74f2, 0x080c, 0x6462, 0x0005, 0xa182, 0x0085, 0x0a0c, 0x13fe, + 0xa182, 0x008c, 0x1a0c, 0x13fe, 0xa182, 0x0085, 0x0002, 0x8d2e, + 0x8d2e, 0x8d2e, 0x8d30, 0x8d2e, 0x8d2e, 0x8d2e, 0x080c, 0x13fe, + 0x0005, 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, + 0x0027, 0x0118, 0x080c, 0x7526, 0x0030, 0x080c, 0x6389, 0x080c, + 0x849b, 0x080c, 0x6462, 0x0005, 0x0036, 0x2019, 0x000b, 0x0031, + 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036, + 0x0086, 0x2091, 0x8000, 0x2c40, 0x080c, 0x724a, 0x1540, 0x080c, + 0x72e2, 0x1528, 0x6000, 0xa086, 0x0000, 0x0508, 0x601c, 0xa086, + 0x0007, 0x01e8, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1140, 0x601f, + 0x0007, 0x2001, 0x94dd, 0x2004, 0x6016, 0x080c, 0x1788, 0x6010, + 0x2068, 0x080c, 0x82ee, 0x0110, 0x080c, 0x9097, 0x00de, 0x6013, + 0x0000, 0x601f, 0x0007, 0x2001, 0x94dd, 0x2004, 0x6016, 0x008e, + 0x003e, 0x012e, 0x0005, 0x00f6, 0x00c6, 0x0036, 0x0156, 0x2079, + 0x9780, 0x7938, 0x783c, 0x080c, 0x240b, 0x1904, 0x8dce, 0x0016, + 0x00c6, 0x080c, 0x4434, 0x15c0, 0x2011, 0x9790, 0xac98, 0x000a, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1578, 0x001e, 0x002e, 0x0026, + 0x0016, 0x2019, 0x0029, 0x080c, 0x73a2, 0x080c, 0x6127, 0x0086, + 0x2041, 0x0000, 0x080c, 0x606d, 0x008e, 0x001e, 0x0086, 0x2041, + 0x0000, 0x080c, 0x8ee4, 0x008e, 0x080c, 0x460d, 0x0026, 0x6204, + 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0118, 0xa286, 0x0004, + 0x1118, 0x62a0, 0x080c, 0x2704, 0x002e, 0x001e, 0x080c, 0x41e0, + 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce, 0x001e, 0x015e, 0x003e, + 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x2009, 0x9220, + 0x2104, 0xa086, 0x0074, 0x1904, 0x8e1e, 0x2069, 0x978e, 0x690c, + 0xa182, 0x0100, 0x0678, 0x6908, 0xa184, 0x8000, 0x05a0, 0x2001, + 0x94d7, 0x2004, 0xa005, 0x1118, 0xa184, 0x0800, 0x0560, 0x6910, + 0xa18a, 0x0001, 0x0610, 0x6914, 0x2069, 0x97ae, 0x6904, 0x81ff, + 0x1198, 0x690c, 0xa182, 0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, + 0x6910, 0xa18a, 0x0001, 0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, + 0x00d0, 0x6013, 0x0100, 0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, + 0x0500, 0x0070, 0x6013, 0x0700, 0x0058, 0x6013, 0x0900, 0x0040, + 0x6013, 0x0b00, 0x0028, 0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, + 0xa085, 0x0001, 0x0008, 0xa006, 0x001e, 0x00de, 0x00ce, 0x0005, + 0x00c6, 0x00d6, 0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, + 0xa394, 0x00ff, 0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, + 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, + 0x0130, 0x00c6, 0x2d60, 0x080c, 0x4443, 0x00ce, 0x04c0, 0x2011, + 0x9796, 0xad98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1580, + 0x2011, 0x979a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x7aee, + 0x1538, 0x0046, 0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, + 0x2009, 0x9252, 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, + 0x90d7, 0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x6127, + 0x0086, 0x2041, 0x0000, 0x080c, 0x606d, 0x2c08, 0x080c, 0x8ee4, + 0x008e, 0x2001, 0x0007, 0x080c, 0x43f1, 0x001e, 0x004e, 0xa006, + 0x015e, 0x003e, 0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, + 0x978e, 0x6800, 0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, + 0xa006, 0x00de, 0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, + 0x0156, 0x2079, 0x978c, 0x7930, 0x7834, 0x080c, 0x240b, 0x11a0, + 0x080c, 0x4434, 0x1188, 0x2011, 0x9790, 0xac98, 0x000a, 0x20a9, + 0x0004, 0x080c, 0x7aee, 0x1140, 0x2011, 0x9794, 0xac98, 0x0006, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x015e, 0x003e, 0x002e, 0x001e, + 0x00fe, 0x00ce, 0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, + 0x0156, 0x2011, 0x9783, 0x2204, 0x8211, 0x220c, 0x080c, 0x240b, + 0x11a0, 0x080c, 0x4434, 0x1188, 0x2011, 0x9796, 0xac98, 0x000a, + 0x20a9, 0x0004, 0x080c, 0x7aee, 0x1140, 0x2011, 0x979a, 0xac98, + 0x0006, 0x20a9, 0x0004, 0x080c, 0x7aee, 0x015e, 0x003e, 0x002e, + 0x001e, 0x000e, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0076, 0x0066, + 0x0056, 0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2029, 0x94ee, + 0x252c, 0x2021, 0x94f4, 0x2424, 0x2061, 0x9900, 0x2071, 0x9200, + 0x7644, 0x7064, 0x8001, 0xa602, 0x1a04, 0x8f44, 0x2100, 0xac06, + 0x05d0, 0x080c, 0x90ee, 0x05b8, 0x671c, 0xa786, 0x0001, 0x0904, + 0x8f56, 0xa786, 0x0007, 0x0578, 0x2500, 0xac06, 0x0560, 0x2400, + 0xac06, 0x0548, 0x080c, 0x90fe, 0x1530, 0x88ff, 0x0118, 0x6020, + 0xa906, 0x1508, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016, + 0x080c, 0x1788, 0x001e, 0x6010, 0x2068, 0x080c, 0x82ee, 0x0180, + 0xa786, 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, + 0x0016, 0x080c, 0x8527, 0x080c, 0x4809, 0x001e, 0x080c, 0x848f, + 0x00de, 0x080c, 0x849b, 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, + 0xac02, 0x1210, 0x0804, 0x8ef6, 0x012e, 0x002e, 0x004e, 0x005e, + 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0xa786, 0x0006, 0x19d8, + 0xa386, 0x0005, 0x0d40, 0x080c, 0x9097, 0x0c10, 0x080c, 0x90fe, + 0x1d10, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x19e0, 0x6000, + 0xa086, 0x0002, 0x19c0, 0x080c, 0x84b7, 0x0130, 0x080c, 0x84c8, + 0x1990, 0x080c, 0x7776, 0x0010, 0x080c, 0x2692, 0x080c, 0x849b, + 0x0850, 0x00c6, 0x00e6, 0x0016, 0x2c08, 0x2170, 0x080c, 0x90ab, + 0x001e, 0x0120, 0x601c, 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, + 0x0005, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f89, 0x8f8b, + 0x8f89, 0xa006, 0x0005, 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, + 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, + 0x90d7, 0x001e, 0x004e, 0x0036, 0x2019, 0x0002, 0x080c, 0x8d4e, + 0x003e, 0xa085, 0x0001, 0x0005, 0x2001, 0x0001, 0x080c, 0x43d1, + 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x9205, + 0x2011, 0x9796, 0x080c, 0x7aee, 0x003e, 0x002e, 0x001e, 0x015e, + 0xa005, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x0026, + 0x0126, 0x2091, 0x8000, 0x2061, 0x9900, 0x2079, 0x0001, 0x8fff, + 0x0904, 0x9014, 0x2071, 0x9200, 0x7644, 0x7064, 0x8001, 0xa602, + 0x1a04, 0x9014, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15a0, 0x2079, + 0x0000, 0x080c, 0x90ee, 0x0578, 0x2400, 0xac06, 0x0560, 0x671c, + 0xa786, 0x0006, 0x1540, 0xa786, 0x0007, 0x0528, 0x88ff, 0x1140, + 0x6018, 0xa206, 0x1500, 0x85ff, 0x0118, 0x6020, 0xa106, 0x11d8, + 0x00d6, 0x6000, 0xa086, 0x0004, 0x1140, 0x601f, 0x0007, 0x2001, + 0x94dd, 0x2004, 0x6016, 0x080c, 0x1788, 0x6010, 0x2068, 0x080c, + 0x82ee, 0x0120, 0x0046, 0x080c, 0x9097, 0x004e, 0x00de, 0x080c, + 0x849b, 0x88ff, 0x1190, 0xace0, 0x000c, 0x2001, 0x9216, 0x2004, + 0xac02, 0x1210, 0x0804, 0x8fc7, 0xa006, 0x012e, 0x002e, 0x006e, + 0x007e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0xa8c5, 0x0001, 0x0ca8, + 0x0086, 0x0056, 0x2041, 0x0000, 0x2029, 0x0001, 0x2c20, 0x2019, + 0x0002, 0x6218, 0x080c, 0x724a, 0x080c, 0x72e2, 0x080c, 0x8fba, + 0x005e, 0x008e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0086, 0x00c6, + 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, + 0x0036, 0x080c, 0x4434, 0x1170, 0x2c10, 0x2041, 0x0000, 0x2508, + 0x0056, 0x2029, 0x0001, 0x080c, 0x724a, 0x080c, 0x72e2, 0x080c, + 0x8fba, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, 0x903f, 0x015e, + 0x00ce, 0x008e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0086, 0x0056, + 0x6218, 0x2041, 0x0000, 0x2029, 0x0001, 0x2019, 0x0048, 0x080c, + 0x724a, 0x080c, 0x72e2, 0x2c20, 0x080c, 0x8fba, 0x005e, 0x008e, + 0x0005, 0x0026, 0x0046, 0x0056, 0x0086, 0x00c6, 0x0156, 0x2c20, + 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, 0x080c, 0x4434, + 0x1150, 0x2c10, 0x2041, 0x0000, 0x2828, 0x080c, 0x724a, 0x080c, + 0x72e2, 0x080c, 0x8fba, 0x003e, 0x001e, 0x8108, 0x1f04, 0x907c, + 0x015e, 0x00ce, 0x008e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0016, + 0x00f6, 0x8dff, 0x0168, 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, + 0x6b52, 0x080c, 0x4809, 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x4809, + 0x00fe, 0x001e, 0x0005, 0x00e6, 0x0046, 0x0036, 0x2061, 0x9900, + 0x2071, 0x9200, 0x7444, 0x7064, 0x8001, 0xa402, 0x12d8, 0x2100, + 0xac06, 0x0168, 0x6000, 0xa086, 0x0000, 0x0148, 0x6008, 0xa206, + 0x1130, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, 0x0140, 0xace0, + 0x000c, 0x2001, 0x9216, 0x2004, 0xac02, 0x1220, 0x0c08, 0xa085, + 0x0001, 0x0008, 0xa006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x00d6, + 0x0006, 0x080c, 0x147c, 0x000e, 0x090c, 0x13fe, 0x6837, 0x010d, + 0x685e, 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, 0x68b2, 0x6802, + 0x683a, 0x685a, 0x080c, 0x4809, 0x00de, 0x0005, 0x6700, 0xa786, + 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786, 0x000a, 0x0128, + 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005, 0x00e6, 0x6018, + 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0xa186, 0x0013, 0x1128, + 0x6004, 0xa082, 0x0085, 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, + 0x080c, 0x6389, 0x0036, 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, + 0x080c, 0x9097, 0x00de, 0x003e, 0x080c, 0x6462, 0x0005, 0xa186, + 0x0014, 0x0d70, 0x080c, 0x7526, 0x0005, 0x912e, 0x912c, 0x912c, + 0x912c, 0x912c, 0x912c, 0x912e, 0x080c, 0x13fe, 0x080c, 0x6389, + 0x6003, 0x000c, 0x080c, 0x6462, 0x0005, 0xa182, 0x008c, 0x1220, + 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x7526, 0x0005, 0x9146, + 0x9146, 0x9146, 0x9146, 0x9148, 0x914d, 0x9146, 0x080c, 0x13fe, + 0x00d6, 0x080c, 0x74f2, 0x00de, 0x0005, 0x080c, 0x74f2, 0x0005, + 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x0126, + 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0x9240, 0xd5a4, 0x0118, + 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000, 0x7032, + 0xd5ac, 0x0118, 0x2071, 0x924a, 0x0451, 0x00ee, 0x000e, 0x012e, + 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0x9240, + 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, + 0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0x924a, 0x0081, 0x00ee, + 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, + 0x2071, 0x9242, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04, + 0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005, + 0x00e6, 0x2071, 0x9240, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, + 0x9244, 0x0c69, 0x00ee, 0x0005, 0x0001, 0x0002, 0x0004, 0x0008, + 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, + 0x1000, 0x2000, 0x4000, 0x8000, 0x448c }; -unsigned short risc_code_length01 = 0x65e6; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/qlogicisp.c linux.ac/drivers/scsi/qlogicisp.c --- linux.vanilla/drivers/scsi/qlogicisp.c Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/scsi/qlogicisp.c Fri Jul 2 19:22:45 1999 @@ -1065,8 +1065,10 @@ ip[0] = 255; ip[1] = 63; ip[2] = size / (ip[0] * ip[1]); +#if 0 if (ip[2] > 1023) ip[2] = 1023; +#endif } LEAVE("isp1020_biosparam"); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.c linux.ac/drivers/scsi/scsi.c --- linux.vanilla/drivers/scsi/scsi.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/scsi.c Mon Jul 19 18:03:35 1999 @@ -32,6 +32,8 @@ * Converted cli() code to spinlocks, Ingo Molnar * * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * out_of_space + add-single-device work, D. Gilbert (dpg) 990612 */ #include @@ -180,6 +182,7 @@ int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, struct Scsi_Host *shpnt, char * scsi_result); void scsi_build_commandblocks(Scsi_Device * SDpnt); +static int scsi_unregister_device(struct Scsi_Device_Template * tpnt); /* * These are the interface to the old error handling code. It should go away @@ -451,16 +454,18 @@ Scsi_Device * SDtail; int sparse_lun; - SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); - memset (SCpnt, 0, sizeof (Scsi_Cmnd)); - - SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); - memset (SDpnt, 0, sizeof (Scsi_Device)); - - - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ( ( !shpnt->unchecked_isa_dma ) - ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + scsi_result = NULL; + SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); + if (SCpnt) { + SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), + GFP_ATOMIC); + if (SDpnt) { + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ( ( !shpnt->unchecked_isa_dma ) + ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); + } + } if (scsi_result == NULL) { @@ -512,18 +517,32 @@ if(lun >= shpnt->max_lun) goto leave; scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun, &SDpnt, SCpnt, shpnt, scsi_result); + + /* See warning by (DB) in scsi_proc_info() towards end of + 'add-single-device' section. (dpg) */ + if (shpnt->select_queue_depths != NULL) + (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + if(SDpnt!=oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) + if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); - oldSDpnt->scsi_request_fn = NULL; - for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if(sdtpnt->attach) { - (*sdtpnt->attach)(oldSDpnt); - if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);} - resize_dma_pool(); + oldSDpnt->scsi_request_fn = NULL; + for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if(sdtpnt->attach) { + (*sdtpnt->attach)(oldSDpnt); + if(oldSDpnt->attached) { + scsi_build_commandblocks(oldSDpnt); + if (0 == oldSDpnt->has_cmdblocks) { + printk("scan_scsis: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } + } + } + resize_dma_pool(); for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) @@ -743,6 +762,17 @@ scsi_result[1] |= 0x80; /* removable */ } + /* + * It would seem the Panasonic DVD-RAM is backwards too + * If DVD-RAM or PD media used, it seems to function + * as Direct-Access + */ + if (!strncmp (scsi_result + 8, "MATSHITA", 7) && + !strncmp (scsi_result + 16, "PD-2 LF-D100", 12)) { + scsi_result[0] = TYPE_DISK; + scsi_result[1] |= 0x80; /* removable */ + } + memcpy (SDpnt->vendor, scsi_result + 8, 8); memcpy (SDpnt->model, scsi_result + 16, 16); memcpy (SDpnt->rev, scsi_result + 32, 4); @@ -884,8 +914,6 @@ return 0; } - memset (SDpnt, 0, sizeof (Scsi_Device)); - /* * And hook up our command block to the new device we will be testing * for. @@ -1429,6 +1457,7 @@ { struct Scsi_Host * host = SCpnt->host; Scsi_Device * device = SCpnt->device; + int mlqueue = 0; SCpnt->owner = SCSI_OWNER_MIDLEVEL; @@ -1463,6 +1492,10 @@ SCpnt->pid = scsi_pid++; while (SCSI_BLOCK((Scsi_Device *) NULL, host)) { + if (in_interrupt()){ + mlqueue = 1; + break; + } spin_unlock(&io_request_lock); /* FIXME!!! */ SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host)); spin_lock_irq(&io_request_lock); /* FIXME!!! */ @@ -1509,7 +1542,15 @@ SCpnt->internal_timeout = NORMAL_TIMEOUT; SCpnt->abort_reason = 0; SCpnt->result = 0; - internal_cmnd (SCpnt); + + if (mlqueue == 1 && host->hostt->use_new_eh_code){ + /* Assign a unique nonzero serial_number. */ + if (++serial_number == 0) serial_number = 1; + SCpnt->serial_number = serial_number; + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + } + else + internal_cmnd (SCpnt); SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n")); } @@ -1899,9 +1940,9 @@ for (order = 0, a_size = PAGE_SIZE; a_size < size; order++, a_size <<= 1) ; - retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); + retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); } else - retval = kmalloc(size, gfp_mask); + retval = kmalloc(size, gfp_mask); if (retval) memset(retval, 0, size); @@ -1970,9 +2011,10 @@ printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n", SDpnt->queue_depth, j); SDpnt->queue_depth = j; - /* Still problem if 0==j , continue anyway ... */ + SDpnt->has_cmdblocks = (0 != j); } - SDpnt->has_cmdblocks = 1; + else + SDpnt->has_cmdblocks = 1; } #ifndef MODULE /* { */ @@ -2036,7 +2078,13 @@ /* SDpnt->scsi_request_fn = NULL; */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) { + printk("scsi_dev_init: DANGER, no command blocks\n"); + /* What to do now ?? */ + } + } } } @@ -2332,8 +2380,9 @@ /* FIXME (DB) This assumes that the queue_depth routines can be used in this context as well, while they were all designed to be called only once after the detect routine. (DB) */ - if (HBA_ptr->select_queue_depths != NULL) - (HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue); + /* ... but scan_scsis(,1,,,) needs the correct queue_length. So + select_queue_depths() has been moved inside scan_scsis() and + is only used in this context (ie scan_scsis(,1,,,) ). (dpg) */ return(length); @@ -2396,7 +2445,7 @@ * Nobody is using this device any more. * Free all of the command structures. */ - for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next) + for(SCpnt=scd->device_queue; SCpnt; SCpnt = scd->device_queue) { scd->device_queue = SCpnt->next; scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); @@ -2429,7 +2478,7 @@ */ static void resize_dma_pool(void) { - int i; + int i, k; unsigned long size; struct Scsi_Host * shpnt; struct Scsi_Host * host = NULL; @@ -2438,6 +2487,7 @@ unsigned int new_dma_sectors = 0; unsigned int new_need_isa_buffer = 0; unsigned char ** new_dma_malloc_pages = NULL; + int out_of_space = 0; if( !scsi_hostlist ) { @@ -2529,27 +2579,67 @@ * race conditions that I would rather not even think * about right now. */ - if( new_dma_sectors < dma_sectors ) +#if 0 /* Why do this? No gain and risks out_of_space */ + if( new_dma_sectors < dma_sectors ) new_dma_sectors = dma_sectors; +#endif + if( new_dma_sectors <= dma_sectors ) + return; /* best to quit while we are in front */ - if (new_dma_sectors) - { - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - new_dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_freelist, 0, size); - - size = (new_dma_sectors / SECTORS_PER_PAGE)*sizeof(*new_dma_malloc_pages); - new_dma_malloc_pages = (unsigned char **) scsi_init_malloc(size, GFP_ATOMIC); - memset(new_dma_malloc_pages, 0, size); - } + for (k = 0; k < 20; ++k) { /* just in case */ + out_of_space = 0; + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + new_dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (new_dma_malloc_freelist) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(*new_dma_malloc_pages); + new_dma_malloc_pages = (unsigned char **) + scsi_init_malloc(size, GFP_ATOMIC); + if (! new_dma_malloc_pages) { + size = (new_dma_sectors / SECTORS_PER_PAGE) * + sizeof(FreeSectorBitmap); + scsi_init_free((char *)new_dma_malloc_freelist, size); + out_of_space = 1; + } + } + else + out_of_space = 1; + + if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { + for(i = dma_sectors / SECTORS_PER_PAGE; + i < new_dma_sectors / SECTORS_PER_PAGE; i++) { + new_dma_malloc_pages[i] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (! new_dma_malloc_pages[i]) + break; + } + if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */ + int k = i; - /* - * If we need more buffers, expand the list. - */ - if( new_dma_sectors > dma_sectors ) { - for(i=dma_sectors / SECTORS_PER_PAGE; i< new_dma_sectors / SECTORS_PER_PAGE; i++) - new_dma_malloc_pages[i] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + out_of_space = 1; + for (i = 0; i < k; ++i) + scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE); + } + } + if (out_of_space) { /* try scaling down new_dma_sectors request (dpg) */ + printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, " + "wanted=%u, scaling\n", dma_sectors, new_dma_sectors); + if (new_dma_sectors < (8 * SECTORS_PER_PAGE)) + break; /* pretty well hopeless ... */ + new_dma_sectors = (new_dma_sectors * 3) / 4; + new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; + if (new_dma_sectors <= dma_sectors) + break; /* stick with what we have got */ + } + else + break; /* found space ... */ + } /* end of for loop */ + if (out_of_space) { + scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */ + printk(" WARNING, not enough memory, pool not expanded\n"); + return; } /* When we dick with the actual DMA list, we need to @@ -2596,6 +2686,7 @@ struct Scsi_Device_Template * sdtpnt; const char * name; unsigned long flags; + int out_of_space = 0; if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or * no detect routine available @@ -2695,11 +2786,11 @@ { if(shpnt->hostt == tpnt) { - scan_scsis(shpnt,0,0,0,0); - if (shpnt->select_queue_depths != NULL) - { - (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); - } + scan_scsis(shpnt,0,0,0,0); + if (shpnt->select_queue_depths != NULL) + { + (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); + } } } @@ -2718,14 +2809,19 @@ { for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt); - if(SDpnt->attached) scsi_build_commandblocks(SDpnt); + if(SDpnt->attached) { + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } } } /* * Now that we have all of the devices, resize the DMA pool, * as required. */ - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); /* This does any final handling that is required. */ @@ -2746,7 +2842,13 @@ #endif MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_host(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } /* @@ -3007,6 +3109,7 @@ { Scsi_Device * SDpnt; struct Scsi_Host * shpnt; + int out_of_space = 0; if (tpnt->next) return 1; @@ -3048,6 +3151,8 @@ { SDpnt->online = TRUE; scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; } } } @@ -3056,15 +3161,22 @@ * This does any final handling that is required. */ if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)(); - resize_dma_pool(); + if (! out_of_space) + resize_dma_pool(); MOD_INC_USE_COUNT; - return 0; + + if (out_of_space) { + scsi_unregister_device(tpnt); /* easiest way to clean up?? */ + return 1; + } + else + return 0; } static int scsi_unregister_device(struct Scsi_Device_Template * tpnt) { Scsi_Device * SDpnt; - Scsi_Cmnd * SCpnt; + Scsi_Cmnd * SCpnt, *SCnext; struct Scsi_Host * shpnt; struct Scsi_Device_Template * spnt; struct Scsi_Device_Template * prev_spnt; @@ -3092,11 +3204,14 @@ * Nobody is using this device any more. Free all of the * command structures. */ - for(SCpnt = SDpnt->device_queue; SCpnt; - SCpnt = SCpnt->next) + + SCpnt = SDpnt->device_queue; + if (SCpnt) SCnext = SCpnt->next; + for(; SCpnt; SCpnt = SCnext) { if(SCpnt == SDpnt->device_queue) SDpnt->device_queue = SCpnt->next; + SCnext = SCpnt->next; scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); } SDpnt->has_cmdblocks = 0; @@ -3229,7 +3344,7 @@ printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n", i++, - SCpnt->host->host_no, + SCpnt->host ? SCpnt->host->host_no : -1, SCpnt->channel, SCpnt->target, SCpnt->lun, @@ -3294,6 +3409,7 @@ int init_module(void) { unsigned long size; + int has_space = 0; /* * This makes /proc/scsi visible. @@ -3309,7 +3425,6 @@ proc_scsi_register(0, &proc_scsi_scsi); #endif - dma_sectors = PAGE_SIZE / SECTOR_SIZE; scsi_dma_free_sectors= dma_sectors; /* @@ -3318,15 +3433,31 @@ */ /* One bit per sector to indicate free/busy */ - size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap); - dma_malloc_freelist = (FreeSectorBitmap *) scsi_init_malloc(size, GFP_ATOMIC); - memset(dma_malloc_freelist, 0, size); - - /* One pointer per page for the page list */ - dma_malloc_pages = (unsigned char **) - scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC); - dma_malloc_pages[0] = (unsigned char *) - scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap); + dma_malloc_freelist = (FreeSectorBitmap *) + scsi_init_malloc(size, GFP_ATOMIC); + if (dma_malloc_freelist) { + /* One pointer per page for the page list */ + dma_malloc_pages = (unsigned char **)scsi_init_malloc( + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages), + GFP_ATOMIC); + if (dma_malloc_pages) { + dma_malloc_pages[0] = (unsigned char *) + scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA); + if (dma_malloc_pages[0]) + has_space = 1; + } + } + if (! has_space) { + if (dma_malloc_freelist) { + scsi_init_free((char *)dma_malloc_freelist, size); + if (dma_malloc_pages) + scsi_init_free((char *)dma_malloc_pages, + (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages)); + } + printk("scsi::init_module: failed, out of memory\n"); + return 1; + } /* * This is where the processing takes place for most everything diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi.h linux.ac/drivers/scsi/scsi.h --- linux.vanilla/drivers/scsi/scsi.h Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/scsi.h Mon Jul 19 20:52:06 1999 @@ -377,6 +377,9 @@ extern int scsi_decide_disposition (Scsi_Cmnd * SCpnt); extern int scsi_block_when_processing_errors(Scsi_Device *); extern void scsi_sleep(int); +extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, + unsigned int *secs); /* * scsi_abort aborts the current command that is executing on host host. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_debug.c linux.ac/drivers/scsi/scsi_debug.c --- linux.vanilla/drivers/scsi/scsi_debug.c Sun Jan 3 03:52:01 1999 +++ linux.ac/drivers/scsi/scsi_debug.c Mon Jul 19 19:48:20 1999 @@ -22,10 +22,6 @@ #include #include -#ifdef MODULE -#include -#endif - #include #include "scsi.h" #include "hosts.h" diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/scsi_error.c linux.ac/drivers/scsi/scsi_error.c --- linux.vanilla/drivers/scsi/scsi_error.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/scsi/scsi_error.c Sat Jun 12 18:09:05 1999 @@ -1926,6 +1926,7 @@ int rtn; struct semaphore sem = MUTEX_LOCKED; unsigned long flags; + struct fs_struct *fs; lock_kernel(); @@ -1936,16 +1937,18 @@ */ exit_mm(current); - current->session = 1; current->pgrp = 1; - /* - * FIXME(eric) this is still a child process of the one that did the insmod. - * This needs to be attached to task[0] instead. - */ + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); - current->fs->umask = 0; + /* * Set the name of this process. diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sd.c linux.ac/drivers/scsi/sd.c --- linux.vanilla/drivers/scsi/sd.c Tue Jun 15 16:49:51 1999 +++ linux.ac/drivers/scsi/sd.c Wed Jun 30 00:51:13 1999 @@ -1050,6 +1050,7 @@ SCpnt->transfersize = rscsi_disks[dev].sector_size; SCpnt->underflow = this_count << 9; + SCpnt->cmd_len = 0; scsi_do_cmd (SCpnt, (void *) cmd, buff, this_count * rscsi_disks[dev].sector_size, rw_intr, @@ -1139,8 +1140,8 @@ unsigned char cmd[10]; char nbuff[6]; unsigned char *buffer; - unsigned long spintime; - int the_result, retries; + unsigned long spintime_value = 0; + int the_result, retries, spintime; Scsi_Cmnd * SCpnt; /* @@ -1235,16 +1236,18 @@ SCpnt->request.sem = NULL; } - spintime = jiffies; + spintime = 1; + spintime_value = jiffies; } time1 = jiffies + HZ; spin_unlock_irq(&io_request_lock); - while(jiffies < time1); /* Wait 1 second for next try */ + while(time_before(jiffies, time1)); /* Wait 1 second for next try */ printk( "." ); spin_lock_irq(&io_request_lock); } - } while(the_result && spintime && spintime+100*HZ > jiffies); + } while(the_result && spintime && + time_after(spintime_value+100*HZ, jiffies)); if (spintime) { if (the_result) printk( "not responding...\n" ); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sgiwd93.c linux.ac/drivers/scsi/sgiwd93.c --- linux.vanilla/drivers/scsi/sgiwd93.c Sun Nov 8 15:07:57 1998 +++ linux.ac/drivers/scsi/sgiwd93.c Tue Jun 22 01:36:47 1999 @@ -5,13 +5,14 @@ * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.1 1998/05/01 01:35:42 ralf Exp $ + * $Id: sgiwd93.c,v 1.13 1999/03/28 23:06:06 tsbogend Exp $ */ #include #include #include #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include "scsi.h" @@ -65,14 +67,40 @@ /* XXX woof! */ static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); wd33c93_intr(sgiwd93_host); + spin_unlock_irqrestore(&io_request_lock, flags); } #undef DEBUG_DMA +static inline +void fill_hpc_entries (struct hpc_chunk **hcp, char *addr, unsigned long len) +{ + unsigned long physaddr; + unsigned long count; + + dma_cache_wback_inv((unsigned long)addr,len); + physaddr = PHYSADDR(addr); + while (len) { + /* + * even cntinfo could be up to 16383, without + * magic only 8192 works correctly + */ + count = len > 8192 ? 8192 : len; + (*hcp)->desc.pbuf = physaddr; + (*hcp)->desc.cntinfo = count; + (*hcp)++; + len -= count; + physaddr += count; + } +} + static int dma_setup(Scsi_Cmnd *cmd, int datainp) { - struct WD33C93_hostdata *hdata = CMDHOSTDATA(cmd); + struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)cmd->host->hostdata; wd33c93_regs *regp = hdata->regp; struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; @@ -84,21 +112,18 @@ hdata->dma_dir = datainp; - if(cmd->use_sg) { + if(cmd->SCp.buffers_residual) { struct scatterlist *slp = cmd->SCp.buffer; int i, totlen = 0; #ifdef DEBUG_DMA printk("SCLIST<"); #endif - for(i = 0; i <= (cmd->use_sg - 1); i++, hcp++) { + for(i = 0; i <= cmd->SCp.buffers_residual; i++) { #ifdef DEBUG_DMA printk("[%p,%d]", slp[i].address, slp[i].length); #endif - dma_cache_wback_inv((unsigned long)slp[i].address, - PAGE_SIZE); - hcp->desc.pbuf = PHYSADDR(slp[i].address); - hcp->desc.cntinfo = (slp[i].length & HPCDMA_BCNT); + fill_hpc_entries (&hcp, slp[i].address, slp[i].length); totlen += slp[i].length; } #ifdef DEBUG_DMA @@ -111,10 +136,16 @@ #ifdef DEBUG_DMA printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); #endif - dma_cache_wback_inv((unsigned long)cmd->SCp.ptr, PAGE_SIZE); - hcp->desc.pbuf = PHYSADDR(cmd->SCp.ptr); - hcp->desc.cntinfo = (cmd->SCp.this_residual & HPCDMA_BCNT); - hcp++; + /* + * wd33c93 shouldn't pass us bogus dma_setups, but + * it does:-( The other wd33c93 drivers deal with + * it the same way (which isn't that obvious). + * IMHO a better fix would be, not to do these + * dma setups in the first place + */ + if (cmd->SCp.ptr == NULL) + return 1; + fill_hpc_entries (&hcp, cmd->SCp.ptr,cmd->SCp.this_residual); write_wd33c93_count(regp, cmd->SCp.this_residual); } @@ -141,9 +172,14 @@ static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, int status) { - struct WD33C93_hostdata *hdata = INSTHOSTDATA(instance); + struct WD33C93_hostdata *hdata = (struct WD33C93_hostdata *)instance->hostdata; wd33c93_regs *regp = hdata->regp; - struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) SCpnt->host->base; + struct hpc3_scsiregs *hregs; + + if (!SCpnt) + return; + + hregs = (struct hpc3_scsiregs *) SCpnt->host->base; #ifdef DEBUG_DMA printk("dma_stop: status<%d> ", status); @@ -158,7 +194,7 @@ hregs->ctrl = 0; /* See how far we got and update scatterlist state if necessary. */ - if(SCpnt->use_sg) { + if(SCpnt->SCp.buffers_residual) { struct scatterlist *slp = SCpnt->SCp.buffer; int totlen, wd93_residual, transferred, i; @@ -178,7 +214,7 @@ #ifdef DEBUG_DMA printk("Jed was here..."); #endif - for(i = 0; i <= (SCpnt->use_sg - 1); i++) { + for(i = 0; i <= SCpnt->SCp.buffers_residual; i++) { if(slp[i].length >= transferred) break; transferred -= slp[i].length; @@ -188,10 +224,10 @@ #ifdef DEBUG_DMA printk("did it all..."); #endif - i = (SCpnt->use_sg - 1); + i = SCpnt->SCp.buffers_residual; } SCpnt->SCp.buffer = &slp[i]; - SCpnt->SCp.buffers_residual = (SCpnt->use_sg - 1 - i); + SCpnt->SCp.buffers_residual = SCpnt->SCp.buffers_residual - i; SCpnt->SCp.ptr = (char *) slp[i].address; SCpnt->SCp.this_residual = slp[i].length; } @@ -200,6 +236,15 @@ #endif } +void sgiwd93_reset(void) +{ + struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; + + hregs->ctrl = HPC3_SCTRL_CRESET; + udelay (50); + hregs->ctrl = 0; +} + static inline void init_hpc_chain(uchar *buf) { struct hpc_chunk *hcp = (struct hpc_chunk *) buf; @@ -231,6 +276,7 @@ sgiwd93_host = scsi_register(HPsUX, sizeof(struct WD33C93_hostdata)); sgiwd93_host->base = (unsigned char *) hregs; + sgiwd93_host->irq = 1; buf = (uchar *) get_free_page(GFP_KERNEL); init_hpc_chain(buf); @@ -239,7 +285,7 @@ wd33c93_init(sgiwd93_host, (wd33c93_regs *) 0xbfbc0003, dma_setup, dma_stop, WD33C93_FS_16_20); - hdata = INSTHOSTDATA(sgiwd93_host); + hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata; hdata->no_sync = 0; hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sgiwd93.h linux.ac/drivers/scsi/sgiwd93.h --- linux.vanilla/drivers/scsi/sgiwd93.h Sun Nov 8 15:07:57 1998 +++ linux.ac/drivers/scsi/sgiwd93.h Tue Jun 22 01:36:47 1999 @@ -1,4 +1,4 @@ -/* $Id: sgiwd93.h,v 1.2 1998/05/04 09:18:49 ralf Exp $ +/* $Id: sgiwd93.h,v 1.5 1998/08/25 09:18:50 ralf Exp $ * sgiwd93.h: SGI WD93 scsi definitions. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/sym53c416.c linux.ac/drivers/scsi/sym53c416.c --- linux.vanilla/drivers/scsi/sym53c416.c Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/scsi/sym53c416.c Mon Jul 19 19:48:20 1999 @@ -3,6 +3,10 @@ * Low-level SCSI driver for sym53c416 chip. * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) * + * Changes : + * + * Marcelo Tosatti : Added io_request_lock locking + * * LILO command line usage: sym53c416=[,] * * This program is free software; you can redistribute it and/or modify it @@ -25,11 +29,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include "scsi.h" @@ -371,7 +375,9 @@ printk("sym53c416: Warning: Reset received\n"); current_command->SCp.phase = idle; current_command->result = DID_RESET << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(int_reg & ILCMD) /* Illegal Command */ @@ -379,7 +385,9 @@ printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG)); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(status_reg & GE) /* Gross Error */ @@ -387,7 +395,9 @@ printk("sym53c416: Warning: Gross Error\n"); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(status_reg & PE) /* Parity Error */ @@ -395,7 +405,9 @@ printk("sym53c416: Warning: Parity Error\n"); current_command->SCp.phase = idle; current_command->result = DID_PARITY << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(pio_int_reg & (CE | OUE)) @@ -403,7 +415,9 @@ printk("sym53c416: Warning: PIO Interrupt Error\n"); current_command->SCp.phase = idle; current_command->result = DID_ERROR << 16; + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } if(int_reg & DIS) /* Disconnect */ @@ -413,7 +427,10 @@ else current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); current_command->SCp.phase = idle; + + spin_lock_irqsave(&io_request_lock, flags); current_command->scsi_done(current_command); + spin_unlock_irqrestore(&io_request_lock, flags); return; } /* Now we handle SCSI phases */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/wd33c93.h linux.ac/drivers/scsi/wd33c93.h --- linux.vanilla/drivers/scsi/wd33c93.h Sun Nov 8 15:07:54 1998 +++ linux.ac/drivers/scsi/wd33c93.h Mon Jul 19 03:45:43 1999 @@ -23,6 +23,7 @@ #ifndef WD33C93_H #define WD33C93_H +#include #define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */ #ifdef PROC_INTERFACE @@ -190,6 +191,9 @@ typedef struct { volatile unsigned char SASR; char pad; +#ifdef CONFIG_SGI + char pad2,pad3; +#endif volatile unsigned char SCMD; } wd33c93_regs; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/scsi/wd7000.c linux.ac/drivers/scsi/wd7000.c --- linux.vanilla/drivers/scsi/wd7000.c Sat Jan 9 21:50:44 1999 +++ linux.ac/drivers/scsi/wd7000.c Mon Jul 5 04:40:34 1999 @@ -1561,19 +1561,16 @@ break; if (i == pass) { -#if (LINUX_VERSION_CODE < 0x020100) -#else void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs, signatures[sig_ptr].len); -#endif - short bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig, + short bios_match=0; + + if(biosaddr) + bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len); -#if (LINUX_VERSION_CODE < 0x020100) -#else iounmap (biosaddr); -#endif if (! bios_match) goto bios_matched; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/Config.in linux.ac/drivers/sgi/Config.in --- linux.vanilla/drivers/sgi/Config.in Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sgi/Config.in Tue Jun 22 01:35:17 1999 @@ -0,0 +1,18 @@ +# +# Character device configuration +# +mainmenu_option next_comment +comment 'SGI devices' + +bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL +if [ "$CONFIG_SGI_SERIAL" != "n" ]; then + define_bool CONFIG_SERIAL y +fi + +bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286 + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX +fi + +endmenu diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/Makefile linux.ac/drivers/sgi/Makefile --- linux.vanilla/drivers/sgi/Makefile Sun Nov 8 15:08:16 1998 +++ linux.ac/drivers/sgi/Makefile Tue Jun 22 01:35:17 1999 @@ -8,13 +8,15 @@ # Note 2! The CFLAGS definitions are now in the main makefile... SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) +MOD_SUB_DIRS := $(SUB_DIRS) char ALL_SUB_DIRS := $(SUB_DIRS) char + L_OBJS := L_TARGET := sgi.a +MOD_LIST_NAME := SGI_MODULES -# Character devices for SGI machines. +# Character and Audio devices for SGI machines. # SUB_DIRS += char L_OBJS += char/sgichar.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/Makefile linux.ac/drivers/sgi/char/Makefile --- linux.vanilla/drivers/sgi/char/Makefile Sun Nov 8 15:08:16 1998 +++ linux.ac/drivers/sgi/char/Makefile Tue Jun 22 01:35:17 1999 @@ -8,11 +8,25 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := sgichar.o -O_OBJS := graphics.o streamable.o newport.o cons_newport.o sgicons.o \ - vga_font.o rrm.o shmiq.o usema.o +OX_OBJS := newport.o +O_OBJS := sgicons.o \ + usema.o shmiq.o streamable.o ifeq ($(CONFIG_SGI_SERIAL),y) O_OBJS += sgiserial.o +endif + +ifeq ($(CONFIG_SGI_DS1286),y) + O_OBJS += ds1286.o +endif + +ifeq ($(CONFIG_SGI_NEWPORT_GFX),y) + O_OBJS += graphics.o rrm.o +else +ifeq ($(CONFIG_SGI_NEWPORT_GFX),m) + OX_OBJS += graphics_syms.o + MX_OBJS += graphics.o rrm.o +endif endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/cons_newport.c linux.ac/drivers/sgi/char/cons_newport.c --- linux.vanilla/drivers/sgi/char/cons_newport.c Sun Nov 8 15:08:16 1998 +++ linux.ac/drivers/sgi/char/cons_newport.c Thu Jan 1 01:00:00 1970 @@ -1,611 +0,0 @@ -/* - * cons_newport.c: Newport graphics console code for the SGI. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: cons_newport.c,v 1.1 1998/01/10 19:05:47 ecd Exp $ - */ - -#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 "gconsole.h" -#include "newport.h" -#include "graphics.h" /* Just for now */ -#include -#include - -#if 0 -#include "linux_logo.h" -#endif - -#define BMASK(c) (c << 24) - -#define RENDER(regs, cp) do { \ -(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \ -(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \ -(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \ -(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \ -(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \ -(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \ -(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \ -(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \ -} while(0) - -#define REVERSE_RENDER(regs, cp) do { \ -(regs)->go.zpattern = BMASK((~(cp)[0x0])); (regs)->go.zpattern = BMASK((~(cp)[0x1])); \ -(regs)->go.zpattern = BMASK((~(cp)[0x2])); (regs)->go.zpattern = BMASK((~(cp)[0x3])); \ -(regs)->go.zpattern = BMASK((~(cp)[0x4])); (regs)->go.zpattern = BMASK((~(cp)[0x5])); \ -(regs)->go.zpattern = BMASK((~(cp)[0x6])); (regs)->go.zpattern = BMASK((~(cp)[0x7])); \ -(regs)->go.zpattern = BMASK((~(cp)[0x8])); (regs)->go.zpattern = BMASK((~(cp)[0x9])); \ -(regs)->go.zpattern = BMASK((~(cp)[0xa])); (regs)->go.zpattern = BMASK((~(cp)[0xb])); \ -(regs)->go.zpattern = BMASK((~(cp)[0xc])); (regs)->go.zpattern = BMASK((~(cp)[0xd])); \ -(regs)->go.zpattern = BMASK((~(cp)[0xe])); (regs)->go.zpattern = BMASK((~(cp)[0xf])); \ -} while(0) - -extern int default_red[16], default_grn[16], default_blu[16]; -extern unsigned char video_type; - -static int cursor_pos = -1; -struct newport_regs *npregs; - -#define TESTVAL 0xdeadbeef -#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11) - -static inline void -newport_disable_video(void) -{ - unsigned short treg; - - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EVIDEO))); -} - -static inline void -newport_enable_video(void) -{ - unsigned short treg; - - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EVIDEO)); -} - -static inline void -newport_disable_cursor(void) -{ - unsigned short treg; - - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP))); -} - -#if 0 -static inline void -newport_enable_cursor(void) -{ - unsigned short treg; - - treg = newport_vc2_get(npregs, VC2_IREG_CONTROL); - newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP)); -} -#endif - -static inline void -newport_init_cmap(void) -{ - unsigned short i; - - for(i = 0; i < 16; i++) { - newport_bfwait(); - newport_cmap_setaddr(npregs, color_table[i]); - newport_cmap_setrgb(npregs, - default_red[i], - default_grn[i], - default_blu[i]); - } -} - -#if 0 -static inline void -newport_init_cursor(void) -{ - unsigned char cursor[256]; - unsigned short *cookie; - int i; - - for(i = 0; i < 256; i++) - cursor[i] = 0x0; - for(i = 211; i < 256; i+=4) { - cursor[i] = 0xff; -#if 0 - cursor[(i + 128) << 2] = 0xff; - cursor[((i + 128) << 2) + 1] = 0xff; -#endif - } - - /* Load the SRAM on the VC2 for this new GLYPH. */ - cookie = (unsigned short *) cursor; - newport_vc2_set(npregs, VC2_IREG_RADDR, VC2_CGLYPH_ADDR); - npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM | - NPORT_DMODE_W2 | VC2_PROTOCOL); - for(i = 0; i < 128; i++) { - newport_bfwait(); - npregs->set.dcbdata0.hwords.s1 = *cookie++; - } - - /* Place the cursor at origin. */ - newport_vc2_set(npregs, VC2_IREG_CURSX, 0); - newport_vc2_set(npregs, VC2_IREG_CURSY, 0); - newport_enable_cursor(); -} -#endif - -static inline void -newport_clear_screen(void) -{ - newport_wait(); - npregs->set.wrmask = 0xffffffff; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX | - NPORT_DMODE0_STOPY); - npregs->set.colori = 0; - npregs->set.xystarti = 0; - npregs->go.xyendi = (((1280 + 63) << 16)|(1024)); - newport_bfwait(); -} - -static inline void -newport_render_version(void) -{ -#if 0 - unsigned short *ush; - int currcons = 0; - char *p; - - ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20; - for (p = "SGI/Linux version " UTS_RELEASE; *p; p++, ush++) { - *ush = (attr << 8) + *p; - newport_blitc (*ush, (unsigned long) ush); - } -#endif -} - -#if 0 -static inline void -newport_render_logo(void) -{ - int i, xpos, ypos; - unsigned char *bmap; - - xpos = 8; - ypos = 18; - - newport_wait(); - npregs->set.colori = 9; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | - NPORT_DMODE0_L32); - - for(i = 0; i < 80; i+=8) { - /* Set coordinates for bitmap operation. */ - npregs->set.xystarti = ((xpos + i) << 16) | ypos; - npregs->set.xyendi = (((xpos + i) + 7) << 16); - newport_wait(); - - bmap = linux_logo + (i * 80); - RENDER(npregs, bmap); bmap += 0x10; - RENDER(npregs, bmap); bmap += 0x10; - RENDER(npregs, bmap); bmap += 0x10; - RENDER(npregs, bmap); bmap += 0x10; - RENDER(npregs, bmap); - } - prom_getchar(); - prom_imode(); -} -#endif - -static inline void -newport_render_background(int xpos, int ypos, int ci) -{ - newport_wait(); - npregs->set.wrmask = 0xffffffff; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX | - NPORT_DMODE0_STOPY); - npregs->set.colori = ci; - npregs->set.xystarti = (xpos << 16) | ypos; - npregs->go.xyendi = ((xpos + 7) << 16) | (ypos + 15); -} - -void -newport_set_origin(unsigned short offset) -{ - /* maybe this works... */ - __origin = offset; -} - -void -newport_hide_cursor(void) -{ - int xpos, ypos, idx; - unsigned long flags; - - if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return; - save_and_cli(flags); - - idx = cursor_pos; - if(idx == -1) { - restore_flags(flags); - return; - } - xpos = 8 + ((idx % video_num_columns) << 3); - ypos = 18 + ((idx / video_num_columns) << 4); - newport_render_background(xpos, ypos, 0); - restore_flags(flags); -} - -void -newport_set_cursor(int currcons) -{ - int xpos, ypos, idx, oldpos; - unsigned short *sp, *osp, cattr; - unsigned long flags; - unsigned char *p; - - if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) - return; - - if (__real_origin != __origin) - __set_origin(__real_origin); - - save_and_cli(flags); - - idx = (pos - video_mem_base) >> 1; - sp = (unsigned short *) pos; - oldpos = cursor_pos; - cursor_pos = idx; - if(!deccm) { - hide_cursor(); - restore_flags(flags); - return; - } - xpos = 8 + ((idx % video_num_columns) << 3); - ypos = 18 + ((idx / video_num_columns) << 4); - if(oldpos != -1) { - int oxpos, oypos; - - /* Restore old location. */ - osp = (unsigned short *) ((oldpos << 1) + video_mem_base); - oxpos = 8 + ((oldpos % video_num_columns) << 3); - oypos = 18 + ((oldpos / video_num_columns) << 4); - cattr = *osp; - newport_render_background(oxpos, oypos, (cattr & 0xf000) >> 12); - p = &vga_font[(cattr & 0xff) << 4]; - newport_wait(); - npregs->set.colori = (cattr & 0x0f00) >> 8; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | - NPORT_DMODE0_L32); - npregs->set.xystarti = (oxpos << 16) | oypos; - npregs->set.xyendi = ((oxpos + 7) << 16); - newport_wait(); - RENDER(npregs, p); - } - cattr = *sp; - newport_render_background(xpos, ypos, (cattr & 0xf000) >> 12); - p = &vga_font[(cattr & 0xff) << 4]; - newport_wait(); - npregs->set.colori = (cattr & 0x0f00) >> 8; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | - NPORT_DMODE0_L32); - npregs->set.xystarti = (xpos << 16) | ypos; - npregs->set.xyendi = ((xpos + 7) << 16); - newport_wait(); - REVERSE_RENDER(npregs, p); - restore_flags (flags); - return; -} - -void -newport_get_scrmem(int currcons) -{ - memcpyw((unsigned short *)vc_scrbuf[currcons], - (unsigned short *)origin, video_screen_size); - origin = video_mem_start = (unsigned long)vc_scrbuf[currcons]; - scr_end = video_mem_end = video_mem_start + video_screen_size; - pos = origin + y*video_size_row + (x<<1); -} - -void -newport_set_scrmem(int currcons, long offset) -{ - if (video_mem_term - video_mem_base < offset + video_screen_size) - offset = 0; - memcpyw((unsigned short *)(video_mem_base + offset), - (unsigned short *) origin, video_screen_size); - video_mem_start = video_mem_base; - video_mem_end = video_mem_term; - origin = video_mem_base + offset; - scr_end = origin + video_screen_size; - pos = origin + y*video_size_row + (x<<1); - has_wrapped = 0; -} - -int -newport_set_get_cmap(unsigned char * arg, int set) -{ - unsigned short ent; - int i; - - i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3); - if (i) - return i; - - for (i=0; i<16; i++) { - if (set) { - __get_user(default_red[i], arg++); - __get_user(default_grn[i], arg++); - __get_user(default_blu[i], arg++); - } else { - __put_user (default_red[i], arg++); - __put_user (default_grn[i], arg++); - __put_user (default_blu[i], arg++); - } - } - if (set) { - for (i=0; ivc_palette[k++] = - default_red[j]; - vc_cons[i].d->vc_palette[k++] = - default_grn[j]; - vc_cons[i].d->vc_palette[k++] = - default_blu[j]; - } - } - } - if(console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) - return 0; - for(ent = 0; ent < 16; ent++) { - newport_bfwait(); - newport_cmap_setaddr(npregs, ent); - newport_cmap_setrgb(npregs, - default_red[ent], - default_grn[ent], - default_blu[ent]); - } - } - - return 0; -} - -void -newport_blitc(unsigned short charattr, unsigned long addr) -{ - int idx, xpos, ypos; - unsigned char *p; - - idx = (addr - (video_mem_base + (__origin<<1))) >> 1; - xpos = 8 + ((idx % video_num_columns) << 3); - ypos = 18 + ((idx / video_num_columns) << 4); - - p = &vga_font[(charattr & 0xff) << 4]; - charattr = (charattr >> 8) & 0xff; - - newport_render_background(xpos, ypos, (charattr & 0xf0) >> 4); - - /* Set the color and drawing mode. */ - newport_wait(); - npregs->set.colori = charattr & 0xf; - npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB | - NPORT_DMODE0_L32); - - /* Set coordinates for bitmap operation. */ - npregs->set.xystarti = (xpos << 16) | ypos; - npregs->set.xyendi = ((xpos + 7) << 16); - newport_wait(); - - /* Go, baby, go... */ - RENDER(npregs, p); -} - -void -newport_memsetw(void * s, unsigned short c, unsigned int count) -{ - unsigned short * addr = (unsigned short *) s; - - count /= 2; - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) { - while (count) { - count--; - *addr++ = c; - } - return; - } - if ((unsigned long) addr + count > video_mem_term || - (unsigned long) addr < video_mem_base) { - if ((unsigned long) addr + count <= video_mem_term || - (unsigned long) addr > video_mem_base) { - while (count) { - count--; - *addr++ = c; - } - return; - } else { - while (count) { - count--; - scr_writew(c, addr++); - } - } - } else { - while (count) { - count--; - if (*addr != c) { - newport_blitc(c, (unsigned long)addr); - *addr++ = c; - } else - addr++; - } - } -} - -void -newport_memcpyw(unsigned short *to, unsigned short *from, unsigned int count) -{ - if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) { - memcpy(to, from, count); - return; - } - if ((unsigned long) to + count > video_mem_term || - (unsigned long) to < video_mem_base) { - if ((unsigned long) to + count <= video_mem_term || - (unsigned long) to > video_mem_base) - memcpy(to, from, count); - else { - count /= 2; - while (count) { - count--; - scr_writew(scr_readw(from++), to++); - } - } - } else { - count /= 2; - while (count) { - count--; - if (*to != *from) { - newport_blitc(*from, (unsigned long)to); - *to++ = *from++; - } else { - from++; - to++; - } - } - } -} - -struct console_ops newport_console = { - newport_set_origin, - newport_hide_cursor, - newport_set_cursor, - newport_get_scrmem, - newport_set_scrmem, - newport_set_get_cmap, - newport_blitc, - newport_memsetw, - newport_memcpyw -}; - -/* Currently hard-coded values that are the same as those found on my system */ -struct ng1_info newport_board_info = { - { "NG1", "" /* what is the label? */, 1280, 1024, sizeof (struct ng1_info) }, - 6, /* boardrev */ - 1, /* rex3rev */ - 0, /* vc2rev */ - 2, /* monitor type */ - 0, /* videoinstalled */ - 3, /* mcrev */ - 24, /* bitplanes */ - 0, /* xmap9rev */ - 2, /* cmaprev */ - { 256, 1280, 1024, 76}, /* ng1_vof_info */ - 13, /* paneltype */ - 0 -}; - -void -newport_reset (void) -{ - newport_wait(); - newport_enable_video(); - - /* Init the cursor disappear. */ - newport_wait(); -#if 0 - newport_init_cursor(); -#else - newport_disable_cursor(); -#endif - - newport_init_cmap(); - - /* Clear the screen. */ - newport_clear_screen(); -} - -/* right now the newport does not do anything at all */ -struct graphics_ops newport_graphic_ops = { - 0, /* owner */ - 0, /* current user */ - (void *) &newport_board_info, /* board info */ - sizeof (struct ng1_info), /* size of our data structure */ - 0, 0, /* g_regs, g_regs_size */ - newport_save, newport_restore, /* g_save_context, g_restore_context */ - newport_reset, newport_ioctl /* g_reset_console, g_ioctl */ -}; - -struct graphics_ops * -newport_probe (int slot, const char **name) -{ - struct newport_regs *p; - - npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000); - - p = npregs; - p->cset.config = NPORT_CFG_GD0; - - if(newport_wait()) { - prom_printf("whoops, timeout, no NEWPORT there?"); - return 0; - } - - p->set.xstarti = TESTVAL; if(p->set._xstart.i != XSTI_TO_FXSTART(TESTVAL)) { - prom_printf("newport_probe: read back wrong value ;-(\n"); - return 0; - } - - if (slot == 0){ - register_gconsole (&newport_console); - video_type = VIDEO_TYPE_SGI; - can_do_color = 1; - *name = "NEWPORT"; - } - - newport_reset (); - newport_render_version(); -#if 0 - newport_render_logo(); -#endif - newport_graphic_ops.g_regs = 0x1f0f0000; - newport_graphic_ops.g_regs_size = sizeof (struct newport_regs); - return &newport_graphic_ops; -} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/ds1286.c linux.ac/drivers/sgi/char/ds1286.c --- linux.vanilla/drivers/sgi/char/ds1286.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sgi/char/ds1286.c Tue Jun 22 01:35:17 1999 @@ -0,0 +1,570 @@ +/* $Id: ds1286.c,v 1.3.2.3 1999/06/17 12:08:44 ralf Exp $ + * + * Real Time Clock interface for Linux + * + * Copyright (C) 1998, 1999 Ralf Baechle + * + * Based on code written by Paul Gortmaker. + * + * This driver allows use of the real time clock (built into + * nearly all computers) from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the /proc/rtc + * pseudo-file for status information. + * + * The ioctls can be used to set the interrupt behaviour and + * generation rate from the RTC via IRQ 8. Then the /dev/rtc + * interface can be used to make use of these timer interrupts, + * be they interval or alarm based. + * + * The /dev/rtc interface will block on reads until an interrupt + * has been received. If a RTC interrupt has already happened, + * it will output an unsigned long and then block. The output value + * contains the interrupt status in the low byte and the number of + * interrupts since the last read in the remaining high bytes. The + * /dev/rtc interface can also be used with the select(2) call. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DS1286_VERSION "1.0" + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static struct wait_queue *ds1286_wait; + +static long long ds1286_llseek(struct file *file, loff_t offset, int origin); + +static ssize_t ds1286_read(struct file *file, char *buf, + size_t count, loff_t *ppos); + +static int ds1286_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static unsigned int ds1286_poll(struct file *file, poll_table *wait); + +void get_rtc_time (struct rtc_time *rtc_tm); +void get_rtc_alm_time (struct rtc_time *alm_tm); + +void set_rtc_irq_bit(unsigned char bit); +void clear_rtc_irq_bit(unsigned char bit); + +static inline unsigned char ds1286_is_updating(void); + +#ifdef __SMP__ +static spinlock_t ds1286_lock = SPIN_LOCK_UNLOCKED; +#endif + +/* + * Bits in rtc_status. (7 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define RTC_TIMER_ON 0x02 /* missed irq timer active */ + +unsigned char ds1286_status = 0; /* bitmapped status byte. */ +unsigned long ds1286_freq = 0; /* Current periodic IRQ rate */ +unsigned long ds1286_irq_data = 0; /* our output to the world */ + +unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * A very tiny interrupt handler. It runs with SA_INTERRUPT set, + * so that there is no possibility of conflicting with the + * set_rtc_mmss() call that happens during some timer interrupts. + * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) + */ + +/* + * Now all the various file operations that we export. + */ + +static long long ds1286_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t ds1286_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct wait_queue wait = { current, NULL }; + unsigned long data; + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&ds1286_wait, &wait); + + current->state = TASK_INTERRUPTIBLE; + + while ((data = xchg(&ds1286_irq_data, 0)) == 0) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + schedule(); + } + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + out: + current->state = TASK_RUNNING; + remove_wait_queue(&ds1286_wait, &wait); + + return retval; +} + +static int ds1286_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + + struct rtc_time wtime; + + switch (cmd) { + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + unsigned int flags; + unsigned char val; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + spin_lock_irqsave(&ds1286_lock, flags); + val = CMOS_READ(RTC_CMD); + val |= RTC_TDM; + CMOS_WRITE(val, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + unsigned int flags; + unsigned char val; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + spin_lock_irqsave(&ds1286_lock, flags); + val = CMOS_READ(RTC_CMD); + val &= ~RTC_TDM; + CMOS_WRITE(val, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; + } + case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ + { + unsigned int flags; + unsigned char val; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + spin_lock_irqsave(&ds1286_lock, flags); + val = CMOS_READ(RTC_CMD); + val |= RTC_WAM; + CMOS_WRITE(val, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; + } + case RTC_WIE_ON: /* Allow watchdog interrupts. */ + { + unsigned int flags; + unsigned char val; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + spin_lock_irqsave(&ds1286_lock, flags); + val = CMOS_READ(RTC_CMD); + val &= ~RTC_WAM; + CMOS_WRITE(val, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; + } + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ + + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + unsigned char hrs, min, sec; + struct rtc_time alm_tm; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + + if (hrs >= 24) + hrs = 0xff; + + if (min >= 60) + min = 0xff; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + + spin_lock(&ds1286_lock); + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + spin_unlock(&ds1286_lock); + + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control; + unsigned int yrs, flags; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= 1940) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irqsave(&ds1286_lock, flags); + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DATE); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); + CMOS_WRITE(0, RTC_HUNDREDTH_SECOND); + + CMOS_WRITE(save_control, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +static int ds1286_open(struct inode *inode, struct file *file) +{ + if(ds1286_status & RTC_IS_OPEN) + return -EBUSY; + + ds1286_status |= RTC_IS_OPEN; + ds1286_irq_data = 0; + return 0; +} + +static int ds1286_release(struct inode *inode, struct file *file) +{ + ds1286_status &= ~RTC_IS_OPEN; + return 0; +} + +static unsigned int ds1286_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &ds1286_wait, wait); + if (ds1286_irq_data != 0) + return POLLIN | POLLRDNORM; + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations ds1286_fops = { + ds1286_llseek, + ds1286_read, + NULL, /* No write */ + NULL, /* No readdir */ + ds1286_poll, + ds1286_ioctl, + NULL, /* No mmap */ + ds1286_open, + NULL, /* No flush */ + ds1286_release +}; + +static struct miscdevice ds1286_dev= +{ + RTC_MINOR, + "rtc", + &ds1286_fops +}; + +__initfunc(int ds1286_init(void)) +{ + printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION); + misc_register(&ds1286_dev); + + ds1286_wait = NULL; + + return 0; +} + +static char *days[] = { + "***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +/* + * Info exported via "/proc/rtc". + */ +int get_ds1286_status(char *buf) +{ + char *p, *s; + struct rtc_time tm; + unsigned char hundredth, month, cmd, amode; + + p = buf; + + get_rtc_time(&tm); + hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND); + hundredth = BCD_TO_BIN(hundredth); + + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d.%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, hundredth, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + /* + * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will + * match any value for that particular field. Values that are + * greater than a valid time, but less than 0xc0 shouldn't appear. + */ + get_rtc_alm_time(&tm); + p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); + if (tm.tm_hour <= 24) + p += sprintf(p, "%02d:", tm.tm_hour); + else + p += sprintf(p, "**:"); + + if (tm.tm_min <= 59) + p += sprintf(p, "%02d\n", tm.tm_min); + else + p += sprintf(p, "**\n"); + + month = CMOS_READ(RTC_MONTH); + p += sprintf(p, + "oscillator\t: %s\n" + "square_wave\t: %s\n", + (month & RTC_EOSC) ? "disabled" : "enabled", + (month & RTC_ESQW) ? "disabled" : "enabled"); + + amode = ((CMOS_READ(RTC_MINUTES_ALARM) & 0x80) >> 5) | + ((CMOS_READ(RTC_HOURS_ALARM) & 0x80) >> 6) | + ((CMOS_READ(RTC_DAY_ALARM) & 0x80) >> 7); + if (amode == 7) s = "each minute"; + else if (amode == 3) s = "minutes match"; + else if (amode == 1) s = "hours and minutes match"; + else if (amode == 0) s = "days, hours and minutes match"; + else s = "invalid"; + p += sprintf(p, "alarm_mode\t: %s\n", s); + + cmd = CMOS_READ(RTC_CMD); + p += sprintf(p, + "alarm_enable\t: %s\n" + "wdog_alarm\t: %s\n" + "alarm_mask\t: %s\n" + "wdog_alarm_mask\t: %s\n" + "interrupt_mode\t: %s\n" + "INTB_mode\t: %s_active\n" + "interrupt_pins\t: %s\n", + (cmd & RTC_TDF) ? "yes" : "no", + (cmd & RTC_WAF) ? "yes" : "no", + (cmd & RTC_TDM) ? "disabled" : "enabled", + (cmd & RTC_WAM) ? "disabled" : "enabled", + (cmd & RTC_PU_LVL) ? "pulse" : "level", + (cmd & RTC_IBH_LO) ? "low" : "high", + (cmd & RTC_IPSW) ? "unswapped" : "swapped"); + + return p - buf; +} + +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char ds1286_is_updating(void) +{ + return CMOS_READ(RTC_CMD) & RTC_TE; +} + +void get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned long uip_watchdog = jiffies; + unsigned char save_control; + unsigned int flags; + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 10 to 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + + if (ds1286_is_updating() != 0) + while (jiffies - uip_watchdog < 2*HZ/100) + barrier(); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&ds1286_lock, flags); + save_control = CMOS_READ(RTC_CMD); + CMOS_WRITE((save_control|RTC_TE), RTC_CMD); + + rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); + rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); + rtc_tm->tm_hour = CMOS_READ(RTC_HOURS) & 0x1f; + rtc_tm->tm_mday = CMOS_READ(RTC_DATE); + rtc_tm->tm_mon = CMOS_READ(RTC_MONTH) & 0x1f; + rtc_tm->tm_year = CMOS_READ(RTC_YEAR); + + CMOS_WRITE(save_control, RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if (rtc_tm->tm_year < 45) + rtc_tm->tm_year += 30; + if ((rtc_tm->tm_year += 40) < 70) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +void get_rtc_alm_time(struct rtc_time *alm_tm) +{ + unsigned char cmd; + unsigned int flags; + + /* + * Only the values that we read from the RTC are set. That + * means only tm_wday, tm_hour, tm_min. + */ + spin_lock_irqsave(&ds1286_lock, flags); + alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM) & 0x7f; + alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM) & 0x1f; + alm_tm->tm_wday = CMOS_READ(RTC_DAY_ALARM) & 0x07; + cmd = CMOS_READ(RTC_CMD); + spin_unlock_irqrestore(&ds1286_lock, flags); + + BCD_TO_BIN(alm_tm->tm_min); + BCD_TO_BIN(alm_tm->tm_hour); + alm_tm->tm_sec = 0; +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/graphics.c linux.ac/drivers/sgi/char/graphics.c --- linux.vanilla/drivers/sgi/char/graphics.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/graphics.c Tue Jun 22 01:35:17 1999 @@ -1,7 +1,10 @@ -/* +/* $Id: graphics.c,v 1.16 1999/04/01 23:45:00 ulfc Exp $ + * * gfx.c: support for SGI's /dev/graphics, /dev/opengl * * Author: Miguel de Icaza (miguel@nuclecu.unam.mx) + * Ralf Baechle (ralf@gnu.org) + * Ulf Carlsson (ulfc@bun.falkenberg.se) * * On IRIX, /dev/graphics is [10, 146] * /dev/opengl is [10, 147] @@ -21,35 +24,56 @@ * We implement those misterious things, and tried not to think about * the reasons behind them. */ +#include #include +#include #include #include #include #include +#include +#include #include #include "gconsole.h" #include "graphics.h" +#include "usema.h" #include #include #include #include +#include -/* The boards */ -#include "newport.h" +#define DEBUG -#ifdef PRODUCTION_DRIVER -#define enable_gconsole() -#define disable_gconsole() -#endif +/* The boards */ +extern struct graphics_ops *newport_probe (int, const char **); static struct graphics_ops cards [MAXCARDS]; static int boards; #define GRAPHICS_CARD(inode) 0 +/* +void enable_gconsole(void) {}; +void disable_gconsole(void) {}; +*/ + + int sgi_graphics_open (struct inode *inode, struct file *file) { + struct newport_regs *nregs = + (struct newport_regs *) KSEG1ADDR(cards[0].g_regs); + + newport_wait(); + nregs->set.wrmask = 0xffffffff; + nregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK | + NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX | + NPORT_DMODE0_STOPY); + nregs->set.colori = 1; + nregs->set.xystarti = (0 << 16) | 0; + nregs->go.xyendi = (1280 << 16) | 1024; + return 0; } @@ -59,10 +83,10 @@ unsigned int board; unsigned int devnum = GRAPHICS_CARD (inode->i_rdev); int i; - + if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT)) return rrm_command (cmd-RRM_BASE, (void *) arg); - + switch (cmd){ case GFX_GETNUM_BOARDS: return boards; @@ -113,7 +137,7 @@ printk ("Parameter board does not match the current board\n"); return -EINVAL; } - + if (board >= boards) return -EINVAL; @@ -126,11 +150,11 @@ * sgi_graphics_mmap */ disable_gconsole (); - r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size, - PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); + r = do_mmap (file, (unsigned long)vaddr, + cards[board].g_regs_size, PROT_READ|PROT_WRITE, + MAP_FIXED|MAP_PRIVATE, 0); if (r) return r; - } /* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD, @@ -141,13 +165,13 @@ case GFX_LABEL: return 0; - + /* Version check * for my IRIX 6.2 X server, this is what the kernel returns */ case 1: return 3; - + /* Xsgi does not use this one, I assume minor is the board being queried */ case GFX_IS_MANAGED: if (devnum > boards) @@ -166,14 +190,15 @@ sgi_graphics_close (struct inode *inode, struct file *file) { int board = GRAPHICS_CARD (inode->i_rdev); - + /* Tell the rendering manager that one client is going away */ rrm_close (inode, file); /* Was this file handle from the board owner?, clear it */ if (current == cards [board].g_owner){ cards [board].g_owner = 0; - (*cards [board].g_reset_console)(); + if (cards [board].g_reset_console) + (*cards [board].g_reset_console)(); enable_gconsole (); } return 0; @@ -184,37 +209,42 @@ */ unsigned long -sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access) +sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int + no_share) { - unsigned long page; + pgd_t *pgd; pmd_t *pmd; pte_t *pte; int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev); -#ifdef DEBUG_GRAPHICS - printk ("Got a page fault for board %d address=%lx guser=%lx\n", board, address, - cards [board].g_user); + unsigned long virt_add, phys_add; + +#ifdef DEBUG + printk ("Got a page fault for board %d address=%lx guser=%lx\n", board, + address, (unsigned long) cards[board].g_user); #endif - /* 1. figure out if another process has this mapped, - * and revoke the mapping in that case. - */ - if (cards [board].g_user && cards [board].g_user != current){ - /* FIXME: save graphics context here, dump it to rendering node? */ - remove_mapping (cards [board].g_user, vma->vm_start, vma->vm_end); + /* Figure out if another process has this mapped, and revoke the mapping + * in that case. */ + if (cards[board].g_user && cards[board].g_user != current) { + /* FIXME: save graphics context here, dump it to rendering + * node? */ + + remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end); } + cards [board].g_user = current; -#if DEBUG_GRAPHICS - printk ("Registers: 0x%lx\n", cards [board].g_regs); - printk ("vm_start: 0x%lx\n", vma->vm_start); - printk ("address: 0x%lx\n", address); - printk ("diff: 0x%lx\n", (address - vma->vm_start)); - printk ("page/pfn: 0x%lx\n", page); - printk ("TLB entry: %lx\n", pte_val (mk_pte (page + PAGE_OFFSET, PAGE_USERIO))); -#endif - - /* 2. Map this into the current process address space */ - page = ((cards [board].g_regs) + (address - vma->vm_start)); - return page + PAGE_OFFSET; + /* Map the physical address of the newport registers into the address + * space of this process */ + + virt_add = address & PAGE_MASK; + phys_add = cards[board].g_regs + virt_add - vma->vm_start; + remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot); + + pgd = pgd_offset(current->mm, address); + pmd = pmd_offset(pgd, address); + pte = pte_offset(pmd, address); + printk("page: %08lx\n", pte_page(*pte)); + return pte_page(*pte); } /* @@ -237,7 +267,7 @@ }; int -sgi_graphics_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) +sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma) { uint size; @@ -250,12 +280,13 @@ /* 2. Set the special tlb permission bits */ vma->vm_page_prot = PAGE_USERIO; - + /* final setup */ - vma->vm_dentry = dget (file->f_dentry); + vma->vm_file = file; return 0; } - + +#if 0 /* Do any post card-detection setup on graphics_ops */ static void graphics_ops_post_init (int slot) @@ -264,6 +295,7 @@ cards [slot].g_owner = (struct task_struct *) 0; cards [slot].g_user = (struct task_struct *) 0; } +#endif struct file_operations sgi_graphics_fops = { NULL, /* llseek */ @@ -284,33 +316,36 @@ /* /dev/graphics */ static struct miscdevice dev_graphics = { - SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops + SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops }; /* /dev/opengl */ static struct miscdevice dev_opengl = { - SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops + SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops }; /* This is called later from the misc-init routine */ -void -gfx_register (void) +__initfunc(void gfx_register (void)) { misc_register (&dev_graphics); misc_register (&dev_opengl); } -void -gfx_init (const char **name) +__initfunc(void gfx_init (const char **name)) { +#if 0 struct console_ops *console; struct graphics_ops *g; +#endif printk ("GFX INIT: "); shmiq_init (); usema_init (); - - if ((g = newport_probe (boards, name)) != 0){ + + boards++; + +#if 0 + if ((g = newport_probe (boards, name)) != 0) { cards [boards] = *g; graphics_ops_post_init (boards); boards++; @@ -318,11 +353,39 @@ } /* Add more graphic drivers here */ /* Keep passing console around */ - - if (boards > MAXCARDS){ - printk ("Too many cards found on the system\n"); - prom_halt (); +#endif + + if (boards > MAXCARDS) + printk (KERN_WARNING "Too many cards found on the system\n"); +} + +#ifdef MODULE +int init_module(void) { + static int initiated = 0; + + printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69); + + if (!initiated++) { + shmiq_init(); + usema_init(); + printk("Adding first board\n"); + boards++; + cards[0].g_regs = 0x1f0f0000; + cards[0].g_regs_size = sizeof (struct newport_regs); } + + printk("Boards: %d\n", boards); + + misc_register (&dev_graphics); + misc_register (&dev_opengl); + + return 0; } +void cleanup_module(void) { + printk("Shutting down SGI Newport Graphics\n"); + misc_deregister (&dev_graphics); + misc_deregister (&dev_opengl); +} +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/graphics.h linux.ac/drivers/sgi/char/graphics.h --- linux.vanilla/drivers/sgi/char/graphics.h Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/graphics.h Tue Jun 22 01:35:17 1999 @@ -25,4 +25,3 @@ void shmiq_init (void); void streamable_init (void); -void usema_init (void); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/graphics_syms.c linux.ac/drivers/sgi/char/graphics_syms.c --- linux.vanilla/drivers/sgi/char/graphics_syms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sgi/char/graphics_syms.c Mon Jul 19 03:45:44 1999 @@ -0,0 +1,36 @@ +/* + * graphics_syms.c: interfaces for SGI Indy newport graphics + * + * Copyright (C) 1999 Alex deVries + * + * We should not even be trying to compile this if we are not doing + * a module. + */ + +#define __NO_VERSION__ +#include + +/* extern int rrm_command (unsigned int cmd, void *arg); +extern int rrm_close (struct inode *inode, struct file *file); +EXPORT_SYMBOL(rrm_command); +EXPORT_SYMBOL(rrm_close); + + +*/ +extern void shmiq_init (void); +extern void usema_init(void); + +EXPORT_SYMBOL(shmiq_init); +EXPORT_SYMBOL(usema_init); + +extern void disable_gconsole(void); +extern void enable_gconsole(void); +extern void remove_mapping (struct task_struct *task, unsigned long start, + unsigned long end); + +EXPORT_SYMBOL(disable_gconsole); +EXPORT_SYMBOL(enable_gconsole); +EXPORT_SYMBOL(remove_mapping); + + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/newport.c linux.ac/drivers/sgi/char/newport.c --- linux.vanilla/drivers/sgi/char/newport.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/newport.c Mon Jul 19 03:45:44 1999 @@ -4,13 +4,19 @@ * * Author: Miguel de Icaza */ + #include #include #include #include #include #include -#include "newport.h" +#include +#include + +struct newport_regs *npregs; + +EXPORT_SYMBOL(npregs); /* Kernel routines for supporting graphics context switching */ @@ -167,7 +173,6 @@ { switch (cmd){ case NG1_SETDISPLAYMODE: { - int i; struct ng1_setdisplaymode_args request; if (copy_from_user (&request, (void *) arg, sizeof (request))) diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/newport.h linux.ac/drivers/sgi/char/newport.h --- linux.vanilla/drivers/sgi/char/newport.h Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/newport.h Thu Jan 1 01:00:00 1970 @@ -1,585 +0,0 @@ -/* $Id: newport.h,v 1.1 1998/01/10 19:05:58 ecd Exp $ - * newport.h: Defines and register layout for NEWPORT graphics - * hardware. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ - -#ifndef _SGI_NEWPORT_H -#define _SGI_NEWPORT_H - - -typedef volatile unsigned long npireg_t; - -union npfloat { - volatile float f; - npireg_t i; -}; - -typedef union npfloat npfreg_t; - -union np_dcb { - npireg_t all; - struct { volatile unsigned short s0, s1; } hwords; - struct { volatile unsigned char b0, b1, b2, b3; } bytes; -}; - -struct newport_rexregs { - npireg_t drawmode1; /* GL extra mode bits */ - -#define DM1_PLANES 0x00000007 -#define DM1_NOPLANES 0x00000000 -#define DM1_RGBPLANES 0x00000001 -#define DM1_RGBAPLANES 0x00000002 -#define DM1_OLAYPLANES 0x00000004 -#define DM1_PUPPLANES 0x00000005 -#define DM1_CIDPLANES 0x00000006 - -#define NPORT_DMODE1_DDMASK 0x00000018 -#define NPORT_DMODE1_DD4 0x00000000 -#define NPORT_DMODE1_DD8 0x00000008 -#define NPORT_DMODE1_DD12 0x00000010 -#define NPORT_DMODE1_DD24 0x00000018 -#define NPORT_DMODE1_DSRC 0x00000020 -#define NPORT_DMODE1_YFLIP 0x00000040 -#define NPORT_DMODE1_RWPCKD 0x00000080 -#define NPORT_DMODE1_HDMASK 0x00000300 -#define NPORT_DMODE1_HD4 0x00000000 -#define NPORT_DMODE1_HD8 0x00000100 -#define NPORT_DMODE1_HD12 0x00000200 -#define NPORT_DMODE1_HD32 0x00000300 -#define NPORT_DMODE1_RWDBL 0x00000400 -#define NPORT_DMODE1_ESWAP 0x00000800 /* Endian swap */ -#define NPORT_DMODE1_CCMASK 0x00007000 -#define NPORT_DMODE1_CCLT 0x00001000 -#define NPORT_DMODE1_CCEQ 0x00002000 -#define NPORT_DMODE1_CCGT 0x00004000 -#define NPORT_DMODE1_RGBMD 0x00008000 -#define NPORT_DMODE1_DENAB 0x00010000 /* Dither enable */ -#define NPORT_DMODE1_FCLR 0x00020000 /* Fast clear */ -#define NPORT_DMODE1_BENAB 0x00040000 /* Blend enable */ -#define NPORT_DMODE1_SFMASK 0x00380000 -#define NPORT_DMODE1_SF0 0x00000000 -#define NPORT_DMODE1_SF1 0x00080000 -#define NPORT_DMODE1_SFDC 0x00100000 -#define NPORT_DMODE1_SFMDC 0x00180000 -#define NPORT_DMODE1_SFSA 0x00200000 -#define NPORT_DMODE1_SFMSA 0x00280000 -#define NPORT_DMODE1_DFMASK 0x01c00000 -#define NPORT_DMODE1_DF0 0x00000000 -#define NPORT_DMODE1_DF1 0x00400000 -#define NPORT_DMODE1_DFSC 0x00800000 -#define NPORT_DMODE1_DFMSC 0x00c00000 -#define NPORT_DMODE1_DFSA 0x01000000 -#define NPORT_DMODE1_DFMSA 0x01400000 -#define NPORT_DMODE1_BBENAB 0x02000000 /* Back blend enable */ -#define NPORT_DMODE1_PFENAB 0x04000000 /* Pre-fetch enable */ -#define NPORT_DMODE1_ABLEND 0x08000000 /* Alpha blend */ -#define NPORT_DMODE1_LOMASK 0xf0000000 -#define NPORT_DMODE1_LOZERO 0x00000000 -#define NPORT_DMODE1_LOAND 0x10000000 -#define NPORT_DMODE1_LOANDR 0x20000000 -#define NPORT_DMODE1_LOSRC 0x30000000 -#define NPORT_DMODE1_LOANDI 0x40000000 -#define NPORT_DMODE1_LODST 0x50000000 -#define NPORT_DMODE1_LOXOR 0x60000000 -#define NPORT_DMODE1_LOOR 0x70000000 -#define NPORT_DMODE1_LONOR 0x80000000 -#define NPORT_DMODE1_LOXNOR 0x90000000 -#define NPORT_DMODE1_LONDST 0xa0000000 -#define NPORT_DMODE1_LOORR 0xb0000000 -#define NPORT_DMODE1_LONSRC 0xc0000000 -#define NPORT_DMODE1_LOORI 0xd0000000 -#define NPORT_DMODE1_LONAND 0xe0000000 -#define NPORT_DMODE1_LOONE 0xf0000000 - - npireg_t drawmode0; /* REX command register */ - - /* These bits define the graphics opcode being performed. */ -#define NPORT_DMODE0_OPMASK 0x00000003 /* Opcode mask */ -#define NPORT_DMODE0_NOP 0x00000000 /* No operation */ -#define NPORT_DMODE0_RD 0x00000001 /* Read operation */ -#define NPORT_DMODE0_DRAW 0x00000002 /* Draw operation */ -#define NPORT_DMODE0_S2S 0x00000003 /* Screen to screen operation */ - - /* The following decide what addressing mode(s) are to be used */ -#define NPORT_DMODE0_AMMASK 0x0000001c /* Address mode mask */ -#define NPORT_DMODE0_SPAN 0x00000000 /* Spanning address mode */ -#define NPORT_DMODE0_BLOCK 0x00000004 /* Block address mode */ -#define NPORT_DMODE0_ILINE 0x00000008 /* Iline address mode */ -#define NPORT_DMODE0_FLINE 0x0000000c /* Fline address mode */ -#define NPORT_DMODE0_ALINE 0x00000010 /* Aline address mode */ -#define NPORT_DMODE0_TLINE 0x00000014 /* Tline address mode */ -#define NPORT_DMODE0_BLINE 0x00000018 /* Bline address mode */ - - /* And now some misc. operation control bits. */ -#define NPORT_DMODE0_DOSETUP 0x00000020 -#define NPORT_DMODE0_CHOST 0x00000040 -#define NPORT_DMODE0_AHOST 0x00000080 -#define NPORT_DMODE0_STOPX 0x00000100 -#define NPORT_DMODE0_STOPY 0x00000200 -#define NPORT_DMODE0_SK1ST 0x00000400 -#define NPORT_DMODE0_SKLST 0x00000800 -#define NPORT_DMODE0_ZPENAB 0x00001000 -#define NPORT_DMODE0_LISPENAB 0x00002000 -#define NPORT_DMODE0_LISLST 0x00004000 -#define NPORT_DMODE0_L32 0x00008000 -#define NPORT_DMODE0_ZOPQ 0x00010000 -#define NPORT_DMODE0_LISOPQ 0x00020000 -#define NPORT_DMODE0_SHADE 0x00040000 -#define NPORT_DMODE0_LRONLY 0x00080000 -#define NPORT_DMODE0_XYOFF 0x00100000 -#define NPORT_DMODE0_CLAMP 0x00200000 -#define NPORT_DMODE0_ENDPF 0x00400000 -#define NPORT_DMODE0_YSTR 0x00800000 - - npireg_t lsmode; /* Mode for line stipple ops */ - npireg_t lspattern; /* Pattern for line stipple ops */ - npireg_t lspatsave; /* Backup save pattern */ - npireg_t zpattern; /* Pixel zpattern */ - npireg_t colorback; /* Background color */ - npireg_t colorvram; /* Clear color for fast vram */ - npireg_t alpharef; /* Reference value for afunctions */ - unsigned long pad0; - npireg_t smask0x; /* Window GL relative screen mask 0 */ - npireg_t smask0y; /* Window GL relative screen mask 0 */ - npireg_t _setup; - npireg_t _stepz; - npireg_t _lsrestore; - npireg_t _lssave; - - unsigned long _pad1[0x30]; - - /* Iterators, full state for context switch */ - npfreg_t _xstart; /* X-start point (current) */ - npfreg_t _ystart; /* Y-start point (current) */ - npfreg_t _xend; /* x-end point */ - npfreg_t _yend; /* y-end point */ - npireg_t xsave; /* copy of xstart integer value for BLOCk addressing MODE */ - npireg_t xymove; /* x.y offset from xstart, ystart for relative operations */ - npfreg_t bresd; - npfreg_t bress1;; - npireg_t bresoctinc1; - volatile int bresrndinc2; - npireg_t brese1; - npireg_t bress2; - npireg_t aweight0; - npireg_t aweight1; - npfreg_t xstartf; - npfreg_t ystartf; - npfreg_t xendf; - npfreg_t yendf; - npireg_t xstarti; - npfreg_t xendf1; - npireg_t xystarti; - npireg_t xyendi; - npireg_t xstartendi; - - unsigned long _unused2[0x29]; - - npfreg_t colorred; - npfreg_t coloralpha; - npfreg_t colorgrn; - npfreg_t colorblue; - npfreg_t slopered; - npfreg_t slopealpha; - npfreg_t slopegrn; - npfreg_t slopeblue; - npireg_t wrmask; - npireg_t colori; - npfreg_t colorx; - npfreg_t slopered1; - npireg_t hostrw0; - npireg_t hostrw1; - npireg_t dcbmode; -#define NPORT_DMODE_WMASK 0x00000003 -#define NPORT_DMODE_W4 0x00000000 -#define NPORT_DMODE_W1 0x00000001 -#define NPORT_DMODE_W2 0x00000002 -#define NPORT_DMODE_W3 0x00000003 -#define NPORT_DMODE_EDPACK 0x00000004 -#define NPORT_DMODE_ECINC 0x00000008 -#define NPORT_DMODE_CMASK 0x00000070 -#define NPORT_DMODE_AMASK 0x00000780 -#define NPORT_DMODE_AVC2 0x00000000 -#define NPORT_DMODE_ACMALL 0x00000080 -#define NPORT_DMODE_ACM0 0x00000100 -#define NPORT_DMODE_ACM1 0x00000180 -#define NPORT_DMODE_AXMALL 0x00000200 -#define NPORT_DMODE_AXM0 0x00000280 -#define NPORT_DMODE_AXM1 0x00000300 -#define NPORT_DMODE_ABT 0x00000380 -#define NPORT_DMODE_AVCC1 0x00000400 -#define NPORT_DMODE_AVAB1 0x00000480 -#define NPORT_DMODE_ALG3V0 0x00000500 -#define NPORT_DMODE_A1562 0x00000580 -#define NPORT_DMODE_ESACK 0x00000800 -#define NPORT_DMODE_EASACK 0x00001000 -#define NPORT_DMODE_CWMASK 0x0003e000 -#define NPORT_DMODE_CHMASK 0x007c0000 -#define NPORT_DMODE_CSMASK 0x0f800000 -#define NPORT_DMODE_SENDIAN 0x10000000 - - unsigned long _unused3; - - union np_dcb dcbdata0; - npireg_t dcbdata1; -}; - -struct newport_cregs { - npireg_t smask1x; - npireg_t smask1y; - npireg_t smask2x; - npireg_t smask2y; - npireg_t smask3x; - npireg_t smask3y; - npireg_t smask4x; - npireg_t smask4y; - npireg_t topscan; - npireg_t xywin; - npireg_t clipmode; -#define NPORT_CMODE_SM0 0x00000001 -#define NPORT_CMODE_SM1 0x00000002 -#define NPORT_CMODE_SM2 0x00000004 -#define NPORT_CMODE_SM3 0x00000008 -#define NPORT_CMODE_SM4 0x00000010 -#define NPORT_CMODE_CMSK 0x00001e00 - - unsigned long _unused0; - unsigned long config; -#define NPORT_CFG_G32MD 0x00000001 -#define NPORT_CFG_BWIDTH 0x00000002 -#define NPORT_CFG_ERCVR 0x00000004 -#define NPORT_CFG_BDMSK 0x00000078 -#define NPORT_CFG_GDMSK 0x00000f80 -#define NPORT_CFG_GD0 0x00000080 -#define NPORT_CFG_GD1 0x00000100 -#define NPORT_CFG_GD2 0x00000200 -#define NPORT_CFG_GD3 0x00000400 -#define NPORT_CFG_GD4 0x00000800 -#define NPORT_CFG_GFAINT 0x00001000 -#define NPORT_CFG_TOMSK 0x0000e000 -#define NPORT_CFG_VRMSK 0x00070000 -#define NPORT_CFG_FBTYP 0x00080000 - - npireg_t _unused1; - npireg_t stat; -#define NPORT_STAT_VERS 0x00000007 -#define NPORT_STAT_GBUSY 0x00000008 -#define NPORT_STAT_BBUSY 0x00000010 -#define NPORT_STAT_VRINT 0x00000020 -#define NPORT_STAT_VIDINT 0x00000040 -#define NPORT_STAT_GLMSK 0x00001f80 -#define NPORT_STAT_BLMSK 0x0007e000 -#define NPORT_STAT_BFIRQ 0x00080000 -#define NPORT_STAT_GFIRQ 0x00100000 - - npireg_t ustat; - npireg_t dreset; -}; - -struct newport_regs { - struct newport_rexregs set; - unsigned long _unused0[0x16e]; - struct newport_rexregs go; - unsigned long _unused1[0x22e]; - struct newport_cregs cset; - unsigned long _unused2[0x1ef]; - struct newport_cregs cgo; -}; -extern struct newport_regs *npregs; - - -typedef struct { - unsigned int drawmode1; - unsigned int drawmode0; - unsigned int lsmode; - unsigned int lspattern; - unsigned int lspatsave; - unsigned int zpattern; - unsigned int colorback; - unsigned int colorvram; - unsigned int alpharef; - unsigned int smask0x; - unsigned int smask0y; - unsigned int _xstart; - unsigned int _ystart; - unsigned int _xend; - unsigned int _yend; - unsigned int xsave; - unsigned int xymove; - unsigned int bresd; - unsigned int bress1; - unsigned int bresoctinc1; - unsigned int bresrndinc2; - unsigned int brese1; - unsigned int bress2; - - unsigned int aweight0; - unsigned int aweight1; - unsigned int colorred; - unsigned int coloralpha; - unsigned int colorgrn; - unsigned int colorblue; - unsigned int slopered; - unsigned int slopealpha; - unsigned int slopegrn; - unsigned int slopeblue; - unsigned int wrmask; - unsigned int hostrw0; - unsigned int hostrw1; - - /* configregs */ - - unsigned int smask1x; - unsigned int smask1y; - unsigned int smask2x; - unsigned int smask2y; - unsigned int smask3x; - unsigned int smask3y; - unsigned int smask4x; - unsigned int smask4y; - unsigned int topscan; - unsigned int xywin; - unsigned int clipmode; - unsigned int config; - - /* dcb registers */ - unsigned int dcbmode; - unsigned int dcbdata0; - unsigned int dcbdata1; -} newport_ctx; - -/* Reading/writing VC2 registers. */ -#define VC2_REGADDR_INDEX 0x00000000 -#define VC2_REGADDR_IREG 0x00000010 -#define VC2_REGADDR_RAM 0x00000030 -#define VC2_PROTOCOL (NPORT_DMODE_EASACK | 0x00800000 | 0x00040000) - -#define VC2_VLINET_ADDR 0x000 -#define VC2_VFRAMET_ADDR 0x400 -#define VC2_CGLYPH_ADDR 0x500 - -/* Now the Indexed registers of the VC2. */ -#define VC2_IREG_VENTRY 0x00 -#define VC2_IREG_CENTRY 0x01 -#define VC2_IREG_CURSX 0x02 -#define VC2_IREG_CURSY 0x03 -#define VC2_IREG_CCURSX 0x04 -#define VC2_IREG_DENTRY 0x05 -#define VC2_IREG_SLEN 0x06 -#define VC2_IREG_RADDR 0x07 -#define VC2_IREG_VFPTR 0x08 -#define VC2_IREG_VLSPTR 0x09 -#define VC2_IREG_VLIR 0x0a -#define VC2_IREG_VLCTR 0x0b -#define VC2_IREG_CTPTR 0x0c -#define VC2_IREG_WCURSY 0x0d -#define VC2_IREG_DFPTR 0x0e -#define VC2_IREG_DLTPTR 0x0f -#define VC2_IREG_CONTROL 0x10 -#define VC2_IREG_CONFIG 0x20 - -extern inline void newport_vc2_set(struct newport_regs *regs, unsigned char vc2ireg, - unsigned short val) -{ - regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W3 | - NPORT_DMODE_ECINC | VC2_PROTOCOL); - regs->set.dcbdata0.all = (vc2ireg << 24) | (val << 8); -} - -extern inline unsigned short newport_vc2_get(struct newport_regs *regs, - unsigned char vc2ireg) -{ - regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W1 | - NPORT_DMODE_ECINC | VC2_PROTOCOL); - regs->set.dcbdata0.bytes.b3 = vc2ireg; - regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_IREG | NPORT_DMODE_W2 | - NPORT_DMODE_ECINC | VC2_PROTOCOL); - return regs->set.dcbdata0.hwords.s1; -} - -/* VC2 Control register bits */ -#define VC2_CTRL_EVIRQ 0x0001 -#define VC2_CTRL_EDISP 0x0002 -#define VC2_CTRL_EVIDEO 0x0004 -#define VC2_CTRL_EDIDS 0x0008 -#define VC2_CTRL_ECURS 0x0010 -#define VC2_CTRL_EGSYNC 0x0020 -#define VC2_CTRL_EILACE 0x0040 -#define VC2_CTRL_ECDISP 0x0080 -#define VC2_CTRL_ECCURS 0x0100 -#define VC2_CTRL_ECG64 0x0200 -#define VC2_CTRL_GLSEL 0x0400 - -/* Controlling the color map on NEWPORT. */ -#define NCMAP_REGADDR_AREG 0x00000000 -#define NCMAP_REGADDR_ALO 0x00000000 -#define NCMAP_REGADDR_AHI 0x00000010 -#define NCMAP_REGADDR_PBUF 0x00000020 -#define NCMAP_REGADDR_CREG 0x00000030 -#define NCMAP_REGADDR_SREG 0x00000040 -#define NCMAP_REGADDR_RREG 0x00000060 -#define NCMAP_PROTOCOL (0x00008000 | 0x00040000 | 0x00800000) - -static inline void newport_cmap_setaddr(struct newport_regs *regs, - unsigned short addr) -{ - regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL | - NPORT_DMODE_SENDIAN | NPORT_DMODE_ECINC | - NCMAP_REGADDR_AREG | NPORT_DMODE_W2); - regs->set.dcbdata0.hwords.s1 = addr; - regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL | - NCMAP_REGADDR_PBUF | NPORT_DMODE_W3); -} - -static inline void newport_cmap_setrgb(struct newport_regs *regs, - unsigned char red, - unsigned char green, - unsigned char blue) -{ - regs->set.dcbdata0.all = - (red << 24) | - (green << 16) | - (blue << 8); -} - -/* Miscellaneous NEWPORT routines. */ -#define BUSY_TIMEOUT 100000 -static inline int newport_wait(void) -{ - int i = 0; - - while(i < BUSY_TIMEOUT) - if(!(npregs->cset.stat & NPORT_STAT_GBUSY)) - break; - if(i == BUSY_TIMEOUT) - return 1; - return 0; -} - -static inline int newport_bfwait(void) -{ - int i = 0; - - while(i < BUSY_TIMEOUT) - if(!(npregs->cset.stat & NPORT_STAT_BBUSY)) - break; - if(i == BUSY_TIMEOUT) - return 1; - return 0; -} - -/* newport.c and cons_newport.c routines */ -extern struct graphics_ops *newport_probe (int, const char **); - -void newport_save (void *); -void newport_restore (void *); -void newport_reset (void); -int newport_ioctl (int card, int cmd, unsigned long arg); - -/* - * DCBMODE register defines: - */ - -/* Widht of the data being transfered for each DCBDATA[01] word */ -#define DCB_DATAWIDTH_4 0x0 -#define DCB_DATAWIDTH_1 0x1 -#define DCB_DATAWIDTH_2 0x2 -#define DCB_DATAWIDTH_3 0x3 - -/* If set, all of DCBDATA will be moved, otherwise only DATAWIDTH bytes */ -#define DCB_ENDATAPACK (1 << 2) - -/* Enables DCBCRS auto increment after each DCB transfer */ -#define DCB_ENCRSINC (1 << 3) - -/* shift for accessing the control register select address (DBCCRS, 3 bits) */ -#define DCB_CRS_SHIFT 4 - -/* DCBADDR (4 bits): display bus slave address */ -#define DCB_ADDR_SHIFT 7 -#define DCB_VC2 (0 << DCB_ADDR_SHIFT) -#define DCB_CMAP_ALL (1 << DCB_ADDR_SHIFT) -#define DCB_CMAP0 (2 << DCB_ADDR_SHIFT) -#define DCB_CMAP1 (3 << DCB_ADDR_SHIFT) -#define DCB_XMAP_ALL (4 << DCB_ADDR_SHIFT) -#define DCB_XMAP0 (5 << DCB_ADDR_SHIFT) -#define DCB_XMAP1 (6 << DCB_ADDR_SHIFT) -#define DCB_BT445 (7 << DCB_ADDR_SHIFT) -#define DCB_VCC1 (8 << DCB_ADDR_SHIFT) -#define DCB_VAB1 (9 << DCB_ADDR_SHIFT) -#define DCB_LG3_BDVERS0 (10 << DCB_ADDR_SHIFT) -#define DCB_LG3_ICS1562 (11 << DCB_ADDR_SHIFT) -#define DCB_RESERVED (15 << DCB_ADDR_SHIFT) - -/* DCB protocol ack types */ -#define DCB_ENSYNCACK (1 << 11) -#define DCB_ENASYNCACK (1 << 12) - -#define DCB_CSWIDTH_SHIFT 13 -#define DCB_CSHOLD_SHIFT 18 -#define DCB_CSSETUP_SHIFT 23 - -/* XMAP9 specific defines */ -/* XMAP9 -- registers as seen on the DCBMODE register*/ -# define XM9_CRS_CONFIG (0 << DCB_CRS_SHIFT) -# define XM9_PUPMODE (1 << 0) -# define XM9_ODD_PIXEL (1 << 1) -# define XM9_8_BITPLANES (1 << 2) -# define XM9_SLOW_DCB (1 << 3) -# define XM9_VIDEO_RGBMAP_MASK (3 << 4) -# define XM9_EXPRESS_VIDEO (1 << 6) -# define XM9_VIDEO_OPTION (1 << 7) -# define XM9_CRS_REVISION (1 << DCB_CRS_SHIFT) -# define XM9_CRS_FIFO_AVAIL (2 << DCB_CRS_SHIFT) -# define XM9_FIFO_0_AVAIL 0 -# define XM9_FIFO_1_AVAIL 1 -# define XM9_FIFO_2_AVAIL 3 -# define XM9_FIFO_3_AVAIL 2 -# define XM9_FIFO_FULL XM9_FIFO_0_AVAIL -# define XM9_FIFO_EMPTY XM9_FIFO_3_AVAIL -# define XM9_CRS_CURS_CMAP_MSB (3 << DCB_CRS_SHIFT) -# define XM9_CRS_PUP_CMAP_MSB (4 << DCB_CRS_SHIFT) -# define XM9_CRS_MODE_REG_DATA (5 << DCB_CRS_SHIFT) -# define XM9_CRS_MODE_REG_INDEX (7 << DCB_CRS_SHIFT) - - -#define DCB_CYCLES(setup,hold,width) \ - ((hold << DCB_CSHOLD_SHIFT) | \ - (setup << DCB_CSSETUP_SHIFT)| \ - (width << DCB_CSWIDTH_SHIFT)) - -#define W_DCB_XMAP9_PROTOCOL DCB_CYCLES (2, 1, 0) -#define WSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (5, 5, 0) -#define WAYSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (12, 12, 0) -#define R_DCB_XMAP9_PROTOCOL DCB_CYCLES (2, 1, 3) - -static inline void -xmap9FIFOWait (struct newport_regs *rex) -{ - rex->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL | - DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL; - newport_bfwait (); - - while ((rex->set.dcbdata0.bytes.b3 & 3) != XM9_FIFO_EMPTY) - ; -} - -static inline void -xmap9SetModeReg (struct newport_regs *rex, unsigned int modereg, unsigned int data24, int cfreq) -{ - if (cfreq > 119) - rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA | - DCB_DATAWIDTH_4 | W_DCB_XMAP9_PROTOCOL; - else if (cfreq > 59) - rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA | - DCB_DATAWIDTH_4 | WSLOW_DCB_XMAP9_PROTOCOL; - else - rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA | - DCB_DATAWIDTH_4 | WAYSLOW_DCB_XMAP9_PROTOCOL; - rex->set.dcbdata0.all = ((modereg) << 24) | (data24 & 0xffffff); -} - -#endif /* !(_SGI_NEWPORT_H) */ - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/rrm.c linux.ac/drivers/sgi/char/rrm.c --- linux.vanilla/drivers/sgi/char/rrm.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/rrm.c Tue Jun 22 01:35:18 1999 @@ -12,6 +12,10 @@ #include #include +#ifdef MODULE +#include +#endif + int rrm_open_rn (int rnid, void *arg) { @@ -66,4 +70,3 @@ /* This routine is invoked when the device is closed */ return 0; } - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/sgicons.c linux.ac/drivers/sgi/char/sgicons.c --- linux.vanilla/drivers/sgi/char/sgicons.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/sgicons.c Tue Jun 22 01:35:18 1999 @@ -1,14 +1,11 @@ -/* +/* $Id: sgicons.c,v 1.11 1999/01/04 16:07:19 ralf Exp $ + * * sgicons.c: Setting up and registering console I/O on the SGI. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) * * This implement a virtual console interface. - * - * This should be replaced with Gert's all-singing all-dancing - * graphics console code in the future - * */ #include #include @@ -17,7 +14,7 @@ #include "gconsole.h" /* To make psaux code cleaner */ -int aux_device_present = 0xaa; +unsigned char aux_device_present = 0xaa; /* This is the system graphics console (the first adapter found) */ struct console_ops *gconsole = 0; @@ -45,139 +42,4 @@ if (gconsole) return; gconsole = gc; -} - -void -__set_origin (unsigned short offset) -{ - if (gconsole) - (*gconsole->set_origin)(offset); -} - -void -hide_cursor (void) -{ - - if (gconsole) - (*gconsole->hide_cursor)(); -} - -void -set_cursor (int currcons) -{ - if (gconsole) - (*gconsole->set_cursor)(currcons); -} - -void -get_scrmem (int currcons) -{ - if (gconsole) - (*gconsole->get_scrmem)(currcons); -} - -void -set_scrmem (int currcons, long offset) -{ - if (gconsole) - (*gconsole->set_scrmem)(currcons, offset); -} - -int -set_get_cmap (unsigned char *arg, int set) -{ - if (gconsole) - return (*gconsole->set_get_cmap)(arg, set); - return 0; -} - -void -blitc (unsigned short charattr, unsigned long addr) -{ - if (gconsole) - (*gconsole->blitc)(charattr, addr); -} - -void -memsetw (void *s, unsigned short c, unsigned int count) -{ - if (gconsole) - (*gconsole->memsetw)(s, c, count); -} - -void -memcpyw (unsigned short *to, unsigned short *from, unsigned int count) -{ - if (gconsole) - (*gconsole->memcpyw)(to, from, count); -} - -int -con_adjust_height (unsigned long fontheight) -{ - return -EINVAL; -} - -int -set_get_font (char *arg, int set, int ch512) -{ - int error, i, line; - - if (!arg) - return -EINVAL; - error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg, - ch512 ? 2* cmapsz : cmapsz); - if (error) - return error; - - /* download the current font */ - if (!set) { - memset (arg, 0, cmapsz); - for (i = 0; i < 256; i++) { - for (line = 0; line < CHAR_HEIGHT; line++) - __put_user (vga_font [i], arg+(i*32+line)); - } - return 0; - } - - /* set the font */ - for (i = 0; i < 256; i++) { - for (line = 0; line < CHAR_HEIGHT; line++) { - __get_user(vga_font [i*CHAR_HEIGHT + line], - arg + (i * 32 + line)); - } - } - return 0; -} - -/* - * dummy routines for the VESA blanking code, which is VGA only, - * so we don't have to carry that stuff around for the Sparc... */ -void vesa_blank(void) { } -void vesa_unblank(void) { } -void set_vesa_blanking(const unsigned long arg) { } -void vesa_powerdown(void) { } -void set_palette (void) { } - -extern unsigned long video_mem_base, video_screen_size, video_mem_term; - -__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name)) -{ - extern int serial_console; - - if (serial_console) - *name = "NONE"; - else { - gfx_init (name); - printk("Video screen size is %08lx at %08lx\n", - video_screen_size, start_mem); - video_mem_base = start_mem; - start_mem += (video_screen_size * 2); - video_mem_term = start_mem; - } - return start_mem; -} - -__initfunc(void con_type_init_finish(void)) -{ } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/sgiserial.c linux.ac/drivers/sgi/char/sgiserial.c --- linux.vanilla/drivers/sgi/char/sgiserial.c Sun Nov 8 15:10:21 1998 +++ linux.ac/drivers/sgi/char/sgiserial.c Tue Jun 22 01:35:18 1999 @@ -1,6 +1,7 @@ /* sgiserial.c: Serial port driver for SGI machines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * */ #include /* for CONFIG_REMOTE_DEBUG */ @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -39,33 +41,16 @@ struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, }; struct sgi_zschannel *zs_conschan; struct sgi_zschannel *zs_kgdbchan; -int zs_nodes[NUM_SERIAL] = { 0, }; struct sgi_serial zs_soft[NUM_CHANNELS]; struct sgi_serial *zs_chain; /* IRQ servicing chain */ static int zilog_irq = 21; -struct tty_struct zs_ttys[NUM_CHANNELS]; -/** struct tty_struct *zs_constty; **/ - /* Console hooks... */ static int zs_cons_chanout = 0; static int zs_cons_chanin = 0; struct sgi_serial *zs_consinfo = 0; -static struct console sgi_console_driver = { - "debug", - NULL, /* write */ - NULL, /* read */ - NULL, /* device */ - NULL, /* wait_key */ - NULL, /* unblank */ - NULL, /* setup */ - CON_PRINTBUFFER, - -1, - 0, - NULL -}; static unsigned char kgdb_regs[16] = { 0, 0, 0, /* write 0, 1, 2 */ (Rx8 | RxENABLE), /* write 3 */ @@ -80,6 +65,22 @@ (DCDIE) /* write 15 */ }; +static unsigned char zscons_regs[16] = { + 0, /* write 0 */ + (EXT_INT_ENAB | INT_ALL_Rx), /* write 1 */ + 0, /* write 2 */ + (Rx8 | RxENABLE), /* write 3 */ + (X16CLK), /* write 4 */ + (DTR | Tx8 | TxENAB), /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + (NV | MIE), /* write 9 */ + (NRZ), /* write 10 */ + (TCBR | RCBR), /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + (BRENABL), /* write 14 */ + (DCDIE | CTSIE | TxUIE | BRKIE) /* write 15 */ +}; + #define ZS_CLOCK 3672000 /* Zilog input clock rate */ DECLARE_TASK_QUEUE(tq_serial); @@ -161,6 +162,10 @@ * driver work on the Sun4 which needs a settling delay after each chip * register access, other machines handle this in hardware via auxiliary * flip-flops which implement the settle time we do in software. + * + * read_zsreg() and write_zsreg() may get called from rs_kgdb_hook() before + * interrupts are enabled. Therefore we have to check ioc_iocontrol before we + * access it. */ static inline unsigned char read_zsreg(struct sgi_zschannel *channel, unsigned char reg) { @@ -169,7 +174,8 @@ udelay(2); channel->control = reg; - junk = ioc_icontrol->istat0; + if (ioc_icontrol) + junk = ioc_icontrol->istat0; udelay(1); retval = channel->control; return retval; @@ -181,10 +187,12 @@ udelay(2); channel->control = reg; - junk = ioc_icontrol->istat0; + if (ioc_icontrol) + junk = ioc_icontrol->istat0; udelay(1); channel->control = value; - junk = ioc_icontrol->istat0; + if (ioc_icontrol) + junk = ioc_icontrol->istat0; return; } @@ -235,7 +243,7 @@ kgdb_regs[R1] = 0; kgdb_regs[R9] &= ~MIE; } - brg = BPS_TO_BRG(bps, ZS_CLOCK/16); + brg = BPS_TO_BRG(bps, ZS_CLOCK/ss->clk_divisor); kgdb_regs[R12] = (brg & 255); kgdb_regs[R13] = ((brg >> 8) & 255); load_zsregs(ss->zs_channel, kgdb_regs); @@ -552,7 +560,7 @@ struct sgi_serial * info = (struct sgi_serial *) dev_id; unsigned char zs_intreg; - zs_intreg = read_zsreg(info->zs_channel, 3); + zs_intreg = read_zsreg(info->zs_next->zs_channel, 3); /* NOTE: The read register 3, which holds the irq status, * does so for both channels on each chip. Although @@ -564,25 +572,25 @@ #define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) /* *** Chip 1 *** */ - /* Channel A -- /dev/ttya, could be the console */ - if(zs_intreg & CHAN_A_IRQMASK) { - if (zs_intreg & CHARxIP) + /* Channel B -- /dev/ttyb, could be the console */ + if(zs_intreg & CHAN_B_IRQMASK) { + if (zs_intreg & CHBRxIP) receive_chars(info, regs); - if (zs_intreg & CHATxIP) + if (zs_intreg & CHBTxIP) transmit_chars(info); - if (zs_intreg & CHAEXT) + if (zs_intreg & CHBEXT) status_handle(info); } info=info->zs_next; - /* Channel B -- /dev/ttyb, could be the console */ - if(zs_intreg & CHAN_B_IRQMASK) { - if (zs_intreg & CHBRxIP) + /* Channel A -- /dev/ttya, could be the console */ + if(zs_intreg & CHAN_A_IRQMASK) { + if (zs_intreg & CHARxIP) receive_chars(info, regs); - if (zs_intreg & CHBTxIP) + if (zs_intreg & CHATxIP) transmit_chars(info); - if (zs_intreg & CHBEXT) + if (zs_intreg & CHAEXT) status_handle(info); } } @@ -904,7 +912,7 @@ /* These are for receiving and sending characters under the kgdb * source level kernel debugger. */ -void putDebugChar(char kgdb_char) +int putDebugChar(char kgdb_char) { struct sgi_zschannel *chan = zs_kgdbchan; volatile unsigned char junk; @@ -919,6 +927,8 @@ chan->data = kgdb_char; junk = ioc_icontrol->istat0; restore_flags(flags); + + return 1; } char getDebugChar(void) @@ -971,63 +981,6 @@ return; } -/* - * zs_console_print is registered for printk. - */ - -static void zs_console_print(struct console *co, const char *str, unsigned int count) -{ - - while(count--) { - if(*str == '\n') - rs_put_char('\r'); - rs_put_char(*str++); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - rs_fair_output(); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct sgi_serial *info = (struct sgi_serial *)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; - - /* Enable transmitter */ - save_flags(flags); cli(); - info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB; - info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB; - write_zsreg(info->zs_channel, 1, info->curregs[1]); - info->curregs[5] |= TxENAB; - info->pendregs[5] |= TxENAB; - write_zsreg(info->zs_channel, 5, info->curregs[5]); - - /* - * Send a first (bootstrapping) character. A best solution is - * to call transmit_chars() here which handles output in a - * generic way. Current transmit_chars() not only transmits, - * but resets interrupts also what we do not desire here. - * XXX Discuss with David. - */ - if (info->zs_channel->control & Tx_BUF_EMP) { - volatile unsigned char junk; - - /* Send char */ - udelay(2); - info->zs_channel->data = info->xmit_buf[info->xmit_tail++]; - junk = ioc_icontrol->istat0; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - restore_flags(flags); -} static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -1117,6 +1070,47 @@ (tty->ldisc.write_wakeup)(tty); } +static void rs_flush_chars(struct tty_struct *tty) +{ + struct sgi_serial *info = (struct sgi_serial *)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; + + /* Enable transmitter */ + save_flags(flags); cli(); + info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + info->curregs[5] |= TxENAB; + info->pendregs[5] |= TxENAB; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + + /* + * Send a first (bootstrapping) character. A best solution is + * to call transmit_chars() here which handles output in a + * generic way. Current transmit_chars() not only transmits, + * but resets interrupts also what we do not desire here. + * XXX Discuss with David. + */ + if (info->zs_channel->control & Tx_BUF_EMP) { + volatile unsigned char junk; + + /* Send char */ + udelay(2); + info->zs_channel->data = info->xmit_buf[info->xmit_tail++]; + junk = ioc_icontrol->istat0; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + restore_flags(flags); +} + /* * ------------------------------------------------------------ * rs_throttle() @@ -1614,7 +1608,7 @@ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && !(info->flags & ZILOG_CLOSING) && do_clocal) break; - if (current->signal & ~current->blocked) { + if (signal_pending(current)) { retval = -ERESTARTSYS; break; } @@ -1725,17 +1719,14 @@ } - static inline void rs_cons_check(struct sgi_serial *ss, int channel) { int i, o, io; - static consout_registered = 0; - static msg_printed = 0; + static int msg_printed = 0; i = o = io = 0; - /* Is this one of the serial console lines? */ if((zs_cons_chanout != channel) && (zs_cons_chanin != channel)) @@ -1744,18 +1735,6 @@ zs_consinfo = ss; - /* Register the console output putchar, if necessary */ - if((zs_cons_chanout == channel)) { - o = 1; - /* double whee.. */ - - if(!consout_registered) { - sgi_console_driver.write = zs_console_print; - register_console(&sgi_console_driver); - consout_registered = 1; - } - } - /* If this is console input, we handle the break received * status interrupt on this line to mean prom_halt(). @@ -1873,8 +1852,8 @@ if(!zs_chips[chip]) { zs_chips[chip] = get_zs(chip); /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + zs_channels[(chip*2)] = &zs_chips[chip]->channelB; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA; zs_soft[(chip*2)].kgdb_channel = 0; zs_soft[(chip*2)+1].kgdb_channel = 0; } @@ -1990,14 +1969,14 @@ if(chip) panic("rs_cons_hook called with chip not zero"); - if(line != 1 && line != 2) + if(line != 0 && line != 1) panic("rs_cons_hook called with line not ttya or ttyb"); - channel = line - 1; + channel = line; if(!zs_chips[chip]) { zs_chips[chip] = get_zs(chip); /* Two channels per chip */ - zs_channels[(chip*2)] = &zs_chips[chip]->channelA; - zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + zs_channels[(chip*2)] = &zs_chips[chip]->channelB; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA; } zs_soft[channel].zs_channel = zs_channels[channel]; zs_soft[channel].change_needed = 0; @@ -2041,3 +2020,176 @@ udelay(5); ZS_CLEARFIFO(zs_kgdbchan); } + +static void zs_console_write(struct console *co, const char *str, unsigned int count) +{ + + while(count--) { + if(*str == '\n') + rs_put_char('\r'); + rs_put_char(*str++); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + rs_fair_output(); +} + +static int zs_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t zs_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + + +__initfunc(static int zs_console_setup(struct console *con, char *options)) +{ + struct sgi_serial *info; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + char *s; + int i, brg; + + 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; + } + con->cflag = cflag; + + rs_cons_hook(0, 0, con->index); + info = zs_soft + con->index; + info->is_cons = 1; + + printk("Console: ttyS%d (Zilog8530)\n", info->line); + + i = con->cflag & CBAUD; + if (con->cflag & CBAUDEX) { + i &= ~CBAUDEX; + con->cflag &= ~CBAUDEX; + } + info->zs_baud = baud; + + switch (con->cflag & CSIZE) { + case CS5: + zscons_regs[3] = Rx5 | RxENABLE; + zscons_regs[5] = Tx5 | TxENAB; + break; + case CS6: + zscons_regs[3] = Rx6 | RxENABLE; + zscons_regs[5] = Tx6 | TxENAB; + break; + case CS7: + zscons_regs[3] = Rx7 | RxENABLE; + zscons_regs[5] = Tx7 | TxENAB; + break; + default: + case CS8: + zscons_regs[3] = Rx8 | RxENABLE; + zscons_regs[5] = Tx8 | TxENAB; + break; + } + zscons_regs[5] |= DTR; + + if (con->cflag & PARENB) + zscons_regs[4] |= PAR_ENA; + if (!(con->cflag & PARODD)) + zscons_regs[4] |= PAR_EVEN; + + if (con->cflag & CSTOPB) + zscons_regs[4] |= SB2; + else + zscons_regs[4] |= SB1; + + brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor); + zscons_regs[12] = brg & 0xff; + zscons_regs[13] = (brg >> 8) & 0xff; + memcpy(info->curregs, zscons_regs, sizeof(zscons_regs)); + memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs)); + load_zsregs(info->zs_channel, zscons_regs); + ZS_CLEARERR(info->zs_channel); + ZS_CLEARFIFO(info->zs_channel); + return 0; +} + +static struct console sgi_console_driver = { + "ttyS", + zs_console_write, /* write */ + NULL, /* read */ + zs_console_device, /* device */ + zs_console_wait_key, /* wait_key */ + NULL, /* unblank */ + zs_console_setup, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sgi_console_driver); + return kmem_start; +} + + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/sgiserial.h linux.ac/drivers/sgi/char/sgiserial.h --- linux.vanilla/drivers/sgi/char/sgiserial.h Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/sgiserial.h Tue Jun 22 01:35:18 1999 @@ -412,7 +412,8 @@ udelay(2); channel->control = ERR_RES; - junk = ioc_icontrol->istat0; + if (ioc_icontrol) + junk = ioc_icontrol->istat0; } extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel) @@ -421,11 +422,17 @@ udelay(2); junk = channel->data; - udelay(2); junk = ioc_icontrol->istat0; + udelay(2); + if (ioc_icontrol) + junk = ioc_icontrol->istat0; junk = channel->data; - udelay(2); junk = ioc_icontrol->istat0; + udelay(2); + if (ioc_icontrol) + junk = ioc_icontrol->istat0; junk = channel->data; - udelay(2); junk = ioc_icontrol->istat0; + udelay(2); + if (ioc_icontrol) + junk = ioc_icontrol->istat0; } #if 0 diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/shmiq.c linux.ac/drivers/sgi/char/shmiq.c --- linux.vanilla/drivers/sgi/char/shmiq.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/shmiq.c Tue Jun 22 01:35:18 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: shmiq.c,v 1.11.2.2 1999/06/17 12:08:45 ralf Exp $ + * * shmiq.c: shared memory input queue driver * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) * @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -237,7 +239,7 @@ return -EBADF; } -extern sys_munmap(unsigned long addr, size_t len); +extern int sys_munmap(unsigned long addr, size_t len); static int qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg, int minor) @@ -394,12 +396,12 @@ } static int -shmiq_qcntl_fasync (struct file *file, int on) +shmiq_qcntl_fasync (int fd, struct file *file, int on) { int retval; int minor = MINOR (file->f_dentry->d_inode->i_rdev); - retval = fasync_helper (file, on, &shmiqs [minor].fasync); + retval = fasync_helper (fd, file, on, &shmiqs [minor].fasync); if (retval < 0) return retval; return 0; @@ -422,7 +424,7 @@ return -EINVAL; lock_kernel (); - shmiq_qcntl_fasync (filp, 0); + shmiq_qcntl_fasync (-1, filp, 0); shmiqs [minor].opened = 0; shmiqs [minor].mapped = 0; shmiqs [minor].events = 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/streamable.c linux.ac/drivers/sgi/char/streamable.c --- linux.vanilla/drivers/sgi/char/streamable.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/streamable.c Tue Jun 22 01:35:18 1999 @@ -1,4 +1,5 @@ -/* +/* $Id: streamable.c,v 1.9 1998/09/19 19:17:50 ralf Exp $ + * * streamable.c: streamable devices. /dev/gfx * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx) * @@ -51,14 +52,14 @@ static int sgi_gfx_open (struct inode *inode, struct file *file) { - printk ("GFX: Opened by %d\n", current->pid); + printk ("GFX: Opened by %ld\n", current->pid); return 0; } static int sgi_gfx_close (struct inode *inode, struct file *file) { - printk ("GFX: Closed by %d\n", current->pid); + printk ("GFX: Closed by %ld\n", current->pid); return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/usema.c linux.ac/drivers/sgi/char/usema.c --- linux.vanilla/drivers/sgi/char/usema.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/usema.c Tue Jun 22 01:35:18 1999 @@ -27,11 +27,13 @@ #include #include #include +#include #include #include #include #include #include +#include "usema.h" #include #include @@ -42,6 +44,7 @@ struct wait_queue *proc_list; }; + static int sgi_usema_attach (usattach_t * attach, struct irix_usema *usema) { @@ -64,7 +67,7 @@ struct irix_usema *usema = file->private_data; int retval; - printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)", + printk("[%s:%ld] wants ioctl 0x%xd (arg 0x%lx)", current->comm, current->pid, cmd, arg); switch(cmd) { @@ -76,7 +79,7 @@ usattach_t *attach = (usattach_t *)arg; retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); if (retval) { - printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): " + printk("[%s:%ld] sgi_usema_ioctl(UIOCATTACHSEMA): " "verify_area failure", current->comm, current->pid); return retval; @@ -84,7 +87,8 @@ if (usema == 0) return -EINVAL; - printk("UIOCATTACHSEMA: attaching usema %p to process %d\n", usema, current->pid); + printk("UIOCATTACHSEMA: attaching usema %p to process %ld\n", + usema, current->pid); /* XXX what is attach->us_handle for? */ return sgi_usema_attach(attach, usema); break; @@ -97,12 +101,12 @@ retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); if (retval) { - printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): " + printk("[%s:%ld] sgi_usema_ioctl(UIOC*BLOCK): " "verify_area failure", current->comm, current->pid); return retval; } - printk("UIOC*BLOCK: putting process %d to sleep on usema %p", + printk("UIOC*BLOCK: putting process %ld to sleep on usema %p", current->pid, usema); if (cmd == UIOCNOIBLOCK) interruptible_sleep_on(&usema->proc_list); @@ -117,13 +121,13 @@ retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); if (retval) { - printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): " + printk("[%s:%ld] sgi_usema_ioctl(UIOC*BLOCK): " "verify_area failure", current->comm, current->pid); return retval; } - printk("[%s:%d] releasing usema %p", + printk("[%s:%ld] releasing usema %p", current->comm, current->pid, usema); wake_up(&usema->proc_list); return 0; @@ -137,7 +141,8 @@ { struct irix_usema *usema = filp->private_data; - printk("[%s:%d] wants to poll usema %p", current->comm, current->pid, usema); + printk("[%s:%ld] wants to poll usema %p", + current->comm, current->pid, usema); return 0; } @@ -187,6 +192,7 @@ void usema_init(void) { - printk("usemaclone misc device registered (minor: %d)\n", SGI_USEMACLONE); + printk("usemaclone misc device registered (minor: %d)\n", + SGI_USEMACLONE); misc_register(&dev_usemaclone); } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/usema.h linux.ac/drivers/sgi/char/usema.h --- linux.vanilla/drivers/sgi/char/usema.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sgi/char/usema.h Tue Jun 22 01:35:18 1999 @@ -0,0 +1,10 @@ +/* usema.h + * + * Copyright (C) 1996 Alex deVries + */ +#ifndef _SGI_USEMA_H +#define _SGI_USEMA_H + +void usema_init (void); + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sgi/char/vga_font.c linux.ac/drivers/sgi/char/vga_font.c --- linux.vanilla/drivers/sgi/char/vga_font.c Sun Nov 8 15:08:17 1998 +++ linux.ac/drivers/sgi/char/vga_font.c Thu Jan 1 01:00:00 1970 @@ -1,346 +0,0 @@ -#include "gconsole.h" - -unsigned char vga_font[cmapsz] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, -0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, -0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, -0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, -0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, -0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, -0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, -0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, -0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, -0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, -0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, -0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, -0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, -0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, -0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, -0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, -0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, -0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, -0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, -0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, -0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, -0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, -0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, -0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, -0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, -0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, -0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, -0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, -0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, -0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, -0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, -0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, -0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, -0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, -0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, -0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, -0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, -0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, -0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, -0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, -0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, -0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, -0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, -0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, -0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, -0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, -0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, -0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, -0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, -0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, -0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, -0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, -0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, -0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, -0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, -0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, -0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, -0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, -0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, -0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, -0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, -0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, -0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, -0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, -0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, -0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, -0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, -0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, -0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, -0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, -0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, -0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Config.in linux.ac/drivers/sound/Config.in --- linux.vanilla/drivers/sound/Config.in Wed Mar 10 21:13:06 1999 +++ linux.ac/drivers/sound/Config.in Fri Jun 4 23:52:43 1999 @@ -97,6 +97,9 @@ comment 'Enter -1 to the following question if you have something else such as SB16/32.' int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi + + dep_tristate 'PCI Legacy soundblaster enabler' CONFIG_SOUND_PCISB $CONFIG_SOUND_OSS + dep_tristate 'ESS-Tech Maestro support' CONFIG_SOUND_ESSMAESTRO $CONFIG_SOUND_OSS dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS @@ -272,16 +275,18 @@ hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi + + #dep_tristate 'USB audio support' CONFIG_SOUND_USBAUDIO $CONFIG_SOUND_OSS if [ "$CONFIG_ARM" = "y" ]; then dep_tristate 'VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS - dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then - hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 - int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 - int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 - int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 - fi + fi + dep_tristate 'Rockwell WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_WAVEARTIST" = "y" ]; then + hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 + int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 fi diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/Makefile linux.ac/drivers/sound/Makefile --- linux.vanilla/drivers/sound/Makefile Tue Jan 19 02:57:32 1999 +++ linux.ac/drivers/sound/Makefile Sat Jun 12 20:00:29 1999 @@ -53,6 +53,8 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_ESSMAESTRO) += ess_pci.o +obj-$(CONFIG_SOUND_PCISB) += pci_legacy.o sb.o uart401.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o @@ -64,11 +66,12 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o -obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o +obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o +obj-$(CONFIG_SOUND_USBAUDIO) += usb_audio.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/dev_table.h linux.ac/drivers/sound/dev_table.h --- linux.vanilla/drivers/sound/dev_table.h Fri Apr 16 22:10:56 1999 +++ linux.ac/drivers/sound/dev_table.h Sat Jun 12 20:06:07 1999 @@ -25,30 +25,18 @@ #define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ #define SNDCARD_VIDC 28 /* ARMs VIDC */ #define SNDCARD_SBPNP 29 -#define SNDCARD_OPL3SA1 38 -#define SNDCARD_OPL3SA1_SB 39 -#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_SOFTOSS 36 #define SNDCARD_VMIDI 37 +#define SNDCARD_OPL3SA1 38 /* Note: clash in msnd.h */ +#define SNDCARD_OPL3SA1_SB 39 +#define SNDCARD_OPL3SA1_MPU 40 #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 #define SNDCARD_WAVEARTIST 44 +#define SNDCARD_OPL3SA2_MSS 45 /* Originally missed */ #define SNDCARD_AD1816 88 -void attach_opl3sa_wss (struct address_info *hw_config); -int probe_opl3sa_wss (struct address_info *hw_config); -void attach_opl3sa_sb (struct address_info *hw_config); -int probe_opl3sa_sb (struct address_info *hw_config); -void attach_opl3sa_mpu (struct address_info *hw_config); -int probe_opl3sa_mpu (struct address_info *hw_config); -void unload_opl3sa_wss(struct address_info *hw_info); -void unload_opl3sa_sb(struct address_info *hw_info); -void unload_opl3sa_mpu(struct address_info *hw_info); -void attach_softsyn_card (struct address_info *hw_config); -int probe_softsyn (struct address_info *hw_config); -void unload_softsyn (struct address_info *hw_config); - /* * NOTE! NOTE! NOTE! NOTE! * @@ -424,6 +412,7 @@ #ifdef CONFIG_SOUND_OPL3SA2 {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, + {"OPL3SA2MSS", 1, SNDCARD_OPL3SA2_MSS, "OPL3SA2 MSS", attach_opl3sa2_mss, probe_opl3sa2_mss, unload_opl3sa2_mss}, {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, #endif @@ -587,10 +576,11 @@ #ifndef CONFIG_OPL3SA2_DMA2 #define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA #endif + {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_CTRL_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MSS, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #ifdef CONFIG_OPL3SA2_MPU_BASE - {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, CONFIG_OPL3SA2_DMA, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SGALAXY diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/dmasound.c linux.ac/drivers/sound/dmasound.c --- linux.vanilla/drivers/sound/dmasound.c Wed Mar 24 10:55:22 1999 +++ linux.ac/drivers/sound/dmasound.c Mon Jul 19 03:21:39 1999 @@ -4579,7 +4579,7 @@ if (nbufs < 2 || nbufs > numBufs) nbufs = numBufs; size &= 0xffff; - if (size >= 8 && size <= 30) { + if (size >= 8 && size <= 29) { size = 1 << size; size *= sound.hard.size * (sound.hard.stereo + 1); size /= sound.soft.size * (sound.soft.stereo + 1); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1370.c linux.ac/drivers/sound/es1370.c --- linux.vanilla/drivers/sound/es1370.c Tue Jun 15 16:49:52 1999 +++ linux.ac/drivers/sound/es1370.c Mon Jul 19 03:56:19 1999 @@ -98,6 +98,9 @@ * (micz). From Kim.Berts@fisub.mail.abb.com * 11.05.99 0.22 Implemented the IMIX call to mute recording monitor. * Guenter Geiger + * 15.06.99 0.23 Fix bad allocation bug. + * Thanks to Deti Fliegl + * 28.06.99 0.24 Add pci_set_master * * some important things missing in Ensoniq documentation: * @@ -531,8 +534,9 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) - db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order); + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) + break; if (!db->rawbuf) return -ENOMEM; db->buforder = order; @@ -2317,7 +2321,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.22 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2381,6 +2385,7 @@ /* initialize the chips */ outl(s->ctrl, s->io+ES1370_REG_CONTROL); outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); + pci_set_master(pcidev); /* enable bus mastering */ wrcodec(s, 0x16, 3); /* no RST, PD */ wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */ wrcodec(s, 0x18, 0); /* recording source is mixer */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/es1371.c linux.ac/drivers/sound/es1371.c --- linux.vanilla/drivers/sound/es1371.c Fri Apr 16 22:10:56 1999 +++ linux.ac/drivers/sound/es1371.c Mon Jul 19 03:56:19 1999 @@ -65,6 +65,9 @@ * reported by "Ivan N. Kokshaysky" * Note: joystick address handling might still be wrong on archs * other than i386 + * 15.06.99 0.12 Fix bad allocation bug. + * Thanks to Deti Fliegl + * 28.06.99 0.13 Add pci_set_master * */ @@ -759,8 +762,9 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) - db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order); + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) + break; if (!db->rawbuf) return -ENOMEM; db->buforder = order; @@ -2732,7 +2736,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.11 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2789,6 +2793,7 @@ outl(s->ctrl, s->io+ES1371_REG_CONTROL); outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); outl(0, s->io+ES1371_REG_LEGACY); + pci_set_master(pcidev); /* enable bus mastering */ /* AC97 warm reset to start the bitclk */ outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL); udelay(2); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/ess_pci.c linux.ac/drivers/sound/ess_pci.c --- linux.vanilla/drivers/sound/ess_pci.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/ess_pci.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,962 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "maestro.h" +#include "maestro_tables.h" + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_SBBASE 0x220 + +struct address_info maestro_cfg; + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(100); + outw(0x0000, ioaddr+0x36); + udelay(100); +} + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +static u16 maestro_map[32]; +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(int ioaddr, u16 reg, u16 data) +{ + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(int ioaddr, u16 reg) +{ + if(READABLE_MAP & (1<>=1; + + for(channel=low_apu; channel <= high_apu; channel++) + { + int i; + + pa = virt_to_bus(buffer); + wave_set_register(io, 0x01FC+channel, 0x0000); + wave_set_register(io,0x0000, pa&0xFFFF); + pa>>=1; + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(io, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(io, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(io, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(io, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(io, channel, 5, pa&0xFFFF); + apu_set_register(io, channel, 6, (pa+size)&0xFFFF); + apu_set_register(io, channel, 7, size); + + apu_set_register(io, channel, 8, 0x0000); + apu_set_register(io, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == low_apu) + apu_set_register(io, channel, 10, 0x8F00); + else + apu_set_register(io, channel, 10, 0x8F10); + } + else + apu_set_register(io, channel, 10, 0x8F08); + apu_set_register(io, channel, 11, 0x0000); + apu_set_register(io, channel, 0, 0x400F); + } + +// outw(1, io+0x04) +// outw(inw(io+0x18)|4, io+0x18); + + for(channel=low_apu; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) /* 16 bit */ + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x20); + else + apu_set_register(io, channel, 0, + (apu_get_register(io, channel, 0)&0xFF0F)|0x40); + } +} + +static void ess_play_finish(int io, int channel, int mode) +{ + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + if(mode&1) + { + channel++; + apu_set_register(io, channel, 0, + apu_get_register(io, channel, 0)&0xFF0F); + } +} + +static void ess_play_test(int io) +{ + u8 *buf=kmalloc(8192, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + for(ct=0; ct<8192;ct++) + { + buf[ct]=ct^39; + } + ess_play_setup(io, 10, 0, 0x39CD, buf, 8192); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(io, 10, 0); + kfree(buf); +} + + +/* + * Configure up legacy mode on the ESS-Tech Maestro and Maestro-2 + * + * This is also pretty much the same set up to configure the native + * mode which is what we will finally use. This is the "2.2 at least + * you get sound" stopgap for the moment. + */ + +static int maestro_install(struct pci_dev *pcidev, char *name) +{ + u16 w; + u32 n; + int iobase; + int i; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + if(check_region(ESS_SBBASE, 16)) + { + printk(KERN_WARNING "ess_pci: skipping - I/O 0x%03X is not free.\n", + ESS_SBBASE); + return 0; + } + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(i=0;i<16;i++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+i, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + (wave_get_register(iobase, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(iobase, IDR7_WAVE_ROMRAM, + wave_get_register(iobase, IDR7_WAVE_ROMRAM)|~0x400); + + maestro_write(iobase, IDR2_CRAM_DATA, 0x0000); + maestro_write(iobase, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(iobase, 0x09, 0x001B); + maestro_write(iobase, 0x0A, 0x8000); + maestro_write(iobase, 0x0B, 0x3F37); + maestro_write(iobase, 0x0C, 0x0098); + + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0xF000)|0x8000); + maestro_write(iobase, 0x0C, + (maestro_read(iobase, 0x0C)&~0x0F00)|0x0500); + + maestro_write(iobase, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + + for(i=0;i<64;i++) + { + for(w=0;w<0x0E;w++) + apu_set_register(iobase, i, w, 0); + } + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<14)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<13)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&~(1<<12)); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xFCFF); + apu_set_register(iobase, 6, 0, + apu_get_register(iobase, 6, 0)&0xF3FF); + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase, 6, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0x00FF); + apu_set_register(iobase, 6, 3, 0x0000); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFF3F); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)|(1<<5)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&~(1<<4)); + apu_set_register(iobase, 6, 2, + apu_get_register(iobase, 6, 2)&0xFFF0); + apu_set_register(iobase, 6, 4, 0x4B5F); + apu_set_register(iobase, 6, 5, 0xFDD5); + apu_set_register(iobase, 6, 6, 0xFE00); + apu_set_register(iobase, 6, 7, 0x0100); + apu_set_register(iobase, 6, 8, 0x78FF); + apu_set_register(iobase, 6, 9, 0xFFFF); + apu_set_register(iobase, 6, 0xA,0x8A10); + apu_set_register(iobase, 6, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<14)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<13)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&~(1<<12)); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xFCFF); + apu_set_register(iobase, 62, 0, + apu_get_register(iobase, 62, 0)&0xF3FF); + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase, 62, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0x00FF); + apu_set_register(iobase, 62, 3, 0x1000); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFF3F); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<5)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&~(1<<4)); + apu_set_register(iobase, 62, 2, + apu_get_register(iobase, 62, 2)&0xFFF0); + apu_set_register(iobase, 62, 4, 0x7F00); + apu_set_register(iobase, 62, 5, 0x8000); + apu_set_register(iobase, 62, 6, 0x8080); + apu_set_register(iobase, 62, 7, 0x0080); + apu_set_register(iobase, 62, 8, 0x7F00); + apu_set_register(iobase, 62, 9, 0xFFFF); + apu_set_register(iobase, 62, 0xA,0x7F00); + apu_set_register(iobase, 62, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<14)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<13)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&~(1<<12)); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xFCFF); + apu_set_register(iobase, 63, 0, + apu_get_register(iobase, 63, 0)&0xF3FF); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase, 63, 0)&0xFFF0)|0x0F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0x00FF); + apu_set_register(iobase, 63, 3, 0x1000); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFF3F); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<5)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&~(1<<4)); + apu_set_register(iobase, 63, 2, + apu_get_register(iobase, 63, 2)&0xFFF0); + apu_set_register(iobase, 63, 4, 0x7F00); + apu_set_register(iobase, 63, 5, 0x0000); + apu_set_register(iobase, 63, 6, 0x0080); + apu_set_register(iobase, 63, 7, 0x0080); + apu_set_register(iobase, 63, 8, 0x7F00); + apu_set_register(iobase, 63, 9, 0xFFFF); + apu_set_register(iobase, 63, 0xA,0x7F10); + apu_set_register(iobase, 63, 0xB,0x00F0); + + apu_set_register(iobase, 6, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(iobase, 62, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + apu_set_register(iobase, 63, 0, + (apu_get_register(iobase,6, 0)&0xFF0F)|(1<<4)); + + load_tables(iobase); + + outb(0x41, ESS_SETUP_A4+iobase); + udelay(1); + + printk(KERN_INFO "ess_pci: Programmed %s at 0x%X to legacy mode.\n", + name, iobase); + + ess_play_test(iobase); + maestro_cfg.dma = 1; + maestro_cfg.irq = pcidev->irq; + maestro_cfg.io_base = ESS_SBBASE; + maestro_cfg.dma2 = -1; + if(sb_dsp_detect(&maestro_cfg, SB_PCI_ESSMAESTRO, iobase)==-1) + { + printk(KERN_WARNING "esspci: Sound blaster emulation not responding.\n"); + return 0; + } + attach_sb_card(&maestro_cfg); + return 1; +} + + + +/* + * For now this does one card only. It is written this way as it will change + */ + +int init_ess19xx(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + + if(!pci_present()) + return -ENODEV; + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro 2"); + if(count) + return 0; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { +// count+=maestro_install(pcidev, "ESS Maestro 2E"); + printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(count) + return 0; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + count+=maestro_install(pcidev, "ESS Maestro"); + if(count) + return 0; + } + if(count==0) + return -ENODEV; + return 0; +} + + +int init_module(void) +{ + if(init_ess19xx()<0) + { + printk(KERN_ERR "No ESS Maestro cards found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + if(maestro_cfg.slots[0] != -1) + unload_sb(&maestro_cfg); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/lowlevel/awe_compat-fbsd.h linux.ac/drivers/sound/lowlevel/awe_compat-fbsd.h --- linux.vanilla/drivers/sound/lowlevel/awe_compat-fbsd.h Tue Dec 22 23:19:53 1998 +++ linux.ac/drivers/sound/lowlevel/awe_compat-fbsd.h Mon Jul 19 19:48:20 1999 @@ -51,7 +51,6 @@ #ifdef AWE_OBSOLETE_VOXWARE -#include #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) #define CONFIG_AWE32_SYNTH #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/mad16.c linux.ac/drivers/sound/mad16.c --- linux.vanilla/drivers/sound/mad16.c Wed Mar 10 21:13:07 1999 +++ linux.ac/drivers/sound/mad16.c Wed Jul 7 07:01:56 1999 @@ -668,7 +668,7 @@ * Set the IRQ and DMA addresses. */ - if (board_type == C930) + if (board_type == C930 || c924pnp) interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ bits = interrupt_bits[hw_config->irq]; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.c linux.ac/drivers/sound/maestro.c --- linux.vanilla/drivers/sound/maestro.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.c Tue Jun 22 19:36:54 1999 @@ -0,0 +1,2797 @@ +/*****************************************************************************/ + +/* + * ESS Maestro/Maestro-2 driver for Linux 2.2.x + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * (c) Copyright 1999 Alan Cox + * + * Based heavily on SonicVibes.c: + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * + * Supported devices: + * /dev/dsp0-7 standard /dev/dsp device, (mostly) OSS compatible + * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible + * + * Revision history + * + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "maestro.h" +#include "maestro_tables.h" + + + + +/* --------------------------------------------------------------------- */ + +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + +#ifndef PCI_VENDOR_ESS +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1969 0x1969 +#define PCI_DEVICE_ID_ESS_ESS1948 0x1948 /* Solo ?? */ +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ +#endif + +#define ESS_CHAN_HARD 0x100 + +#define ESS_CFMT_STEREO 0x01 +#define ESS_CFMT_16BIT 0x02 +#define ESS_CFMT_MASK 0x03 +#define ESS_CFMT_ASHIFT 0 +#define ESS_CFMT_CSHIFT 4 + +#define ESS_ENABLE_PE 1 +#define ESS_ENABLE_RE 2 + +#define ESS_MAGIC 0x125D1968 + +#define DAC_RUNNING 1 +#define ADC_RUNNING 2 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; + +#define SND_DEV_DSP16 5 + +/* --------------------------------------------------------------------- */ + +struct ess_state { + unsigned int magic; + /* FIXME: we probably want submixers in here, but only one record pair */ + u8 apu[4]; /* Left, Right, Left In, Right In */ + u8 apu_mode[4]; /* Running mode for this APU */ + u8 apu_pan[4]; /* Panning setup for this APU */ + struct ess_card *card; /* Card info */ + /* wave stuff */ + unsigned int rateadc, ratedac; + unsigned char fmt, enable; + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + struct wait_queue *open_wait; + + /* soundcore stuff */ + int dev_audio; + int dev_mixer; + + struct dmabuf { + void *rawbuf; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + unsigned hwptr, swptr; + unsigned total_bytes; + int count; + unsigned error; /* over/underrun */ + struct wait_queue *wait; + /* redundant, but makes calculations easier */ + unsigned fragsize; + unsigned dmasize; + unsigned fragsamples; + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + u16 base; /* Offset for ptr */ + } dma_dac, dma_adc; +}; + +struct ess_card { + unsigned int magic; + + /* We keep maestro cards in a linked list */ + struct ess_card *next; + + struct ess_state channels[8]; + u16 maestro_map[32]; /* Register map */ + + /* hardware resources */ + u32 iobase; + u32 irq; + + /* mixer stuff */ + struct { + unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } mix; +}; + +extern __inline__ unsigned ld2(unsigned int x) +{ + unsigned r = 0; + + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; + } + if (x >= 2) + r++; + return r; +} + + +/* --------------------------------------------------------------------- */ + +static struct ess_card *devs = NULL; + +/* --------------------------------------------------------------------- */ + + +/* + * ESS Maestro AC97 codec programming interface. + */ + +static void maestro_ac97_set(int io, u8 cmd, u16 val) +{ + int i; + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + /* + * Write the bus + */ + outw(val, io+ESS_AC97_DATA); + udelay(1); + outb(cmd, io+ESS_AC97_INDEX); + udelay(1); +} + +static u16 maestro_ac97_get(int io, u8 cmd) +{ + int sanity=100000; + u16 data; + int i; + + /* + * Wait for the codec bus to be free + */ + + for(i=0;i<10000;i++) + { + if(!(inb(io+ESS_AC97_INDEX)&1)) + break; + } + + outb(cmd|0x80, io+ESS_AC97_INDEX); + udelay(1); + + while(inb(io+ESS_AC97_INDEX)&1) + { + sanity--; + if(!sanity) + { + printk(KERN_ERR "ess_pci: ac97 codec timeout.\n"); + return 0; + } + } + data=inw(io+ESS_AC97_DATA); + udelay(1); + return data; +} + +/* + * The Maestro can be wired to a standard AC97 compliant codec + * (see www.intel.com for the pdf's on this), or to a PT101 codec + * which appears to be the ES1918 (data sheet on the esstech.com.tw site) + * + * The PT101 setup is untested. + */ + +static u16 maestro_ac97_init(int iobase) +{ + maestro_ac97_set(iobase, 0x02, 0x0000); + maestro_ac97_set(iobase, 0x04, 0x0000); + maestro_ac97_set(iobase, 0x06, 0x0000); + maestro_ac97_set(iobase, 0x08, 0x9F1F); + maestro_ac97_set(iobase, 0x0A, 0x9F1F); + maestro_ac97_set(iobase, 0x0C, 0x9F1F); + maestro_ac97_set(iobase, 0x0E, 0x9F1F); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x9F1F); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0808); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0404); + maestro_ac97_set(iobase, 0x1E, 0x0404); + maestro_ac97_set(iobase, 0x20, 0x0000); + maestro_ac97_set(iobase, 0x26, 0x000F); + return 0; +} + +static u16 maestro_pt101_init(int iobase) +{ + maestro_ac97_set(iobase, 0x2A, 0x0001); + maestro_ac97_set(iobase, 0x2C, 0x0000); + maestro_ac97_set(iobase, 0x2C, 0xFFFF); + maestro_ac97_set(iobase, 0x10, 0x9F1F); + maestro_ac97_set(iobase, 0x12, 0x0808); + maestro_ac97_set(iobase, 0x14, 0x9F1F); + maestro_ac97_set(iobase, 0x16, 0x9F1F); + maestro_ac97_set(iobase, 0x18, 0x0404); + maestro_ac97_set(iobase, 0x1A, 0x0000); + maestro_ac97_set(iobase, 0x1C, 0x0000); + maestro_ac97_set(iobase, 0x02, 0x0404); + maestro_ac97_set(iobase, 0x04, 0x0808); + maestro_ac97_set(iobase, 0x0C, 0x801F); + maestro_ac97_set(iobase, 0x0E, 0x801F); + return 0; +} + +static void maestro_ac97_reset(int ioaddr) +{ + outw(0x2000, ioaddr+0x36); + udelay(20); + outw(0x0000, ioaddr+0x36); + udelay(200); +} + + + +/* + * Indirect register access. Not all registers are readable so we + * need to keep register state ourselves + */ + +#define WRITEABLE_MAP 0xEFFFFF +#define READABLE_MAP 0x64003F + +/* + * The ESS engineers were a little indirection happy. These indirected + * registers themselves include indirect registers at another layer + */ + +static void maestro_write(struct ess_state *ess, u16 reg, u16 data) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, ioaddr+0x02); + outw(data, ioaddr+0x00); + ess->card->maestro_map[reg]=data; + restore_flags(flags); +} + +static u16 maestro_read(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + if(READABLE_MAP & (1<card->maestro_map[reg]=inw(ioaddr+0x00); + restore_flags(flags); + } + return ess->card->maestro_map[reg]; +} + +/* + * These routines handle accessing the second level indirections to the + * wave ram. + */ + +/* + * The register names are the ones ESS uses (see 104T31.ZIP) + */ + +#define IDR0_DATA_PORT 0x00 +#define IDR1_CRAM_POINTER 0x01 +#define IDR2_CRAM_DATA 0x02 +#define IDR3_WAVE_DATA 0x03 +#define IDR4_WAVE_PTR_LOW 0x04 +#define IDR5_WAVE_PTR_HI 0x05 +#define IDR6_TIMER_CTRL 0x06 +#define IDR7_WAVE_ROMRAM 0x07 + +static void apu_index_set(struct ess_state *ess, u16 index) +{ + int i; + maestro_write(ess, IDR1_CRAM_POINTER, index); + for(i=0;i<1000;i++) + if(maestro_read(ess, IDR1_CRAM_POINTER)==index) + return; + printk(KERN_WARNING "ess_pci: APU register select failed.\n"); +} + +static void apu_data_set(struct ess_state *ess, u16 data) +{ + int i; + for(i=0;i<1000;i++) + { + if(maestro_read(ess, IDR0_DATA_PORT)==data) + return; + maestro_write(ess, IDR0_DATA_PORT, data); + } +} + +/* + * This is the public interface for APU manipulation. It handles the + * interlock to avoid two APU writes in parallel etc. Don't diddle + * directly with the stuff above. + */ + +static void apu_set_register(struct ess_state *ess, u16 channel, u8 reg, u16 data) +{ + unsigned long flags; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + { + if(channel>3) + printk("BAD CHANNEL %d.\n",channel); + else + channel = ess->apu[channel]; + } + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + apu_data_set(ess, data); + restore_flags(flags); +} + +static u16 apu_get_register(struct ess_state *ess, u16 channel, u8 reg) +{ + unsigned long flags; + u16 v; + + if(channel&ESS_CHAN_HARD) + channel&=~ESS_CHAN_HARD; + else + channel = ess->apu[channel]; + + reg|=(channel<<4); + + save_flags(flags); + cli(); + apu_index_set(ess, reg); + v=maestro_read(ess, IDR0_DATA_PORT); + restore_flags(flags); + return v; +} + + +/* + * The ASSP is fortunately not double indexed + */ + +static void assp_set_register(int ioaddr, u32 reg, u32 value) +{ + unsigned long flags; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + outl(value, ioaddr+0x84); + restore_flags(flags); +} + +static u32 assp_get_register(int ioaddr, u32 reg) +{ + unsigned long flags; + u32 value; + + save_flags(flags); + cli(); + outl(reg, ioaddr+0x80); + value=inl(ioaddr+0x84); + restore_flags(flags); + + return value; +} + +/* + * The wavecache is also sane + */ + +static void wave_set_register(struct ess_state *ess, u16 reg, u16 value) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + outw(value, ioaddr+0x12); + restore_flags(flags); +} + +static u16 wave_get_register(struct ess_state *ess, u16 reg) +{ + long ioaddr = ess->card->iobase; + unsigned long flags; + u16 value; + + save_flags(flags); + cli(); + outw(reg, ioaddr+0x10); + value=inw(ioaddr+0x12); + restore_flags(flags); + + return value; +} + +/* + * Additional Reset Functions + */ + +static void maestro_reset(int ioaddr) +{ + outw(0x8000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void sound_reset(int ioaddr) +{ + outw(0x2000, 0x18+ioaddr); + udelay(10); + outw(0x0000, 0x18+ioaddr); + udelay(10); +} + +static void asp_load(int ioaddr, u16 l, u16 h, u16 *data, int len) +{ + int i; + outw(l, ioaddr+0x80); + outw(h, ioaddr+0x82); + for(i=0;i>=1; + + + for(channel=0; channel <= high_apu; channel++) + { + int i; + + /* + * To understand this it helps to know how the + * wave cache works. There are 4 DSP wavecache + * blocks which are 0x1FC->0x1FF. They are selected + * by setting bits 22,21,20 of the address to + * 1 X Y where X Y select the block. + * + * In addition stereo pairing is supported. This is + * set in the wave cache control for the channel as is + * 8bit unsigned. + * + * Note that this causes a problem. With our limit of + * about 12 full duplex pairs (48 channels active) we + * will need to do a lot of juggling to get all the + * memory we want sufficiently close together. + * + * Even with 64K blocks that means + * 24 channel pairs + * 6 pairs/block + * + * 10K per channel pair = 5000 samples. + */ + + pa = virt_to_bus(buffer); + + wave_set_register(ess, 0x01FC, (pa&0xFFE00000)>>12); + + /* Flush the wave cache entry */ + if(!(mode&1)) + wave_set_register(ess, ess->apu[channel]<<3, (pa&0xFFFF)-0x10); + else + wave_set_register(ess, ess->apu[channel]<<3, ((pa&0xFFFF)-0x10)|2); + + pa&=0x1FFFFF; /* Low 21 bits */ + pa>>=1; + + ess->dma_dac.base = pa&0xFFFF; + + if(mode&1) /* Enable stereo */ + pa|=0x00800000; + pa|=0x00400000; /* System RAM */ + + /* Begin loading the APU */ + + for(i=0;i<15;i++) + apu_set_register(ess, channel, i, 0x0000); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10); + apu_set_register(ess, channel, 3, rate>>8); + + /* Load the buffer into the wave engine */ + apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8); + apu_set_register(ess, channel, 5, pa&0xFFFF); + apu_set_register(ess, channel, 6, (pa+size)&0xFFFF); + apu_set_register(ess, channel, 7, size); + + apu_set_register(ess, channel, 8, 0x0000); + apu_set_register(ess, channel, 9, 0xD000); + + if(mode&1) + { + /* Set left or right */ + if(channel == 0) + apu_set_register(ess, channel, 10, 0x8F00); + else + apu_set_register(ess, channel, 10, 0x8F10); + } + else + apu_set_register(ess, channel, 10, 0x8F08); + apu_set_register(ess, channel, 11, 0x0000); + apu_set_register(ess, channel, 0, 0x400F); + } + + outw(1, ess->card->iobase+0x04); + outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); + + for(channel=0; channel<=high_apu; channel++) + { + /* Turn on the DMA */ + if(mode&2) + { /* 16 bit */ + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x20); + ess->apu_mode[channel]=0x20; + } + else + { + apu_set_register(ess, channel, 0, + (apu_get_register(ess, channel, 0)&0xFF0F)|0x40); + ess->apu_mode[channel]=0x40; + } + } +} + +static void ess_play_finish(struct ess_state *ess, int mode) +{ + apu_set_register(ess, 0, 0, + apu_get_register(ess, 0, 0)&0xFF0F); + if(mode&1) + { + apu_set_register(ess, 1, 0, + apu_get_register(ess, 1, 0)&0xFF0F); + } +} + +static void ess_play_test(struct ess_state *ess) +{ + u8 *buf=kmalloc(16384, GFP_KERNEL|GFP_DMA); + int ct; + long time=jiffies; + if(buf!=NULL) + { + for(ct=0; ct<16384;ct++) + { + buf[ct]=ct^39; + } + } + ess_play_setup(ess, 0, 0x39CD, buf, 16384); + + while((jiffies-time)<5*HZ) + { + schedule(); + } + printk("\n"); + ess_play_finish(ess, 0); + if(buf) + kfree(buf); +} + + + + +/* --------------------------------------------------------------------- */ + +static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count) +{ +} + +/* Playback pointer */ + +extern __inline__ unsigned get_dmaa(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[0]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + offset-=s->dma_dac.base; + +// printk("Offset = %d\n", (offset&0x0FFFE)<<1); + return (offset&0xFFFE)/*<<1*/; +} + +/* Record pointer */ +extern __inline__ unsigned get_dmac(struct ess_state *s) +{ + long ioport = s->card->iobase; + int offset; + + outw(1, ioport+2); + outw(s->apu[2]<<4|5, ioport); + outw(0, ioport+2); + offset=inw(ioport); + + /* The offset is an address not a position relative to base */ + + + return (offset&0xFFFE)<<1; +} + +static void set_apu_fmt(struct ess_state *s, int apu, int mode) +{ + if(mode&ESS_CFMT_16BIT) + { + s->apu_mode[apu] = 2; + s->apu_mode[apu+1] = 2; + } + else + { + s->apu_mode[apu] = 4; + s->apu_mode[apu+1] = 4; + } +} + +static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data) +{ + s->fmt = (s->fmt & mask) | data; + set_apu_fmt(s, 0, s->fmt & ESS_CFMT_MASK); + set_apu_fmt(s, 2, (s->fmt >> ESS_CFMT_CSHIFT) & ESS_CFMT_MASK); +} + +static u16 compute_rate(u32 freq) +{ + if(freq==48000) + return 0xFFFF; + freq<<=16; + freq/=48000; + return freq; +} + +static void set_dac_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 0, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 0, 3, freq>>8); + apu_set_register(s, 1, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 1, 3, freq>>8); + s->ratedac = rate; +} + +static void set_adc_rate(struct ess_state *s, unsigned rate) +{ + u32 freq; + + if (rate > 48000) + rate = 48000; + if (rate < 4000) + rate = 4000; + freq = compute_rate(rate); + + /* Load the frequency, turn on 6dB, turn off the effects */ + apu_set_register(s, 2, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 2, 3, freq>>8); + apu_set_register(s, 3, 2, (freq&0xFF)<<8|0x10); + apu_set_register(s, 3, 3, freq>>8); + s->rateadc = rate; +} + +/* + * Meet Bob, the timer... + */ + + +static struct timer_list tmp_timer; + +static int bob_stopped; + +static int ess_interrupt_fake(unsigned long v) +{ + extern int ess_interrupt(int, void *, struct pt_regs *); + ess_interrupt(5, (void *)v, NULL); + del_timer(&tmp_timer); + if(!bob_stopped) + { + tmp_timer.expires=jiffies+1; + add_timer(&tmp_timer); + } + else + printk("Stopping bob\n"); + return 0; +} + +static void stop_bob(struct ess_state *s) +{ + bob_stopped=1; +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void kill_bob(struct ess_state *s) +{ + del_timer(&tmp_timer); + printk("Killing bob\n"); +// /* Mask IDR 11,17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)&~1); +// maestro_write(s, 0x17, maestro_read(s, 11)&~1); +} + +static void start_bob(struct ess_state *s) +{ +// stop_bob(s); +// maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11); +// /* Now set IDR 11/17 */ +// maestro_write(s, 0x11, maestro_read(s, 11)|1); +// maestro_write(s, 0x17, maestro_read(s, 11)|1); + static int init=1; + if(init) + { + init=0; + init_timer(&tmp_timer); + tmp_timer.function = ess_interrupt_fake; + } + bob_stopped = 0; + if(!timer_pending(&tmp_timer)) + { + del_timer(&tmp_timer); + tmp_timer.expires = jiffies+1; + tmp_timer.data = (unsigned long)s->card; + add_timer(&tmp_timer); + printk("Starting bob\n"); + } +} + +/* --------------------------------------------------------------------- */ + +static int adc_active = 0; + +extern inline void stop_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + /* Stop left and right recording APU */ + s->enable &= ~ADC_RUNNING; + apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F); + apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F); + adc_active&=~1; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +extern inline void stop_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + s->enable &= ~DAC_RUNNING; + apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F); + apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F); + adc_active&=~2; +// if(!adc_active) +// stop_bob(s); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_dac(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + s->enable |= DAC_RUNNING; + apu_set_register(s, 0, 0, + (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]); + apu_set_register(s, 1, 0, + (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=2; + spin_unlock_irqrestore(&s->lock, flags); +} + +static void start_adc(struct ess_state *s) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + && s->dma_adc.ready) { + s->enable |= ADC_RUNNING; + apu_set_register(s, 2, 0, + (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]); + apu_set_register(s, 3, 0, + (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]); + } +// if(!adc_active) +// start_bob(s); + adc_active|=1; + spin_unlock_irqrestore(&s->lock, flags); +} + +/* --------------------------------------------------------------------- */ + +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +static void dealloc_dmabuf(struct dmabuf *db) +{ + unsigned long map, mapend; + + if (db->rawbuf) { + /* undo marking the pages as reserved */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); + free_pages((unsigned long)db->rawbuf, db->buforder); + } + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + + +static int prog_dmabuf(struct ess_state *s, unsigned rec) +{ + struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac; + unsigned rate = rec ? s->rateadc : s->ratedac; + int order; + unsigned bytepersec; + unsigned bufs; + unsigned long map, mapend; + unsigned char fmt; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + fmt = s->fmt; + if (rec) { + s->enable &= ~ESS_ENABLE_RE; + fmt >>= ESS_CFMT_CSHIFT; + } else { + s->enable &= ~ESS_ENABLE_PE; + fmt >>= ESS_CFMT_ASHIFT; + } + spin_unlock_irqrestore(&s->lock, flags); + + db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) + db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order); + if (!db->rawbuf) + return -ENOMEM; + db->buforder = order; + if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) + printk(KERN_DEBUG "maestro: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) + printk(KERN_DEBUG "maestro: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); + } + bytepersec = rate << sample_shift[fmt]; + bufs = PAGE_SIZE << db->buforder; + if (db->ossfragshift) { + if ((1000 << db->ossfragshift) < bytepersec) + db->fragshift = ld2(bytepersec/1000); + else + db->fragshift = db->ossfragshift; + } else { + db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); + if (db->fragshift < 3) + db->fragshift = 3; + } + db->numfrag = bufs >> db->fragshift; + while (db->numfrag < 4 && db->fragshift > 3) { + db->fragshift--; + db->numfrag = bufs >> db->fragshift; + } + db->fragsize = 1 << db->fragshift; + if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) + db->numfrag = db->ossmaxfrags; + db->fragsamples = db->fragsize >> sample_shift[fmt]; + db->dmasize = db->numfrag << db->fragshift; + memset(db->rawbuf, (fmt & ESS_CFMT_16BIT) ? 0 : 0x80, db->dmasize); + spin_lock_irqsave(&s->lock, flags); + if (rec) { + set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + } else { + //set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + /* program enhanced mode registers */ + /* FILL */ + set_dac_rate(s, s->ratedac); + ess_play_setup(s, fmt, compute_rate(s->ratedac), + db->rawbuf, db->numfrag << db->fragshift); + + } + spin_unlock_irqrestore(&s->lock, flags); + db->ready = 1; + return 0; +} + +extern __inline__ void clear_advance(struct ess_state *s) +{ + unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80; + unsigned char *buf = s->dma_dac.rawbuf; + unsigned bsize = s->dma_dac.dmasize; + unsigned bptr = s->dma_dac.swptr; + unsigned len = s->dma_dac.fragsize; + + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(buf + bptr, c, x); + bptr = 0; + len -= x; + } + memset(buf + bptr, c, len); +} + +/* call with spinlock held! */ +static void ess_update_ptr(struct ess_state *s) +{ + unsigned hwptr; + int diff; + + /* update ADC pointer */ + if (s->dma_adc.ready) { + hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + if (!s->dma_adc.mapped) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { + s->enable &= ~ESS_ENABLE_RE; + /* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + stop_adc(s); + s->dma_adc.error++; + } + } + } + /* update DAC pointer */ + if (s->dma_dac.ready) { + hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + if (s->dma_dac.mapped) { + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + wake_up(&s->dma_dac.wait); + } else { + s->dma_dac.count -= diff; + if (s->dma_dac.count <= 0) { + s->enable &= ~ESS_ENABLE_PE; +/* FILL ME */ +// wrindir(s, SV_CIENABLE, s->enable); + + stop_dac(s); + s->dma_dac.error++; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { + clear_advance(s); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) + wake_up(&s->dma_dac.wait); + } + } +} + +static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ess_state *s; + struct ess_card *c = (struct ess_card *)dev_id; + int i; + u32 event; +/* + * 0x1A is a byte on maestro2E + * Turning this to byte cause the ess_play_test to play something + * but I don't know if it is what is intended to play .... seems a single + * note, in the medium range. + */ + event = inb(c->iobase+0x1A); + + outw(inw(c->iobase+4)&1, c->iobase+4); + + if(event&(1<<6)) + { + event = inw(c->iobase+0x18); + outb(0xFF, c->iobase+0x1A); + } + else + { + outb(0xFF, c->iobase+0x1A); + } + + /* + * Update the pointers for all 32 APU's we are running. + */ + for(i=0;i<8;i++) + { + s=&c->channels[i]; + if(s->dev_audio == -1) + break; + spin_lock(&s->lock); + ess_update_ptr(s); + spin_unlock(&s->lock); + } +} + + +/* --------------------------------------------------------------------- */ + +static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value\n"; + +#define VALIDATE_STATE(s) \ +({ \ + if (!(s) || (s)->magic != ESS_MAGIC) { \ + printk(invalid_magic); \ + return -ENXIO; \ + } \ +}) + +/* --------------------------------------------------------------------- */ +#if 0 + +#define MT_4 1 +#define MT_5MUTE 2 +#define MT_4MUTEMONO 3 +#define MT_6MUTE 4 + +static const struct { + unsigned left:5; + unsigned right:5; + unsigned type:3; + unsigned rec:3; +} mixtable[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 }, + [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 }, + [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 }, + [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 }, + [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 }, + [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 }, + [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 }, + [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 }, + [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } +}; + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +static int return_mixval(struct ess_state *s, unsigned i, int *arg) +{ + unsigned long flags; + unsigned char l, r, rl, rr; + + spin_lock_irqsave(&s->lock, flags); +// l = rdindir(s, mixtable[i].left); +// r = rdindir(s, mixtable[i].right); + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + r &= 0xf; + l &= 0xf; + rl = 10 + 6 * (l & 15); + rr = 10 + 6 * (r & 15); + break; + + case MT_4MUTEMONO: + rl = 55 - 3 * (l & 15); + if (r & 0x10) + rl += 45; + rr = rl; + r = l; + break; + + case MT_5MUTE: + default: + rl = 100 - 3 * (l & 31); + rr = 100 - 3 * (r & 31); + break; + + case MT_6MUTE: + rl = 100 - 3 * (l & 63) / 2; + rr = 100 - 3 * (r & 63) / 2; + break; + } + if (l & 0x80) + rl = 0; + if (r & 0x80) + rr = 0; + return put_user((rr << 8) | rl, arg); +} + +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + [SOUND_MIXER_RECLEV] = 1, + [SOUND_MIXER_LINE1] = 2, + [SOUND_MIXER_CD] = 3, + [SOUND_MIXER_LINE] = 4, + [SOUND_MIXER_MIC] = 5, + [SOUND_MIXER_SYNTH] = 6, + [SOUND_MIXER_LINE2] = 7, + [SOUND_MIXER_VOLUME] = 8, + [SOUND_MIXER_PCM] = 9 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static unsigned mixer_recmask(struct ess_state *s) +{ + unsigned long flags; + int i, j; + + spin_lock_irqsave(&s->lock, flags); +// j = rdindir(s, SV_CIMIX_ADCINL) >> 5; + /* FILL ME */ + spin_unlock_irqrestore(&s->lock, flags); + j &= 7; + for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++); + return 1 << i; +} + +static int mixer_ioctl(struct ess_state *s, unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int i, val; + unsigned char l, r, rl, rr; + + VALIDATE_STATE(s); + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + info.modify_counter = s->mix.modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "SonicVibes", sizeof(info.id)); + strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ + get_user_ret(val, (int *)arg, -EFAULT); + spin_lock_irqsave(&s->lock, flags); + if (val & 1) { + if (val & 2) { + l = 4 - ((val >> 2) & 7); + if (l & ~3) + l = 4; + r = 4 - ((val >> 5) & 7); + if (r & ~3) + r = 4; + wrindir(s, SV_CISRSSPACE, l); + wrindir(s, SV_CISRSCENTER, r); + } else + wrindir(s, SV_CISRSSPACE, 0x80); + } + l = rdindir(s, SV_CISRSSPACE); + r = rdindir(s, SV_CISRSCENTER); + spin_unlock_irqrestore(&s->lock, flags); + if (l & 0x80) + return put_user(0, (int *)arg); + return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, (int *)arg); + } + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + return put_user(mixer_recmask(s), (int *)arg); + + case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].rec) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ + for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) + val |= 1 << i; + return put_user(val, (int *)arg); + + case SOUND_MIXER_CAPS: + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } + } + if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) + return -EINVAL; + s->mix.modcnt++; + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ + get_user_ret(val, (int *)arg, -EFAULT); + i = hweight32(val); + if (i == 0) + return 0; /*val = mixer_recmask(s);*/ + else if (i > 1) + val &= ~mixer_recmask(s); + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!(val & (1 << i))) + continue; + if (mixtable[i].rec) + break; + } + if (!mixtable[i].rec) + return 0; + spin_lock_irqsave(&s->lock, flags); + frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5); + frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + l = val & 0xff; + r = (val >> 8) & 0xff; + if (mixtable[i].type == MT_4MUTEMONO) + l = (r + l) / 2; + if (l > 100) + l = 100; + if (r > 100) + r = 100; + spin_lock_irqsave(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + if (l >= 10) + l -= 10; + if (r >= 10) + r -= 10; + frobindir(s, mixtable[i].left, 0xf0, l / 6); + frobindir(s, mixtable[i].right, 0xf0, l / 6); + break; + + case MT_4MUTEMONO: + rr = 0; + if (l < 10) + rl = 0x80; + else { + if (l >= 55) { + rr = 0x10; + l -= 45; + } + rl = (55 - l) / 3; + } + wrindir(s, mixtable[i].left, rl); + frobindir(s, mixtable[i].right, ~0x10, rr); + break; + + case MT_5MUTE: + if (l < 7) + rl = 0x80; + else + rl = (100 - l) / 3; + if (r < 7) + rr = 0x80; + else + rr = (100 - r) / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + + case MT_6MUTE: + if (l < 6) + rl = 0x80; + else + rl = (100 - l) * 2 / 3; + if (r < 6) + rr = 0x80; + else + rr = (100 - r) * 2 / 3; + wrindir(s, mixtable[i].left, rl); + wrindir(s, mixtable[i].right, rr); + break; + } + spin_unlock_irqrestore(&s->lock, flags); +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + } +} + +#endif + +/* --------------------------------------------------------------------- */ + +static loff_t ess_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + +#if 0 +static int ess_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_state *s = devs; + + while (s && s->dev_mixer != minor) + s = s->next; + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + file->private_data = s; + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release_mixdev(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + MOD_DEC_USE_COUNT; + return 0; +} + +static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl((struct ess_state *)file->private_data, cmd, arg); +} + +static /*const*/ struct file_operations ess_mixer_fops = { + &ess_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + &ess_ioctl_mixdev, + NULL, /* mmap */ + &ess_open_mixdev, + NULL, /* flush */ + &ess_release_mixdev, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + +#endif + +/* --------------------------------------------------------------------- */ + +static int drain_dac(struct ess_state *s, int nonblock) +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int count, tmo; + + if (s->dma_dac.mapped || !s->dma_dac.ready) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / s->ratedac; + tmo >>= sample_shift[(s->fmt >> ESS_CFMT_ASHIFT) & ESS_CFMT_MASK]; + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "maestro: dma timed out??\n"); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static ssize_t ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + /* FILL ME */ +// wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_adc.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + return ret; +} + +static ssize_t ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; +#if 0 + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + cnt = s->dma_dac.dmasize-swptr; + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ +// wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); +// wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + /* FILL ME */ + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_dac.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + return ret; +} + +static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + +static int ess_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf(s, 1)) != 0) + return ret; + db = &s->dma_dac; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf(s, 0)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (vma->vm_offset != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + return 0; +} + +static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + unsigned char fmtm, fmtd; + + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; + } + return 0; + + case SNDCTL_DSP_SPEED: + get_user_ret(val, (int *)arg, -EFAULT); + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + set_adc_rate(s, val); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + set_dac_rate(s, val); + } + } + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SNDCTL_DSP_STEREO: + get_user_ret(val, (int *)arg, -EFAULT); + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + return 0; + + case SNDCTL_DSP_CHANNELS: + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 0) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val >= 2) + fmtd |= ESS_CFMT_STEREO << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_STEREO << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != AFMT_QUERY) { + fmtd = 0; + fmtm = ~0; + if (file->f_mode & FMODE_READ) { + stop_adc(s); + s->dma_adc.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_CSHIFT); + } + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + s->dma_dac.ready = 0; + if (val == AFMT_S16_LE) + fmtd |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + else + fmtm &= ~(ESS_CFMT_16BIT << ESS_CFMT_ASHIFT); + } + set_fmt(s, fmtm, fmtd); + } + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && s->enable & ESS_ENABLE_RE) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && s->enable & ESS_ENABLE_PE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->enable & ESS_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + ess_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf(s, 0))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf(s, 1))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + get_user_ret(val, (int *)arg, -EFAULT); + if (file->f_mode & FMODE_READ) { + s->dma_adc.ossfragshift = val & 0xffff; + s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_adc.ossfragshift < 4) + s->dma_adc.ossfragshift = 4; + if (s->dma_adc.ossfragshift > 15) + s->dma_adc.ossfragshift = 15; + if (s->dma_adc.ossmaxfrags < 4) + s->dma_adc.ossmaxfrags = 4; + } + if (file->f_mode & FMODE_WRITE) { + s->dma_dac.ossfragshift = val & 0xffff; + s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; + if (s->dma_dac.ossfragshift < 4) + s->dma_dac.ossfragshift = 4; + if (s->dma_dac.ossfragshift > 15) + s->dma_dac.ossfragshift = 15; + if (s->dma_dac.ossmaxfrags < 4) + s->dma_dac.ossmaxfrags = 4; + } + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + get_user_ret(val, (int *)arg, -EFAULT); + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_STEREO << ESS_CFMT_CSHIFT) + : (ESS_CFMT_STEREO << ESS_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_CFMT_16BIT << ESS_CFMT_CSHIFT) + : (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } +// return mixer_ioctl(s, cmd, arg); + return -EINVAL; +} + +static int ess_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct ess_card *c = devs; + struct ess_state *s = NULL, *sp; + int i; + unsigned char fmtm = ~0, fmts = 0; + + /* + * Scan the cards and find the channel. We only + * do this at open time so it is ok + */ + + while (c!=NULL) + { + for(i=0;i<8;i++) + { + sp=&c->channels[i]; + if(sp->dev_audio < 0) + continue; + if((sp->dev_audio ^ minor) & ~0xf) + continue; + s=sp; + } + c=c->next; + } + + if (!s) + return -ENODEV; + + VALIDATE_STATE(s); + file->private_data = s; + /* wait for device to become free */ + down(&s->open_sem); + while (s->open_mode & file->f_mode) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EWOULDBLOCK; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + if (file->f_mode & FMODE_READ) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_CSHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_CSHIFT; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + set_adc_rate(s, 8000); + } + if (file->f_mode & FMODE_WRITE) { + fmtm &= ~((ESS_CFMT_STEREO | ESS_CFMT_16BIT) << ESS_CFMT_ASHIFT); + if ((minor & 0xf) == SND_DEV_DSP16) + fmts |= ESS_CFMT_16BIT << ESS_CFMT_ASHIFT; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + set_dac_rate(s, 8000); + } + set_fmt(s, fmtm, fmts); + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + start_bob(s); + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} + +static int ess_release(struct inode *inode, struct file *file) +{ + struct ess_state *s = (struct ess_state *)file->private_data; + + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(&s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(&s->dma_adc); + } + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); + stop_bob(s); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +static /*const*/ struct file_operations ess_audio_fops = { + &ess_llseek, + &ess_read, + &ess_write, + NULL, /* readdir */ + &ess_poll, + &ess_ioctl, + &ess_mmap, + &ess_open, + NULL, /* flush */ + &ess_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL, /* lock */ +}; + + +/* --------------------------------------------------------------------- */ + +/* maximum number of devices */ +#define NR_DEVICE 4 + +/* --------------------------------------------------------------------- */ + +#if 0 +static struct initvol { + int mixch; + int vol; +} initvol[] __initdata = { + { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, + { SOUND_MIXER_WRITE_LINE1, 0x4040 }, + { SOUND_MIXER_WRITE_CD, 0x4040 }, + { SOUND_MIXER_WRITE_LINE, 0x4040 }, + { SOUND_MIXER_WRITE_MIC, 0x4040 }, + { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, + { SOUND_MIXER_WRITE_LINE2, 0x4040 }, + { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, + { SOUND_MIXER_WRITE_PCM, 0x4040 } +}; + +#endif + +static int maestro_install(struct pci_dev *pcidev, char *name, int index) +{ + u16 w; + u32 n; + int iobase; + int i; + struct ess_card *card; + struct ess_state *ess; + int apu; + int num = 0; + + iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + + card = kmalloc(sizeof(struct ess_card), GFP_KERNEL); + if(card == NULL) + { + printk(KERN_WARNING "maestro: out of memory\n"); + return 0; + } + + memset(card, 0, sizeof(*card)); + + card->iobase = iobase; + card->irq = pcidev->irq; + card->next = devs; + devs = card; + + for(i=0;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + + s->card = card; + init_waitqueue(&s->dma_adc.wait); + init_waitqueue(&s->dma_dac.wait); + init_waitqueue(&s->open_wait); + s->open_sem = MUTEX; + s->magic = ESS_MAGIC; + + s->apu[0] = 4*i; + s->apu[1] = (4*i)+1; + s->apu[2] = (4*i)+2; + s->apu[3] = (4*i)+3; + + if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf) + printk("BOTCH!\n"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0) + break; +// if ((s->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) +// break; + } + + num = i; + + for(;i<8;i++) + { + struct ess_state *s=&card->channels[i]; + s->dev_audio = -1; + } + + ess = &card->channels[0]; + + /* + * Ok card ready. Begin setup proper + */ + + printk(KERN_INFO "ess_pci: Configuring %s at 0x%04X\n", name, iobase); + + /* + * Disable ACPI + */ + + pci_write_config_dword(pcidev, 0x54, 0x00000000); + + /* + * Use TDMA for now. TDMA works on all boards, so while its + * not the most efficient its the simplest. + */ + + pci_read_config_word(pcidev, 0x50, &w); + + /* Clear DMA bits */ + w&=~(1<<10|1<<9|1<<8); + + /* TDMA on */ + w|=(1<<8); + + /* + * MPU at 330 + */ + + w&=~((1<<4)|(1<<3)); + + /* + * SB at 0x220 + */ + + w&=~(1<<2); + + /* + * Reserved write as 0 + */ + + w&=~(1<<1); + + /* + * Some of these are undocumented bits + */ + + w&=~(1<<13)|(1<<14); /* PIC Snoop mode bits */ + w&=~(1<<11); /* Safeguard off */ + w|= (1<<7); /* Posted write */ + w|= (1<<6); /* ISA timing on */ + w&=~(1<<1); /* Subtractive decode off */ + w&=~(1<<5); /* Don't swap left/right */ + + pci_write_config_word(pcidev, 0x50, w); + + pci_read_config_word(pcidev, 0x52, &w); + w&=~(1<<15); /* Turn off internal clock multiplier */ + w&=~(1<<14); /* External clock */ + + w&=~(1<<7); /* HWV off */ + w&=~(1<<6); /* Debounce off */ + w&=~(1<<5); /* GPIO 4:5 */ + w&=~(1<<4); /* Disconnect from the CHI */ + w&=~(1<<3); /* IDMA off (undocumented) */ + w&=~(1<<2); /* MIDI fix off (undoc) */ + w&=~(1<<0); /* IRQ to ISA off (undoc) */ + pci_write_config_word(pcidev, 0x52, w); + + /* + * DDMA off + */ + + pci_read_config_word(pcidev, 0x60, &w); + w&=~(1<<0); + pci_write_config_word(pcidev, 0x60, w); + + /* + * Legacy mode + */ + + pci_read_config_word(pcidev, 0x40, &w); + w&=~(1<<15); /* legacy decode on */ + w&=~(1<<14); /* Disable SIRQ */ + w&=~(1<<13|1<<12|1<<11); + + /* + * We don't use the emulation IRQ's + */ + + w|=(1<<11); /* MPU IRQ 7 */ + w&=~(1<<10|1<<9|1<<8); /* SB IRQ 5 */ + w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ + w&=~(1<<7|1<<6); + w|=(1<<6); /* DMA 1 */ + + /* + * Default to DMA 1 + */ + + pci_write_config_word(pcidev, 0x40, w); + + sound_reset(iobase); + + + /* + * Reset the CODEC + */ + + maestro_ac97_reset(iobase); + + /* + * Ring Bus Setup + */ + + n=inl(iobase+0x34); + n&=~0xF000; + n|=12<<12; /* Direct Sound, Stereo */ + + n=inl(iobase+0x34); + n&=~0x0F00; /* Modem off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F0; + n|=9<<4; /* DAC, Stereo */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F; /* ASSP off */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<29); /* Enable ring bus */ + outl(n, iobase+0x34); + + + n=inl(iobase+0x34); + n|=(1<<28); /* Enable serial bus */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x00F00000; /* MIC off */ + outl(n, iobase+0x34); + + n=inl(iobase+0x34); + n&=~0x000F0000; /* I2S off */ + outl(n, iobase+0x34); + + w=inw(iobase+0x18); + w&=~(1<<7); /* ClkRun off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<6); /* Harpo off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<4); /* ASSP irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<3); /* ISDN irq off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<2); /* Direct Sound IRQ on */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w&=~(1<<1); /* MPU401 IRQ off */ + outw(w, iobase+0x18); + + w=inw(iobase+0x18); + w|=(1<<0); /* SB IRQ on */ + outw(w, iobase+0x18); + + + outb(0, iobase+0xA4); + outb(3, iobase+0xA2); + outb(0, iobase+0xA6); + + for(apu=0;apu<16;apu++) + { + /* Write 0 into the buffer area 0x1E0->1EF */ + outw(0x01E0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + + /* + * The 1.10 test program seem to write 0 into the buffer area + * 0x1D0-0x1DF too. + */ + outw(0x01D0+apu, 0x10+iobase); + outw(0x0000, 0x12+iobase); + } + +#if 1 + wave_set_register(ess, IDR7_WAVE_ROMRAM, + (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200); + wave_set_register(ess, IDR7_WAVE_ROMRAM, + wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400); +#else + maestro_write(ess, IDR7_WAVE_ROMRAM, + (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00)); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200); + maestro_write(ess, IDR7_WAVE_ROMRAM, + maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400); +#endif + + maestro_write(ess, IDR2_CRAM_DATA, 0x0000); + maestro_write(ess, 0x08, 0xB004); + /* Now back to the DirectSound stuff */ + maestro_write(ess, 0x09, 0x001B); + maestro_write(ess, 0x0A, 0x8000); + maestro_write(ess, 0x0B, 0x3F37); + maestro_write(ess, 0x0C, 0x0098); + + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0xF000)|0x8000); + maestro_write(ess, 0x0C, + (maestro_read(ess, 0x0C)&~0x0F00)|0x0500); + + maestro_write(ess, 0x0D, 0x7632); + + /* Wave cache control on - test off, sg off, + enable, enable extra chans 1Mb */ + + outw(inw(0x14+iobase)|(1<<8),0x14+iobase); + outw(inw(0x14+iobase)&0xFE03,0x14+iobase); + outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase); + outw(inw(0x14+iobase)|(1<<7),0x14+iobase); + + outw(0xA1A0, 0x14+iobase); /* 0300 ? */ + + if(maestro_ac97_get(iobase, 0x00)==0x0080) + { + printk(KERN_INFO "ess_pci: PT101 Codec detected\n"); + maestro_pt101_init(iobase); + } + else + { + printk(KERN_INFO "ess_pci: AC97 Codec detected\n"); + maestro_ac97_init(iobase); + } + + /* Now clear the channel data */ + for(apu=0;apu<64;apu++) + { + for(w=0;w<0x0E;w++) + apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0); + } + + + /* Now we program up the APU's */ + + /* + * APU 6 is the mixer + */ + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 3, 0x0000); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)|(1<<5)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 6|ESS_CHAN_HARD, 2, + apu_get_register(ess, 6|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 6|ESS_CHAN_HARD, 4, 0x4B5F); + apu_set_register(ess, 6|ESS_CHAN_HARD, 5, 0xFDD5); + apu_set_register(ess, 6|ESS_CHAN_HARD, 6, 0xFE00); + apu_set_register(ess, 6|ESS_CHAN_HARD, 7, 0x0100); + apu_set_register(ess, 6|ESS_CHAN_HARD, 8, 0x78FF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xA,0x8A10); + apu_set_register(ess, 6|ESS_CHAN_HARD, 0xB,0x8009); + + /* + * APU 62 - Right channel DSP + */ + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 62|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 62|ESS_CHAN_HARD, 2, + apu_get_register(ess, 62|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 62|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 5, 0x8000); + apu_set_register(ess, 62|ESS_CHAN_HARD, 6, 0x8080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 62|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xA,0x7F00); + apu_set_register(ess, 62|ESS_CHAN_HARD, 0xB,0x00F0); + + /* + * APU 63 - Left channel DSP + */ + + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<14)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<13)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&~(1<<12)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFCFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xF3FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 63|ESS_CHAN_HARD, 0)&0xFFF0)|0x0F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0x00FF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 3, 0x1000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFF3F); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<5)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&~(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 2, + apu_get_register(ess, 63|ESS_CHAN_HARD, 2)&0xFFF0); + apu_set_register(ess, 63|ESS_CHAN_HARD, 4, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 5, 0x0000); + apu_set_register(ess, 63|ESS_CHAN_HARD, 6, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 7, 0x0080); + apu_set_register(ess, 63|ESS_CHAN_HARD, 8, 0x7F00); + apu_set_register(ess, 63|ESS_CHAN_HARD, 9, 0xFFFF); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xA,0x7F10); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0xB,0x00F0); + + apu_set_register(ess, 6|ESS_CHAN_HARD, 0, + (apu_get_register(ess, 6|ESS_CHAN_HARD, 0)&0xFF0F)|(9<<4)); + + udelay(30); + + apu_set_register(ess, 62|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + apu_set_register(ess, 63|ESS_CHAN_HARD, 0, + (apu_get_register(ess,6|ESS_CHAN_HARD, 0)&0xFF0F)|(1<<4)); + + + load_tables(iobase); + + udelay(1); + + + if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, name, card)) + { + printk(KERN_ERR "ess_maestro: unable to allocate irq %d,\n", card->irq); + return 0; + } + + ess_play_test(ess); + printk("ess_maestro: %d channels configured.\n", num); + return 1; +} + +#ifdef MODULE + +__initfunc(int init_module(void)) +#else +__initfunc(int init_maestro(void)) +#endif +{ + struct pci_dev *pcidev = NULL; + int index = 0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "maestro: version v0.01 time " __TIME__ " " __DATE__ "\n"); + + pcidev = NULL; + + /* + * Find the ESS Maestro 2. + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2", index); + if(index == NR_DEVICE) + return index; + } + + /* + * Find the ESS Maestro 2E + */ + + while((pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro 2E", index); +// printk(KERN_INFO "ESS Maestro 2E not yet supported.\n"); + if(index == NR_DEVICE) + return index; + } + + /* + * ESS Maestro 1 + */ + + while((pcidev = pci_find_device(0x1285, 0x100, pcidev))!=NULL) + { + index+=maestro_install(pcidev, "ESS Maestro", index); + if(index == NR_DEVICE) + return index; + } + if(index==0) + return -ENODEV; + return 0;; +} + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +MODULE_AUTHOR("Alan Cox "); +MODULE_DESCRIPTION("ESS Maestro Driver"); + +void cleanup_module(void) +{ + struct ess_card *s; + + while ((s = devs)) { + int i; + devs = devs->next; +// ess_play_test(&s->channels[0]); + kill_bob(&s->channels[0]); +// outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ +// synchronize_irq(); +// inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ +// wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + //outb(0, s->iodmaa + SV_DMA_RESET); + //outb(0, s->iodmac + SV_DMA_RESET); + free_irq(s->irq, s); +// unregister_sound_mixer(s->dev_mixer); + for(i=0;i<8;i++) + { + struct ess_state *ess = &s->channels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + kfree(s); + } + printk(KERN_INFO "maestro: unloading\n"); +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro.h linux.ac/drivers/sound/maestro.h --- linux.vanilla/drivers/sound/maestro.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,60 @@ +/* + * Registers for the ESS PCI cards + */ + +/* + * Memory access + */ + +#define ESS_MEM_DATA 0x00 +#define ESS_MEM_INDEX 0x02 + +/* + * AC-97 Codec port. Delay 1uS after each write. This is used to + * talk AC-97 (see intel.com). Write data then register. + */ + +#define ESS_AC97_INDEX 0x30 /* byte wide */ +#define ESS_AC97_DATA 0x32 + +/* + * Reading is a bit different. You write register|0x80 to ubdex + * delay 1uS poll the low bit of index, when it clears read the + * data value. + */ + +/* + * Control port. Not yet fully understood + * The value 0xC090 gets loaded to it then 0x0000 and 0x2800 + * to the data port. Then after 4uS the value 0x300 is written + */ + +#define RING_BUS_CTRL_L 0x34 +#define RING_BUS_CTRL_H 0x36 + +/* + * This is also used during setup. The value 0x17 is written to it + */ + +#define ESS_SETUP_18 0x18 + +/* + * And this one gets 0x000b + */ + +#define ESS_SETUP_A2 0xA2 + +/* + * And this 0x0000 + */ + +#define ESS_SETUP_A4 0xA4 +#define ESS_SETUP_A6 0xA6 + +/* + * Stuff to do with Harpo - the wave stuff + */ + +#define ESS_WAVETABLE_SIZE 0x14 +#define ESS_WAVETABLE_2M 0xA180 + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maestro_tables.h linux.ac/drivers/sound/maestro_tables.h --- linux.vanilla/drivers/sound/maestro_tables.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/maestro_tables.h Fri Jun 4 23:52:44 1999 @@ -0,0 +1,333 @@ +/* + * Set up data block for the ESS soundblaster emulation. This is like + * the example code from ftp.esstech.com.tw (104T31.ZIP) + */ + +u16 asp_block_0[]= { + 0x7980, 0x003a, 0x7980, 0x007d, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, 0xbe3a, 0x8b00, + 0x7980, 0x0be6, 0x7980, 0x0069, 0xbe3a, 0x8b00, 0x8048, 0x6945, + 0xb801, 0x9045, 0x6941, 0xe388, 0x0031, 0x6944, 0xba50, 0xe38c, + 0x0031, 0x8b88, 0x6942, 0x304a, 0xe308, 0x0028, 0x6949, 0x9042, + 0x0042, 0xafa0, 0x8000, 0xafa0, 0x8000, 0x8042, 0x6944, 0xb801, + 0x9044, 0x0048, 0xbe3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xbe41, 0xbf80, 0x0101, 0x8806, 0x8804, 0xb912, + 0x8807, 0xbc26, 0xbe40, 0xb92f, 0x9001, 0x9002, 0x003b, 0x0122, + 0x7a88, 0x0055, 0x003a, 0x013c, 0x7a88, 0x0055, 0x4902, 0xe100, + 0x0800, 0x0c02, 0xa000, 0x7980, 0x004e, 0xb908, 0x8809, 0xbec6, + 0x0067, 0x4a80, 0xe200, 0x0065, 0x4880, 0xe200, 0x0063, 0xb97f, + 0x6e80, 0x7980, 0x0066, 0x1089, 0x9088, 0xb900, 0x90a9, 0x8ba8, + 0xef00, 0x803d, 0x0003, 0x1007, 0x881f, 0x8b88, 0xbb0f, 0xada0, + 0x0810, 0x9003, 0x4903, 0xe200, 0x007b, 0x9002, 0x6a05, 0x6d04, + 0x9803, 0x9804, 0x9005, 0x003d, 0xbe3a, 0xaf06, 0x0000, 0x803d, + 0x8b88, 0x6906, 0x8810, 0xaf06, 0x0001, 0xbfb0, 0x00ff, 0xbaf5, + 0xe3cc, 0x009a, 0x5e06, 0x003f, 0xbf80, 0x0080, 0x4a06, 0xe200, + 0x0095, 0x6e80, 0x6d06, 0x7980, 0x009b, 0x9080, 0x0810, 0xba46, + 0x8810, 0x8b00, 0x1006, 0x9080, 0x003d, 0xbe3a, 0x1024, 0x2009, + 0x8810, 0x8b88, 0x8b00, 0x1089, 0xbfb0, 0x000e, 0xbe0a, 0x880d, + 0x903e, 0x1038, 0x2008, 0x8810, 0x1037, 0x2008, 0x8811, 0x5f3e, + 0x0000, 0x8b00, 0xf500, 0x5e80, 0xfffe, 0x1039, 0x2008, 0x8815, + 0x8b8d, 0x0231, 0x0333, 0x108a, 0x90ad, 0x1025, 0x200a, 0x8815, + 0x0605, 0xb91f, 0x8809, 0x4f16, 0x1080, 0xf600, 0xbfb0, + 0x0003, 0xbfb0, 0x0007, 0x9089, 0xbe47, 0xbe43, 0xbec6, + 0x00f6, 0x4f8b, 0x14a8, 0xe500, 0x6380, 0x8b89, 0x4e8a, + 0xbfe3, 0xe500, 0x2480, 0xbe46, 0x8b9d, 0xbfe7, 0xbfb0, + 0x00ff, 0x288c, 0x2026, 0x8814, 0xbe47, 0x8b00, 0x738f, + 0x54aa, 0xbe03, 0xbe0a, 0x2fa8, 0x988a, 0x8da9, 0xbe03, + 0x4d8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe03, + 0x4c8e, 0xbfe1, 0xf500, 0x6180, 0x9880, 0x8ba9, 0xbe42, + 0x1039, 0x2008, 0x8815, 0x8b8d, 0x8b00, 0x8d8a, 0x7980, + 0x0bcf}; + +u16 asp_block_1[]={ + 0x0005, 0xb900, 0x9008, 0x9009, 0x900a, 0xbb3f, 0x90a0, + 0x001a, 0x011b, 0x021c, 0x0323, 0x1089, 0x9015, 0x108a, + 0x9016, 0x108b, 0x9017, 0x1088, 0x9018, 0x0137, 0x0524, + 0x8b8d, 0x4f16, 0xe200, 0x0827, 0x4f15, 0xe200, 0x0827, + 0x7a80, 0x08e6, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb900, + 0x90a0, 0x908d, 0x7980, 0x0833, 0x7a80, 0x0913, 0x7803, + 0x7a80, 0x0913, 0x102c, 0xb802, 0x8813, 0x8b8b, 0xb903, + 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, 0x0845, 0x4e15, + 0xe200, 0x0845, 0x7a80, 0x08e6, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb901, 0x90a0, 0x908d, 0x7980, 0x0851, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb806, 0x8813, + 0x8b8b, 0xb904, 0x90a0, 0x908d, 0x7c02, 0x4f16, 0xe200, + 0x0863, 0x4d15, 0xe200, 0x0863, 0x7a80, 0x08e6, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb902, 0x90a0, 0x908d, 0x7980, + 0x086f, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, + 0xb80a, 0x8813, 0x8b8b, 0xb905, 0x90a0, 0x908d, 0x7801, + 0x7a80, 0x0913, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x1024, 0xbf90, 0x0100, 0x8815, 0x4f16, 0xe200, + 0x088e, 0x4c15, 0xe200, 0x088e, 0x7a80, 0x08e6, 0x102c, + 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0100, 0x90a0, 0x908d, + 0x7980, 0x089b, 0x7a80, 0x0913, 0x7803, 0x7a80, 0x0913, + 0x102c, 0xb814, 0x8813, 0x8b8b, 0xbf80, 0x0103, 0x90a0, + 0x908d, 0x7c02, 0x4f16, 0xe200, 0x08ae, 0x4b15, 0xe200, + 0x08ae, 0x7a80, 0x08e6, 0x102c, 0xb818, 0x8813, 0x8b8b, + 0xbf80, 0x0101, 0x90a0, 0x908d, 0x7980, 0x08bb, 0x7a80, + 0x0913, 0x7803, 0x7a80, 0x0913, 0x102c, 0xb818, 0x8813, + 0x8b8b, 0xbf80, 0x0104, 0x90a0, 0x908d, 0x7c02, 0x4f16, + 0xe200, 0x08ce, 0x4a15, 0xe200, 0x08ce, 0x7a80, 0x08e6, + 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0102, 0x90a0, + 0x908d, 0x7980, 0x08db, 0x7a80, 0x0913, 0x7803, 0x7a80, + 0x0913, 0x102c, 0xb81c, 0x8813, 0x8b8b, 0xbf80, 0x0105, + 0x90a0, 0x908d, 0x7801, 0x7a80, 0x0913, 0x7801, 0x7a80, + 0x0913, 0x7801, 0x7a80, 0x0913, 0x7980, 0x0920, 0x4f80, + 0x7803, 0xe100, 0x08fe, 0x4f89, 0xe100, 0x08f5, 0xb901, + 0x90a0, 0xb902, 0x90a0, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb901, 0x90a0, 0xb906, 0x90a0, 0xb900, 0x90a0, 0xb906, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x090a, 0xb905, 0x90a0, + 0xb900, 0x90a0, 0xb902, 0x90a0, 0xb906, 0x90ad, 0xef00, + 0xb905, 0x90a0, 0xb900, 0x90a0, 0xb906, 0x90a0, 0xb904, + 0x90ad, 0xef00, 0x4f89, 0xe100, 0x091b, 0xb901, 0x90a0, + 0xb906, 0x90ad, 0xef00, 0xb905, 0x90a0, 0xb904, 0x90ad, + 0xef00, 0xb91f, 0x8809, 0x0034, 0x8b88, 0xbec6, 0x0932, + 0x1313, 0xbe1e, 0x1014, 0xbe1a, 0xbe01, 0xbfe8, 0xbe17, + 0x6a13, 0x6214, 0xbe14, 0x9813, 0x9014, 0x98a0, 0xbe47, + 0x5f0f, 0x002e, 0xe200, 0x093d, 0xbf80, 0xffd2, 0x900f, + 0x7980, 0x0940, 0x100f, 0xb801, 0x900f, 0x400f, 0x8b00, + 0xe500, 0xbe01, 0xbe09, 0x9010, 0xbe46, 0x5f11, 0x003f, + 0xe200, 0x094f, 0xb900, 0x9011, 0x7980, 0x0952, 0x1011, + 0xb801, 0x9011, 0x1001, 0xe388, 0x0bcf, 0x1021, 0x2009, + 0x8813, 0x8b8b, 0x8b00, 0x1080, 0xbfe6, 0x7810, 0x8b00, + 0x8b00, 0x2180, 0xbfb0, 0x0007, 0x4c11, 0x8b00, 0xe100, + 0x096c, 0x4b11, 0x8b00, 0xe600, 0xb900, 0x7980, 0x096d, + 0xbe0a, 0x4a11, 0x8b00, 0xe500, 0xbe01, 0x9012, 0x1037, + 0x2008, 0x8811, 0x102e, 0x2008, 0x8812, 0x4a89, 0xb901, + 0xe500, 0x9019, 0xe100, 0x09c9, 0xb900, 0x9019, 0x4a18, + 0xe200, 0x09c9, 0x5f0a, 0x0010, 0xe200, 0x098d, 0x4b18, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0013, + 0xe200, 0x0997, 0x4b18, 0xb901, 0xe500, 0x9019, 0x7980, + 0x09c9, 0x5f0a, 0x0011, 0xe200, 0x09a4, 0x4f18, 0xb905, + 0xe500, 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, + 0x5f0a, 0x0014, 0xe200, 0x09b1, 0x4c18, 0xb904, 0xe500, + 0x9080, 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, + 0x0012, 0xe200, 0x09be, 0x4d18, 0xb905, 0xe500, 0x9080, + 0xb901, 0xe500, 0x9019, 0x7980, 0x09c9, 0x5f0a, 0x0015, + 0xe200, 0x09c9, 0x4e18, 0xb904, 0xe500, 0x9080, 0xb901, + 0xe500, 0x9019, 0x8b8a, 0x4f19, 0xe200, 0x09d4, 0x4b80, + 0xe200, 0x09d6, 0x5d80, 0x0020, 0x7980, 0x09d9, 0x5d80, + 0x0010, 0x4a80, 0xe200, 0x0bca, 0x1001, 0xba01, 0x9001, + 0x1024, 0x2009, 0x8815, 0x8b89, 0x4d8d, 0xe200, 0x09f8, + 0x4f16, 0xe100, 0x09ed, 0x8b89, 0x1080, 0xbfc0, 0x000c, + 0x908c, 0x7980, 0x09f8, 0x4b89, 0x108d, 0xf600, 0xbfb0, + 0x0003, 0x4a89, 0x8b00, 0xf500, 0xbfc0, 0x0008, 0x908c, + 0x1022, 0x2009, 0x8811, 0x102e, 0x2008, 0x8812, 0x102f, + 0x2008, 0x8813, 0x1020, 0x200a, 0x8814, 0x101d, 0x200a, + 0x8815, 0x8b8a, 0x4f19, 0xe100, 0x0a11, 0x5e80, 0x0020, + 0x5d80, 0x0018, 0x7980, 0x0a3e, 0x4f80, 0xe200, 0x0a1e, + 0x8b8b, 0x108a, 0xbfa0, 0x7fc0, 0x8b00, 0xf704, 0x5c80, + 0x0003, 0x7980, 0x0a3e, 0x4e80, 0xe200, 0x0a36, 0x8b8c, + 0x178b, 0xbe01, 0xbfb7, 0x00f0, 0x308a, 0xe344, 0x0a3e, + 0x8b8d, 0x4a8a, 0x8b00, 0xe200, 0x0a32, 0x5c80, 0x0006, + 0x7980, 0x0a3e, 0x5c80, 0x000a, 0x7980, 0x0a3e, 0x4c80, + 0xe200, 0x0a3e, 0x4b80, 0x8b00, 0xf500, 0x5c80, 0x0019, + 0x4f80, 0xe200, 0x0a4d, 0x101f, 0x200a, 0x8816, 0x8b00, + 0x8b00, 0x8b8e, 0x1780, 0xbfb7, 0x00f0, 0x900b, 0x7980, + 0x0a64, 0x4e80, 0xe200, 0x0a5c, 0x101f, 0x200a, 0x8816, + 0x8b00, 0x8b00, 0x8b8e, 0x1b80, 0xbfbb, 0x000f, 0x900b, + 0x7980, 0x0a64, 0x4c80, 0xe200, 0x0a64, 0x8b8c, 0x1b80, + 0xbfbb, 0x000f, 0x900b, 0x8b89, 0x1880, 0xbfb8, 0x001c, + 0x4917, 0xe100, 0x0a6e, 0x4f80, 0x7980, 0x0a70, 0x4e80, + 0x8b00, 0xf500, 0xbf98, 0x0002, 0x8b8d, 0x4b89, 0x8b00, + 0xe600, 0xbfe1, 0x903e, 0xbe43, 0x6a0b, 0x613e, 0xbfe8, + 0x980c, 0xbe42, 0x7c10, 0x1080, 0xbfe5, 0xbe1e, 0x7810, + 0x1280, 0xbfb2, 0x001f, 0xbe11, 0x2027, 0x8811, 0x101e, + 0x200a, 0x8816, 0x8b00, 0x128e, 0x4980, 0xe100, 0x0a9b, + 0x4880, 0xe100, 0x0a98, 0xb900, 0x7980, 0x0a9f, 0xbe0a, + 0x7980, 0x0a9f, 0x4880, 0xe200, 0x0a9f, 0xbe09, 0xbe1e, + 0x158d, 0xbfb5, 0x003f, 0xbe11, 0x4889, 0xe200, 0x0aae, + 0xbe1e, 0x1010, 0x4818, 0x8b00, 0xe600, 0xbfe1, 0xbe11, + 0xbfe1, 0x8811, 0xbe1e, 0xb9ff, 0x8819, 0x8b00, 0x8b00, + 0xbf46, 0x8b00, 0xe600, 0xbe1f, 0xbe01, 0xbfb0, 0x00ff, + 0x202a, 0x8811, 0x8b00, 0x8b00, 0x108a, 0x900d, 0xb91f, + 0x8809, 0x0732, 0x730d, 0x4f80, 0xe200, 0x0ad8, 0x1028, + 0x200c, 0x8815, 0xbe43, 0x8b8b, 0x6a8d, 0xbec6, 0x0ad4, + 0x618b, 0x9880, 0x548f, 0x8dad, 0xbe42, 0x7980, 0x0b24, + 0x4e80, 0xe200, 0x0af9, 0x8b8c, 0x178b, 0xbe01, 0xbfb7, + 0x00f0, 0x903e, 0x1029, 0x200c, 0x8815, 0x108d, 0xbec6, + 0x0af6, 0x308b, 0xbe1e, 0x303e, 0x903f, 0x403f, 0xbe1f, + 0xe500, 0x103e, 0x9080, 0xbfe6, 0x202a, 0x8811, 0x8b00, + 0x1089, 0x548f, 0x8dad, 0x7980, 0x0b24, 0x4c8b, 0xe200, + 0x0b1b, 0x1029, 0x200c, 0x8815, 0xbf80, 0x007f, 0x903e, + 0x108d, 0xbec6, 0x0b14, 0x308b, 0xbe1e, 0x303e, 0x903f, + 0x403f, 0xbe1f, 0xe500, 0xb900, 0x9080, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x1089, 0x548f, 0x8dad, 0x8b8a, 0xf500, + 0x5e80, 0xffdf, 0x7980, 0x0b24, 0x1089, 0xbfe6, 0x202a, + 0x8811, 0x8b00, 0x8b00, 0x548f, 0xbb1f, 0x8da0, 0x8b8f, + 0x0732, 0x1021, 0x2009, 0x8811, 0x8b89, 0x101d, 0x200a, + 0x8812, 0x1080, 0x7810, 0x8b00, 0xbe47, 0x288a, 0xbfb0, + 0x03ff, 0x4989, 0xe200, 0x0b3e, 0xbe1e, 0x1012, 0x4918, + 0x8b00, 0xe600, 0xbe0a, 0xbe11, 0x900e, 0xbe46, 0x108a, + 0xbfb0, 0x001c, 0xbfe1, 0x880d, 0x8b00, 0x6b0e, 0xbe0a, + 0x880c, 0x108c, 0xbfb0, 0x000f, 0x202d, 0x8814, 0x8b00, + 0x8b00, 0x5589, 0xbf03, 0x8c0e, 0xbf00, 0x1030, 0x2008, + 0x8811, 0xb91f, 0x8809, 0x108b, 0x0333, 0xbec6, 0x0b5f, + 0x200e, 0x90a0, 0x8b00, 0x8b89, 0x9080, 0x4a18, 0xe200, + 0x0b7a, 0x5f0a, 0x0011, 0xe200, 0x0b6c, 0x4f18, 0xe900, + 0x0b7c, 0x5f0a, 0x0014, 0xe200, 0x0b73, 0x4c18, 0xe900, + 0x0b9b, 0x5f0a, 0x0015, 0xe200, 0x0b7a, 0x4e18, 0xe900, + 0x0bb2, 0x7980, 0x009e, 0x0034, 0xb91f, 0x8809, 0x0333, + 0x8b8b, 0xbec6, 0x0b99, 0x1280, 0x6c80, 0xbfea, 0xbe1e, + 0x1580, 0x6c88, 0xbfec, 0xbe13, 0x903e, 0x6cab, 0x903f, + 0x4f3e, 0xb900, 0xf500, 0xbf80, 0x8000, 0x4f3f, 0xbf90, + 0x0d00, 0xf500, 0xbf90, 0x2700, 0x90a0, 0xef00, 0x0034, + 0xb91f, 0x8809, 0x0333, 0x8b88, 0xbec6, 0x0bb0, 0x1eab, + 0x6c80, 0xbfed, 0x903e, 0x4180, 0xb900, 0xf500, 0xbf80, + 0x8000, 0x4f3e, 0x8b00, 0xf500, 0xbf90, 0x4000, 0x90a8, + 0xef00, 0x0034, 0xb91f, 0x8809, 0x0333, 0x8b8b, 0xbec6, + 0x0bc8, 0x1280, 0x6c8b, 0xbfea, 0xbe1e, 0x1580, 0x6c80, + 0xbfec, 0xbe13, 0x903e, 0x4f3e, 0xbf80, 0x4000, 0xf500, + 0xbf90, 0x8000, 0x90a0, 0xef00, 0x0231, 0x8b8a, 0xb900, + 0xbb20, 0x90a0, 0x5f08, 0x0023, 0xe100, 0x0043, 0x1008, + 0xb801, 0x9008, 0x102b, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x900a, 0x102c, 0x2008, 0x8812, 0x8b00, 0x8b00, + 0x1080, 0x9009, 0x7980, 0x0952, 0x8148, 0x6946, 0xb801, + 0x9046, 0xb901, 0x9041, 0x6944, 0xba08, 0xe344, 0x0bfe, + 0x9044, 0x8b89, 0x0143, 0x694b, 0x881f, 0xbb0f, 0xada0, + 0x8143, 0x0811, 0x304a, 0xe308, 0x0bfe, 0x6949, 0x9043, + 0x0148, 0xbe3a +}; + +u16 asp_block_2[]={ + 0x0000, 0x0000, 0x0003, 0x0003, 0x0001, 0x0001, + 0x0004, 0x0004, 0x0002, 0x0002, 0x0005, 0x0005, + 0x0006, 0x0006, 0x0007, 0x0007, 0x0008, 0x0008, + 0x0100, 0x0100, 0x0103, 0x0103, 0x0101, 0x0101, + 0x0104, 0x0104, 0x0102, 0x0102, 0x0105, 0x0105, + 0x0106, 0x0106, 0x0107, 0x0107, 0x0108, 0x0108 +}; + +u16 asp_block_3[]={ + 0x0000, 0x0000, 0x0000, 0x1200, 0x1200, 0x1280, 0x0000, 0x05d0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1104, 0x1105, 0x1008, 0x1020, 0x1040, 0x1060, + 0x1080, 0x10a0, 0x10b0, 0x100d, 0x1010, 0x10e0, 0x2000, 0x2980, + 0x2b00, 0x2b40, 0x2a00, 0x2b90, 0x13dc, 0x2b80, 0x11bc, 0x134c, + 0x1370, 0x12e0, 0x1240, 0x1260, 0x12c0, 0x009e, 0x0045, 0x10bc, + 0x1394, 0x13b8, 0x11f6, 0x10f6, 0x11b0, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0815, 0x0956, 0x09df, 0x0be5, 0x0a19, 0x0a48, 0x0b37, + 0x0b5d, 0x0a8b, 0x0aae, 0x0ad2 }; + + +u16 asp_block_4[] = { + 0x0192, 0x04b6, 0x07d9, 0x0afb, 0x0e1c, 0x113a, 0x1455, 0x176e, + 0x1a83, 0x1d93, 0x209f, 0x23a7, 0x26a8, 0x29a4, 0x2c99, 0x2f87, + 0x326e, 0x354e, 0x3825, 0x3af3, 0x3db8, 0x4074, 0x4326, 0x45cd, + 0x486a, 0x4afb, 0x4d81, 0x4ffb, 0x5269, 0x54ca, 0x571e, 0x5964, + 0x5b9d, 0x5dc8, 0x5fe4, 0x61f1, 0x63ef, 0x65de, 0x67bd, 0x698c, + 0x6b4b, 0x6cf9, 0x6e97, 0x7023, 0x719e, 0x7308, 0x7460, 0x75a6, + 0x76d9, 0x77fb, 0x790a, 0x7a06, 0x7aef, 0x7bc6, 0x7c89, 0x7d3a, + 0x7dd6, 0x7e60, 0x7ed6, 0x7f38, 0x7f87, 0x7fc2, 0x7fea, 0x7ffe, + 0x7ffe, 0x7fea, 0x7fc2, 0x7f87, 0x7f38, 0x7ed6, 0x7e60, 0x7dd6, + 0x7d3a, 0x7c89, 0x7bc6, 0x7aef, 0x7a06, 0x790a, 0x77fb, 0x76d9, + 0x75a6, 0x7460, 0x7308, 0x719e, 0x7023, 0x6e97, 0x6cf9, 0x6b4b, + 0x698c, 0x67bd, 0x65de, 0x63ef, 0x61f1, 0x5fe4, 0x5dc8, 0x5b9d, + 0x5964, 0x571e, 0x54ca, 0x5269, 0x4ffb, 0x4d81, 0x4afb, 0x486a, + 0x45cd, 0x4326, 0x4074, 0x3db8, 0x3af3, 0x3825, 0x354e, 0x326e, + 0x2f87, 0x2c99, 0x29a4, 0x26a8, 0x23a7, 0x209f, 0x1d93, 0x1a83, + 0x176e, 0x1455, 0x113a, 0x0e1c, 0x0afb, 0x07d9, 0x04b6, 0x0192, + 0xfe6f, 0xfb4b, 0xf828, 0xf506, 0xf1e5, 0xeec7, 0xebac, 0xe893, + 0xe57e, 0xe26e, 0xdf62, 0xdc5a, 0xd959, 0xd65d, 0xd368, 0xd07a, + 0xcd93, 0xcab3, 0xc7dc, 0xc50e, 0xc249, 0xbf8d, 0xbcdb, 0xba34, + 0xb797, 0xb506, 0xb280, 0xb006, 0xad98, 0xab37, 0xa8e3, 0xa69d, + 0xa464, 0xa239, 0xa01d, 0x9e10, 0x9c12, 0x9a23, 0x9844, 0x9675, + 0x94b6, 0x9308, 0x916a, 0x8fde, 0x8e63, 0x8cf9, 0x8ba1, 0x8a5b, + 0x8928, 0x8806, 0x86f7, 0x85fb, 0x8512, 0x843b, 0x8378, 0x82c7, + 0x822b, 0x81a1, 0x812b, 0x80c9, 0x807a, 0x803f, 0x8017, 0x8003, + 0x8003, 0x8017, 0x803f, 0x807a, 0x80c9, 0x812b, 0x81a1, 0x822b, + 0x82c7, 0x8378, 0x843b, 0x8512, 0x85fb, 0x86f7, 0x8806, 0x8928, + 0x8a5b, 0x8ba1, 0x8cf9, 0x8e63, 0x8fde, 0x916a, 0x9308, 0x94b6, + 0x9675, 0x9844, 0x9a23, 0x9c12, 0x9e10, 0xa01d, 0xa239, 0xa464, + 0xa69d, 0xa8e3, 0xab37, 0xad98, 0xb006, 0xb280, 0xb506, 0xb797, + 0xba34, 0xbcdb, 0xbf8d, 0xc249, 0xc50e, 0xc7dc, 0xcab3, 0xcd93, + 0xd07a, 0xd368, 0xd65d, 0xd959, 0xdc5a, 0xdf62, 0xe26e, 0xe57e, + 0xe893, 0xebac, 0xeec7, 0xf1e5, 0xf506, 0xf828, 0xfb4b, 0xfe6f, + 0x7cc3, 0x725e, 0x68d5, 0x6017, 0x5813, 0x50b9, 0x49fb, 0x43cd, + 0x3e22, 0x38ef, 0x342b, 0x2fcc, 0x2bc9, 0x281c, 0x24be, 0x21a6, + 0x1ed1, 0x1c37, 0x19d5, 0x17a6, 0x15a5, 0x13ce, 0x121f, 0x1093, + 0x0f28, 0x0ddc, 0x0cab, 0x0b93, 0x0a92, 0x09a7, 0x08cf, 0x080a, + 0x0754, 0x06ae, 0x0615, 0x0589, 0x0509, 0x0494, 0x0428, 0x03c5, + 0x036a, 0x0317, 0x02cb, 0x0285, 0x0245, 0x020a, 0x01d4, 0x01a2, + 0x0175, 0x014b, 0x0125, 0x0102, 0x00e2, 0x00c5, 0x00aa, 0x0091, + 0x007b, 0x0066, 0x0053, 0x0041, 0x0031, 0x0022, 0x0015, 0x0009, + 0xfffe, 0xfff2, 0xffe5, 0xffd7, 0xffc8, 0xffb7, 0xffa5, 0xff91, + 0xff7b, 0xff64, 0xff4a, 0xff2e, 0xff0f, 0xfeee, 0xfec9, 0xfea1, + 0xfe76, 0xfe46, 0xfe13, 0xfdda, 0xfd9d, 0xfd5a, 0xfd11, 0xfcc1, + 0xfc6b, 0xfc0c, 0xfba5, 0xfb34, 0xfab9, 0xfa33, 0xf9a1, 0xf902, + 0xf854, 0xf797, 0xf6c8, 0xf5e7, 0xf4f1, 0xf3e5, 0xf2c1, 0xf183, + 0xf027, 0xeeac, 0xed0f, 0xeb4d, 0xe961, 0xe74a, 0xe501, 0xe284, + 0xdfcd, 0xdcd8, 0xd99d, 0xd618, 0xd242, 0xce12, 0xc982, 0xc487, + 0xbf1a, 0xb92e, 0xb2ba, 0xabaf, 0xa402, 0x9ba3, 0x9282, 0x888d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, 0x0010, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x000a, 0x000e, + 0x0010, 0x0014, 0x0016, 0x0018, 0x001a, 0x001c, 0x001e, 0x0020, + 0x0000, 0x0000, 0x0000, 0x000a, 0x0010, 0x0016, 0x001a, 0x001e, + 0x0020, 0x0024, 0x0026, 0x0028, 0x002a, 0x002c, 0x002e, 0x0030, + 0x0000, 0x0000, 0x0010, 0x001a, 0x0020, 0x0026, 0x002a, 0x002e, + 0x0030, 0x0034, 0x0036, 0x0038, 0x003a, 0x003c, 0x003e, 0x0040, + 0x0000, 0x0010, 0x0020, 0x002a, 0x0030, 0x0036, 0x003a, 0x003e, + 0x0040, 0x0044, 0x0046, 0x0048, 0x004a, 0x004c, 0x004e, 0x0050, + 0x0000, 0x0020, 0x0030, 0x003a, 0x0040, 0x0046, 0x004a, 0x004e, + 0x0050, 0x0054, 0x0056, 0x0058, 0x005a, 0x005c, 0x005e, 0x0060, + 0x0000, 0x0030, 0x0040, 0x004a, 0x0050, 0x0056, 0x005a, 0x005e, + 0x0060, 0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070, + 0x0008, 0x0021, 0x0042, 0x0064, 0x0086, 0x00a8, 0x00cb, 0x00ee, + 0x0111, 0x0135, 0x0158, 0x017d, 0x01a1, 0x01c6, 0x01eb, 0x0211, + 0x0236, 0x025d, 0x0283, 0x02aa, 0x02d1, 0x02f9, 0x0321, 0x0349, + 0x0372, 0x039b, 0x03c4, 0x03ee, 0x0418, 0x0442, 0x046d, 0x0499, + 0x04c4, 0x04f0, 0x051d, 0x054a, 0x0577, 0x05a5, 0x05d3, 0x0601, + 0x0630, 0x0660, 0x0690, 0x06c0, 0x06f1, 0x0722, 0x0753, 0x0785, + 0x07b8, 0x07eb, 0x081e, 0x0852, 0x0886, 0x08bb, 0x08f0, 0x0926, + 0x095c, 0x0993, 0x09ca, 0x0a02, 0x0a3a, 0x0a73, 0x0aac, 0x0ae6, + 0x0b20, 0x0b5b, 0x0b96, 0x0bd2, 0x0c0e, 0x0c4b, 0x0c89, 0x0cc7, + 0x0d05, 0x0d44, 0x0d84, 0x0dc5, 0x0e05, 0x0e47, 0x0e89, 0x0ecc, + 0x0f0f, 0x0f53, 0x0f97, 0x0fdd, 0x1022, 0x1069, 0x10b0, 0x10f7, + 0x1140, 0x1189, 0x11d2, 0x121c, 0x1267, 0x12b3, 0x12ff, 0x134c, + 0x139a, 0x13e8, 0x1438, 0x1487, 0x14d8, 0x1529, 0x157b, 0x15ce, + 0x1621, 0x1676, 0x16cb, 0x1720, 0x1777, 0x17ce, 0x1826, 0x187f, + 0x18d9, 0x1934, 0x198f, 0x19eb, 0x1a48, 0x1aa6, 0x1b05, 0x1b64, + 0x1bc5, 0x1c26, 0x1c88, 0x1ceb, 0x1d4f, 0x1db4, 0x1e1a, 0x1e80, + 0x1ee8, 0x1f51, 0x1fba, 0x2025, 0x2090, 0x20fc, 0x216a, 0x21d8, + 0x2247, 0x22b8, 0x2329, 0x239b, 0x240f, 0x2483, 0x24f9, 0x256f, + 0x25e7, 0x2660, 0x26da, 0x2755, 0x27d1, 0x284e, 0x28cc, 0x294b, + 0x29cc, 0x2a4e, 0x2ad1, 0x2b55, 0x2bda, 0x2c61, 0x2ce8, 0x2d71, + 0x2dfb, 0x2e87, 0x2f13, 0x2fa1, 0x3031, 0x30c1, 0x3153, 0x31e6, + 0x327b, 0x3310, 0x33a8, 0x3440, 0x34da, 0x3575, 0x3612, 0x36b0, + 0x3750, 0x37f1, 0x3893, 0x3937, 0x39dc, 0x3a83, 0x3b2c, 0x3bd6, + 0x3c81, 0x3d2e, 0x3ddd, 0x3e8d, 0x3f3f, 0x3ff2, 0x40a7, 0x415d, + 0x4216, 0x42d0, 0x438b, 0x4448, 0x4507, 0x45c8, 0x468b, 0x474f, + 0x4815, 0x48dd, 0x49a6, 0x4a72, 0x4b3f, 0x4c0e, 0x4cdf, 0x4db2, + 0x4e87, 0x4f5d, 0x5036, 0x5111, 0x51ed, 0x52cc, 0x53ac, 0x548f, + 0x5573, 0x565a, 0x5743, 0x582e, 0x591b, 0x5a0a, 0x5afb, 0x5bef, + 0x5ce4, 0x5ddc, 0x5ed7, 0x5fd3, 0x60d2, 0x61d3, 0x62d6, 0x63dc, + 0x64e4, 0x65ee, 0x66fb, 0x680a, 0x691c, 0x6a30, 0x6b47, 0x6c60, + 0x6d7c, 0x6e9a, 0x6fbb, 0x70de, 0x7204, 0x732d, 0x7459, 0x7587, + 0x76b8, 0x77eb, 0x7922, 0x7a5b, 0x7b97, 0x7cd6, 0x7e18, 0x7f5d, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0002, 0x0002, 0x0003, + 0x0003, 0x0004, 0x0004, 0x0005, 0x0006, 0x0008, 0x0009, 0x000a, + 0x000c, 0x0010, 0x0012, 0x0015, 0x0019, 0x0022, 0x0024, 0x002a, + 0x0031, 0x003e, 0x0049, 0x0055, 0x0062, 0x007c, 0x0092, 0x00a9, + 0x00c4, 0x00fc, 0x0125, 0x0152, 0x0187, 0x01f2, 0x024a, 0x02a4, + 0x030d, 0x03e3, 0x0492, 0x0547, 0x061b, 0x07c7, 0x0923, 0x0a8d, + 0x0c19, 0x0eb3, 0x1228, 0x14c1, 0x17fb, 0x1d17, 0x22f2, 0x2835, + 0x2dd4, 0x3cd0, 0x4cf5, 0x51cc, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0005, 0x0007, 0x0008, 0x000a, + 0x000b, 0x000e, 0x0011, 0x0014, 0x0017, 0x001c, 0x0022, 0x0028, + 0x002e, 0x0039, 0x0045, 0x0050, 0x005c, 0x0073, 0x008a, 0x00a0, + 0x00b9, 0x00e7, 0x0114, 0x0141, 0x0172, 0x01ce, 0x0228, 0x0283, + 0x02e3, 0x039b, 0x0454, 0x0501, 0x05bf, 0x072a, 0x0899, 0x0a18, + 0x0b7e, 0x0e55, 0x10d3, 0x1404, 0x16c3, 0x16c3, 0x16c3, 0x16c3, + 0x0012, 0x0024, 0x0048, 0x006c, 0x0090, 0x00b4, 0x00d8, 0x00fc, + 0x0120, 0x0144, 0x0168, 0x0168, 0x01b0, 0x01b0, 0x021c, 0x021c, + 0x0000, 0x0003, 0x0008, 0x000b, 0x0001, 0x0004, 0x0009, 0x000c, + 0x0002, 0x0005, 0x000a, 0x000d, 0x0010, 0x0013, 0x0011, 0x0014, + 0x0012, 0x0015, 0x0100, 0x0103, 0x0108, 0x010b, 0x0101, 0x0104, + 0x0109, 0x010c, 0x0102, 0x0105, 0x010a, 0x010d, 0x0110, 0x0113, + 0x0111, 0x0114, 0x0112, 0x0115 }; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/maui.c linux.ac/drivers/sound/maui.c --- linux.vanilla/drivers/sound/maui.c Sun Nov 8 15:10:21 1998 +++ linux.ac/drivers/sound/maui.c Sat Jul 3 20:33:06 1999 @@ -15,9 +15,12 @@ * system * * Status: - * Untested + * Andrew J. Kroll Tested 06/01/1999 with: + * * OSWF.MOT File Version: 1.15 + * * OSWF.MOT File Dated: 09/12/94 + * * Older versions will cause problems. */ - + #include #include #include diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/mpu401.c linux.ac/drivers/sound/mpu401.c --- linux.vanilla/drivers/sound/mpu401.c Sun Nov 8 15:08:01 1998 +++ linux.ac/drivers/sound/mpu401.c Mon Jun 14 13:56:17 1999 @@ -437,6 +437,15 @@ devc->m_busy = 0; } +int intchk_mpu401(void *dev_id) +{ + struct mpu_config *devc; + int dev = (int) dev_id; + + devc = &dev_conf[dev]; + return input_avail(devc); +} + void mpuintr(int irq, void *dev_id, struct pt_regs *dummy) { struct mpu_config *devc; @@ -1715,6 +1724,7 @@ EXPORT_SYMBOL(probe_mpu401); EXPORT_SYMBOL(attach_mpu401); EXPORT_SYMBOL(unload_mpu401); +EXPORT_SYMBOL(intchk_mpu401); EXPORT_SYMBOL(mpuintr); #ifdef MODULE diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/opl3sa2.c linux.ac/drivers/sound/opl3sa2.c --- linux.vanilla/drivers/sound/opl3sa2.c Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/opl3sa2.c Sat Jun 12 20:06:07 1999 @@ -467,13 +467,13 @@ } -static int probe_opl3sa2_mss(struct address_info *hw_config) +int probe_opl3sa2_mss(struct address_info *hw_config) { return probe_ms_sound(hw_config); } -static void attach_opl3sa2_mss(struct address_info *hw_config) +void attach_opl3sa2_mss(struct address_info *hw_config) { char mixer_name[64]; @@ -516,7 +516,7 @@ } -static void unload_opl3sa2_mss(struct address_info *hw_config) +void unload_opl3sa2_mss(struct address_info *hw_config) { unload_ms_sound(hw_config); } @@ -592,6 +592,9 @@ { /* Generate a pretty name */ sprintf(chipset_name, "OPL3-SA%c", tag); +#if defined(CONFIG_OPL3SA2_MPU_BASE) && !defined(MODULE) + sound_getconf(SNDCARD_OPL3SA2_MPU)->always_detect = 1; +#endif return 1; } return 0; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/pci_legacy.c linux.ac/drivers/sound/pci_legacy.c --- linux.vanilla/drivers/sound/pci_legacy.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/sound/pci_legacy.c Fri Jun 4 23:52:44 1999 @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb_mixer.h" +#include "sb.h" + +/* + * Legacy initialisation tables + */ + +struct pci_legacy +{ + int vendor; + int device; + char *description; + int (*install)(struct pci_dev *, struct pci_legacy *); + int flags; +}; + +#define MAX_CARDS 8 + +static struct address_info pci_cards[MAX_CARDS]; +static int card_count=0; + +static struct address_info pci_mpu_cards[MAX_CARDS]; +static int mpu_count=0; + +static int find_space(int *array, int len) +{ + int i; + for(i=0;array[i]!=0;i++) + { + if(check_region(array[i],len)==0) + return i; + } + return -1; +} + +static int find_dma(int *array) +{ + int i; + for(i=0;array[i]!= -1;i++) + { + if(request_dma(array[i],"pci_legacy")==0) + { + free_dma(array[i]); + return i; + } + } + return -1; +} + +/* + * Setup the Yamaha cards. For now don't do the MPU401/OPL3 ports. + * Does anyone actually use the glorified doorbell mode on an SB ? + * + * For now we only support PC/PCI. If you don't have a PC/PCI sideband + * connector on your board bad luck - you can write the DDMA support. + */ + +static int ymf_init(struct pci_dev *pci_dev, struct pci_legacy *pl) +{ + u16 r; + int slot; + int dma; + int doorbell; + int mpu; + static int ymf_sb[]={0x220, 0x240, 0x260, 0x280, 0}; + static int ymf_opl3[]={0x3A8,0x3A0, 0x398, 0x388, 0}; + static int ymf_dma[]={1,3,0, -1}; + static int ymf_mpu[]={0x330, 0x300, 0x332, 0x334, 0}; + struct address_info *card; + + if((slot=find_space(ymf_sb, 16))==-1) + { + printk(KERN_WARNING "%s: no free soundblaster addresses.\n", + pl->description); + return 0; + } + if((dma=find_dma(ymf_dma))==-1) + { + printk(KERN_WARNING "%s: no free DMA channels.\n", + pl->description); + return 0; + } + + doorbell = find_space(ymf_opl3, 4); + mpu = find_space(ymf_mpu, 4); + + printk(KERN_INFO "Found a %s. Due to lack of documentation this card will\n", + pl->description); + printk(KERN_INFO "be configured as an 8bit soundblaster.\n"); + switch(pl->flags) + { + case 0: + case 1: + pci_read_config_word(pci_dev, 0x42, &r); + /* Mask the fields we will set */ + r&=~0x783F; + /* Set the I/O */ + r|=(slot<<2); + /* Serialized IRQ crap off */ + r|=(1<<15); + /* Set the OPL3 */ + if(doorbell != -1) + { + printk(KERN_INFO "Enabling OPL3 at 0x%03X.\n", + ymf_opl3[doorbell]); + r|=(3-doorbell); + } + if(mpu != -1) + { + r|=(mpu<<4); + printk(KERN_INFO "Enabling MPU at I/O 0x%03X.\n", + ymf_mpu[mpu]); + } + pci_write_config_word(pci_dev, 0x42, r); + pci_read_config_word(pci_dev, 0x40, &r); + /* Set DMA */ + r&=~0x00C0; + r|=(ymf_dma[dma])<<6; + /* SB port only */ + r&=~0xF; + r|=1; + if(doorbell != -1) + r|=2; + if(mpu != -1) + r|=24; + /* SIRQ off, I/O on */ + r&=~(1<<14); + r&=~(1<<15); + pci_write_config_word(pci_dev, 0x40, r); + + + pci_read_config_word(pci_dev, 0x4C, &r); + r&=~1; + pci_write_config_word(pci_dev, 0x4C, r); + + pci_read_config_word(pci_dev, 0x48, &r); + r=1; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + udelay(2000); + r=0; + pci_write_config_word(pci_dev, 0x48, r); + + + pci_read_config_word(pci_dev, 0x48, &r); + r=3; + udelay(2000); + pci_write_config_word(pci_dev, 0x48, r); + + printk(KERN_INFO "%s: set to I/O 0x%03X DMA %d.\n", + pl->description, + ymf_sb[slot], ymf_dma[dma]); + break; + } + + card=&pci_cards[card_count]; + + card->dma = ymf_dma[dma]; + card->irq = pci_dev->irq; + card->io_base = ymf_sb[slot]; + card->dma2 = -1; + + if(sb_dsp_detect(card, SB_PCI_YAMAHA, 0)==-1) + { + printk(KERN_WARNING "pci_legacy: Sound blaster emulation not responding.\n"); + return 0; + } + + attach_sb_card(card); + + if(mpu != -1) + { + card=&pci_mpu_cards[mpu_count]; + card->dma = -1; + card->irq = -1; + card->io_base = ymf_mpu[mpu]; + card->dma2 = -1; + if(probe_sbmpu(card)) + { + attach_sbmpu(card); + mpu_count++; + } + else + printk(KERN_WARNING "pci_legacy: MPU401 emulation not responding.\n"); + + } + + card_count++; + return 1; +} + +/* + * Important; Put the less flexible cards first so that they get + * the SB emulation slots they need. + */ + +struct pci_legacy pci_legacy_table[]={ + { 0x1073, 0x0003, "Yamaha YFM-740C", ymf_init, 0 }, + { 0x1073, 0x000D, "Yamaha YFM-724F", ymf_init, 1 }, + { 0x1073, 0x0004, "Yamaha YFM-724", ymf_init, 1 }, + { 0, 0, NULL, 0, 0} +}; + + +int init_legacy_pci(void) +{ + struct pci_dev *pcidev=NULL; + int count=0; + struct pci_legacy *pt=&pci_legacy_table[0]; + + if(!pci_present()) + return -ENODEV; + + while(pt->vendor) + { + pcidev = NULL; + + printk("Scan for %04X %04X\n", + pt->vendor, pt->device); + while((pcidev = pci_find_device(pt->vendor, pt->device, pcidev))!=NULL) + { + printk("Trying to init %04X %04X\n", + pt->vendor, pt->device); + count+=pt->install(pcidev, pt); + if(count >= MAX_CARDS) + return 0; + } + pt++; + } + + if(count==0) + return -ENODEV; + + printk(KERN_INFO "pci_legacy: %d unsupported PCI card%s placed in legacy 8bit mode.\n", + card_count, + card_count==1?"s":""); + return 0; +} + + +int init_module(void) +{ + if(init_legacy_pci()<0) + { + printk(KERN_ERR "No supported devices found.\n"); + return -ENODEV; + } + return 0; +} + +void cleanup_module(void) +{ + int i; + for(i=0;iirq, devc->midi_irq_cookie, NULL); + if(devc->midi_irq_cookie) + uart401intr(devc->irq, devc->midi_irq_cookie, NULL); #endif if (!(src & 3)) @@ -1191,8 +1192,12 @@ void attach_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + hw_config->slots[4] = -1; attach_uart401(hw_config); - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + if(hw_config->slots[4] != -1) + last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + else + last_sb->midi_irq_cookie=NULL; #endif } diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_ess.c linux.ac/drivers/sound/sb_ess.c --- linux.vanilla/drivers/sound/sb_ess.c Thu May 27 22:11:56 1999 +++ linux.ac/drivers/sound/sb_ess.c Thu Jul 8 00:35:56 1999 @@ -40,6 +40,10 @@ * recording problems for high samplerates. I * fixed this by removing ess_calc_best_speed () * and just doing what the documentation says. + * Andy Sloane (June 4 1999): Stole some code from ALSA to fix the playback + * andy@guildsoftware.com speed on ES1869, ES1879, ES1887, and ES1888. + * 1879's were previously ignored by this driver; + * added (untested) support for those. * * This files contains ESS chip specifics. It's based on the existing ESS * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This @@ -190,15 +194,23 @@ #define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */ #define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */ -int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */ +int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */ #define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */ #define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */ #define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */ #define SUBMDL_ES1878 0x13 /* Subtype ES1878 for specific handling */ +#define SUBMDL_ES1879 0x16 /* ES1879 was initially forgotten */ #define SUBMDL_ES1887 0x14 /* Subtype ES1887 for specific handling */ #define SUBMDL_ES1888 0x15 /* Subtype ES1888 for specific handling */ +#define SB_CAP_ES18XX_RATE 0x100 + +#define ES1688_CLOCK1 795444 /* 128 - div */ +#define ES1688_CLOCK2 397722 /* 256 - div */ +#define ES18XX_CLOCK1 793800 /* 128 - div */ +#define ES18XX_CLOCK2 768000 /* 256 - div */ + #ifdef FKS_LOGGING static void ess_show_mixerregs (sb_devc *devc); #endif @@ -323,7 +335,6 @@ return retval; } -#ifdef OBSOLETE static int ess_calc_best_speed (int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp) { @@ -347,7 +358,6 @@ return retval; } -#endif /* * Depending on the audiochannel ESS devices can @@ -366,11 +376,14 @@ * The 0x80 is important for the first audio channel */ div = 0x80 | ess_calc_div (795500, 128, speedp, &diff); + } else if(devc->caps & SB_CAP_ES18XX_RATE) { + ess_calc_best_speed(ES18XX_CLOCK1, 128, ES18XX_CLOCK2, 256, + &div, speedp); } else { if (*speedp > 22000) { - div = 0x80 | ess_calc_div (795500, 256, speedp, &diff); + div = 0x80 | ess_calc_div (ES1688_CLOCK1, 256, speedp, &diff); } else { - div = 0x00 | ess_calc_div (397700, 128, speedp, &diff); + div = 0x00 | ess_calc_div (ES1688_CLOCK2, 128, speedp, &diff); } } *divp = div; @@ -1070,6 +1083,12 @@ case 1788: submodel = SUBMDL_ES1788; break; + case 1878: + submodel = SUBMDL_ES1878; + break; + case 1879: + submodel = SUBMDL_ES1879; + break; case 1887: submodel = SUBMDL_ES1887; break; @@ -1117,6 +1136,10 @@ chip = "ES1878"; devc->submodel = SUBMDL_ES1878; break; + case 0x1879: + chip = "ES1879"; + devc->submodel = SUBMDL_ES1879; + break; default: if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) { printk ("ess_init: Unrecognized %04x\n", type); @@ -1173,6 +1196,17 @@ sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f); } else { strcpy(name, "Jazz16"); + } + + /* AAS: info stolen from ALSA: these boards have different clocks */ + switch(devc->submodel) { +/* APPARENTLY NOT 1869 + case SUBMDL_ES1869: +*/ + case SUBMDL_ES1887: + case SUBMDL_ES1888: + devc->caps |= SB_CAP_ES18XX_RATE; + break; } hw_config->name = name; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_mixer.c linux.ac/drivers/sound/sb_mixer.c --- linux.vanilla/drivers/sound/sb_mixer.c Fri Apr 16 22:10:57 1999 +++ linux.ac/drivers/sound/sb_mixer.c Wed Jun 9 20:07:30 1999 @@ -13,6 +13,7 @@ * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch] + * Stanislav Voronyi : Support for AWE 3DSE device (Jun 7 1999) */ #include @@ -550,14 +551,37 @@ int val, ret; /* - * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). + * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1) + * or mode==2 put 3DSE state to mode. */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) - { - if (get_user(val, (int *)arg)) - return -EFAULT; - sb_setmixer(devc, 0x43, (~val) & 0x01); - return 0; + if (devc->model == MDL_SB16) { + if (cmd == SOUND_MIXER_AGC) + { + if (get_user(val, (int *)arg)) + return -EFAULT; + sb_setmixer(devc, 0x43, (~val) & 0x01); + return 0; + } + if (cmd == SOUND_MIXER_3DSE) + { + /* I put here 15, but I don't know the exact version. + At least my 4.13 havn't 3DSE, 4.16 has it. */ + if (devc->minor < 15) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val == 0 || val == 1) + sb_chgmixer(devc, AWE_3DSE, 0x01, val); + else if (val == 2) + { + ret = sb_getmixer(devc, AWE_3DSE)&0x01; + return put_user(ret, (int *)arg); + } + else + return -EINVAL; + return 0; + } } if (((cmd >> 8) & 0xff) == 'M') { diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sb_mixer.h linux.ac/drivers/sound/sb_mixer.h --- linux.vanilla/drivers/sound/sb_mixer.h Sat Jan 9 21:50:45 1999 +++ linux.ac/drivers/sound/sb_mixer.h Wed Jun 9 20:07:30 1999 @@ -78,6 +78,11 @@ #define RIGHT_CHN 1 /* + * 3DSE register of AWE32/64 + */ +#define AWE_3DSE 0x90 + +/* * Mixer registers of ALS007 */ #define ALS007_RECORD_SRC 0x6c diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sgalaxy.c linux.ac/drivers/sound/sgalaxy.c --- linux.vanilla/drivers/sound/sgalaxy.c Fri Nov 13 01:37:15 1998 +++ linux.ac/drivers/sound/sgalaxy.c Sat Jun 12 20:00:29 1999 @@ -2,7 +2,7 @@ * sound/sgalaxy.c * * Low level driver for Aztech Sound Galaxy cards. - * Copyright 1998 Artur Skawina + * Copyright 1998 Artur Skawina * * Supported cards: * Aztech Sound Galaxy Waverider Pro 32 - 3D diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sonicvibes.c linux.ac/drivers/sound/sonicvibes.c --- linux.vanilla/drivers/sound/sonicvibes.c Fri Apr 16 22:10:57 1999 +++ linux.ac/drivers/sound/sonicvibes.c Mon Jul 19 03:56:19 1999 @@ -68,6 +68,9 @@ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; * Alpha fixes reported by Peter Jones * Note: dmaio hack might still be wrong on archs other than i386 + * 15.06.99 0.15 Fix bad allocation bug. + * Thanks to Deti Fliegl + * 28.06.99 0.16 Add pci_set_master * */ @@ -699,8 +702,9 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--) - db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order); + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) + break; if (!db->rawbuf) return -ENOMEM; db->buforder = order; @@ -2321,7 +2325,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.14 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); @@ -2447,6 +2451,7 @@ goto err_dev3; if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) goto err_dev4; + pci_set_master(pcidev); /* enable bus mastering */ /* initialize the chips */ fs = get_fs(); set_fs(KERNEL_DS); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sound_calls.h linux.ac/drivers/sound/sound_calls.h --- linux.vanilla/drivers/sound/sound_calls.h Wed Jan 6 23:02:26 1999 +++ linux.ac/drivers/sound/sound_calls.h Mon Jun 14 13:56:17 1999 @@ -157,6 +157,7 @@ /* From mpu401.c */ void attach_mpu401(struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +int intchk_mpu401(void *dev_id); void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); /* From uart6850.c */ @@ -256,21 +257,39 @@ void unload_trix_mpu(struct address_info *hw_info); void unload_cs4232(struct address_info *hw_info); void unload_cs4232_mpu(struct address_info *hw_info); +void unload_opl3sa_wss(struct address_info *hw_info); +void unload_opl3sa_sb(struct address_info *hw_info); +void unload_opl3sa_mpu(struct address_info *hw_info); void unload_opl3sa2(struct address_info *hw_info); void unload_opl3sa2_mpu(struct address_info *hw_info); +void unload_opl3sa2_mss(struct address_info *hw_info); +void unload_softsyn (struct address_info *hw_config); -/* From cs4232.c */ - +/* From cs4232.c */ int probe_cs4232 (struct address_info *hw_config); void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); -/* From opl3sa2.c */ +/* From opl3sa.c */ +void attach_opl3sa_wss (struct address_info *hw_config); +int probe_opl3sa_wss (struct address_info *hw_config); +void attach_opl3sa_sb (struct address_info *hw_config); +int probe_opl3sa_sb (struct address_info *hw_config); +void attach_opl3sa_mpu (struct address_info *hw_config); +int probe_opl3sa_mpu (struct address_info *hw_config); + +/* From opl3sa2.c */ int probe_opl3sa2 (struct address_info *hw_config); void attach_opl3sa2 (struct address_info *hw_config); int probe_opl3sa2_mpu (struct address_info *hw_config); void attach_opl3sa2_mpu (struct address_info *hw_config); +int probe_opl3sa2_mss (struct address_info *hw_config); +void attach_opl3sa2_mss (struct address_info *hw_config); + +/* From softoss.c */ +void attach_softsyn_card (struct address_info *hw_config); +int probe_softsyn (struct address_info *hw_config); /* From maui.c */ void attach_maui(struct address_info * hw_config); @@ -291,12 +310,12 @@ int probe_waveartist(struct address_info *hw_config); void unload_waveartist(struct address_info *hw_config); -/* From wavefront.c */ +/* From wavefront.c */ void attach_wavefront (struct address_info *hw_config); int probe_wavefront (struct address_info *hw_config); void unload_wavefront (struct address_info *hw_config); -/* From wf_midi.c */ +/* From wf_midi.c */ void attach_wf_mpu(struct address_info * hw_config); int probe_wf_mpu(struct address_info *hw_config); void unload_wf_mpu(struct address_info *hw_config); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/sound_syms.c linux.ac/drivers/sound/sound_syms.c --- linux.vanilla/drivers/sound/sound_syms.c Wed Jan 6 23:02:26 1999 +++ linux.ac/drivers/sound/sound_syms.c Sat Jul 3 20:33:06 1999 @@ -3,6 +3,9 @@ * modulespace. * * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL + * + * Thu May 27 1999 Andrew J. Kroll + * left out exported symbol... fixed */ #include @@ -43,6 +46,7 @@ EXPORT_SYMBOL(load_mixer_volumes); +EXPORT_SYMBOL(trace_init); /* oops! this is needed for maui.c -- AJK */ EXPORT_SYMBOL(conf_printf); EXPORT_SYMBOL(conf_printf2); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/trix.c linux.ac/drivers/sound/trix.c --- linux.vanilla/drivers/sound/trix.c Wed Mar 10 21:13:08 1999 +++ linux.ac/drivers/sound/trix.c Tue Jun 22 19:50:28 1999 @@ -42,6 +42,12 @@ static int mpu = 0; +#ifdef TRIX_JOYSTICK +static int joystick=1; +#else +static int joystick=0; +#endif + static unsigned char trix_read(int addr) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ @@ -196,9 +202,8 @@ if (ret) { -#ifdef TRIX_ENABLE_JOYSTICK - trix_write(0x15, 0x80); -#endif + if(joystick==1) + trix_write(0x15, 0x80); request_region(0x390, 2, "AudioTrix"); } return ret; @@ -477,7 +482,7 @@ MODULE_PARM(sb_irq,"i"); MODULE_PARM(mpu_io,"i"); MODULE_PARM(mpu_irq,"i"); - +MODULE_PARM(joystick, "i"); struct address_info config; struct address_info sb_config; struct address_info mpu_config; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/sound/waveartist.c linux.ac/drivers/sound/waveartist.c --- linux.vanilla/drivers/sound/waveartist.c Sat Jan 9 21:50:46 1999 +++ linux.ac/drivers/sound/waveartist.c Fri Jun 4 23:52:44 1999 @@ -5,6 +5,7 @@ * codec chip used in the Corel Computer NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) + * Tweaked for X86 by Alan Cox */ /* @@ -40,12 +41,19 @@ #include #include +#ifdef CONFIG_ARCH_NETWINDER #include +#define IS_VNC +#endif #include "soundmodule.h" #include "sound_config.h" #include "waveartist.h" +#ifndef NO_DMA +#define NO_DMA 255 +#endif + #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec #define MIXER_PRIVATE3_RESET 0x53570000 @@ -203,7 +211,7 @@ } while (timeout--); if (timeout == 0) { - printk("WaveArtist: reset timeout "); + printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); @@ -222,7 +230,7 @@ unsigned int i; if (debug_flg & DEBUG_CMD) { - printk("waveartist_cmd: cmd="); + printk(KERN_DEBUG "waveartist_cmd: cmd="); for (i = 0; i < nr_cmd; i++) printk("%04X ", cmd[i]); @@ -239,7 +247,7 @@ old_data = inw(io_base + CMDR); if (debug_flg & DEBUG_CMD) - printk("flushed %04X...", old_data); + printk(KERN_DEBUG "flushed %04X...", old_data); udelay(10); } @@ -272,14 +280,14 @@ if (debug_flg & DEBUG_CMD) { if (!timed_out) { - printk("waveartist_cmd: resp="); + printk(KERN_DEBUG "waveartist_cmd: resp="); for (i = 0; i < nr_resp; i++) printk("%04X ", resp[i]); printk("\n"); } else - printk("waveartist_cmd: timed out\n"); + printk(KERN_WARNING "waveartist_cmd: timed out\n"); } return timed_out ? 1 : 0; @@ -317,7 +325,7 @@ int count; if (debug_flg & DEBUG_CMD) - printk("waveartist_sendcmd: cmd=0x%04X...", cmd); + printk(KERN_DEBUG "waveartist_sendcmd: cmd=0x%04X...", cmd); udelay(10); @@ -330,7 +338,7 @@ udelay(10); if (debug_flg & DEBUG_CMD) - printk(" flushed %04X...", count); + printk(KERN_DEBUG " flushed %04X...", count); } /* @@ -350,7 +358,7 @@ /* ready BEFORE timeout? */ if (debug_flg & DEBUG_CMD) - printk(" %s\n", count ? "Done OK." : "Error!"); + printk(KERN_DEBUG " %s\n", count ? "Done OK." : "Error!"); udelay(10); @@ -455,7 +463,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_OUT) - printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: output block, buf=0x%lx, count=0x%x...\n", buf, count); /* * 16 bit data @@ -501,7 +509,7 @@ unsigned int count = __count; if (debug_flg & DEBUG_IN) - printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", + printk(KERN_DEBUG "waveartist: start input, buf=0x%lx, count=0x%x...\n", buf, count); if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ @@ -604,26 +612,26 @@ cli(); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) - printk("waveartist: error setting record to %d channels\n", + printk(KERN_WARNING "waveartist: error setting record to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) - printk("waveartist: error setting the record speed " + printk(KERN_WARNING "waveartist: error setting the record speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) - printk("waveartist: error setting the record data path " + printk(KERN_WARNING "waveartist: error setting the record data path " "to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) - printk("waveartist: error setting the record format to %d\n", + printk(KERN_WARNING "waveartist: error setting the record format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -631,9 +639,9 @@ waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -658,19 +666,19 @@ if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) - printk("waveartist: error setting the playback speed " + printk(KERN_WARNING "waveartist: error setting the playback speed " "to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) - printk("waveartist: error setting the playback to" + printk(KERN_WARNING "waveartist: error setting the playback to" " %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) - printk("waveartist: error setting the playback data path " + printk(KERN_WARNING "waveartist: error setting the playback data path " "to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) - printk("waveartist: error setting the playback format to %d\n", + printk(KERN_WARNING "waveartist: error setting the playback format to %d\n", portc->audio_format); devc->xfer_count = 0; @@ -678,9 +686,9 @@ waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { - printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); - printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); - printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); + printk(KERN_DEBUG "WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); + printk(KERN_DEBUG "WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); + printk(KERN_DEBUG "WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; @@ -775,7 +783,7 @@ unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { - printk("wavnc: audio trigger "); + printk(KERN_DEBUG "wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) @@ -883,15 +891,14 @@ status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) - printk("waveartist_intr: stat=%02x, irqstat=%02x\n", + printk(KERN_DEBUG "waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else - printk("waveartist: unexpected interrupt\n"); + printk(KERN_WARNING "waveartist: unexpected interrupt\n"); -#ifdef CONFIG_AUDIO if (irqstatus & 0x01) { int temp = 1; @@ -906,12 +913,11 @@ temp = 0; } if (temp) //default: - printk("WaveArtist: Unknown interrupt\n"); + printk(KERN_WARNING "WaveArtist: Unknown interrupt\n"); } -#endif if (irqstatus & 0x2) // We do not use SB mode natively... - printk("WaveArtist: Unexpected SB interrupt...\n"); + printk(KERN_WARNING "WaveArtist: Unexpected SB interrupt...\n"); } /* ------------------------------------------------------------------------- @@ -1032,7 +1038,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); vals[1] &= ~0x03F; //kill current left/right mux input select @@ -1106,7 +1112,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, + printk(KERN_DEBUG "RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); #else @@ -1127,7 +1133,7 @@ waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) - printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", + printk(KERN_DEBUG "RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1], vals[2]); /* @@ -1197,7 +1203,7 @@ } if (debug_flg & DEBUG_MIXER) - printk("RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", + printk(KERN_DEBUG "RECSRC %d: left(4) 0x%04X, right(8) 0x%04X.\n", level, vals[1], vals[2]); #endif /* @@ -1220,7 +1226,7 @@ right = (level & 0x7f00) >> 8; if (debug_flg & DEBUG_MIXER) - printk("wa_mixer_set(dev=%d, level=%X)\n", + printk(KERN_DEBUG "wa_mixer_set(dev=%d, level=%X)\n", whichDev, level); switch (whichDev) { @@ -1321,7 +1327,7 @@ int i; if (debug_flg & DEBUG_MIXER) - printk("%s: mixer_reset\n", devc->hw.name); + printk(KERN_DEBUG "%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd @@ -1615,20 +1621,20 @@ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { - printk("%s: IRQ %d in use\n", + printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { - printk("%s: Can't allocate DMA%d\n", + printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { - printk("%s: can't allocate DMA%d\n", + printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } @@ -1660,6 +1666,14 @@ return -1; } +#ifndef IS_VNC + +static void vnc_mute(wavnc_info *devc, int mute) +{ +} + +#else + /* * Corel Netwinder specifics... */ @@ -1793,31 +1807,34 @@ mod_timer(&vnc_timer, jiffies + next_timeout); } +#endif + int probe_waveartist(struct address_info *hw_config) { wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { - printk("waveartist: too many audio devices\n"); + printk(KERN_ERR "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { - printk("WaveArtist: I/O port conflict\n"); + printk(KERN_ERR "WaveArtist: I/O port conflict\n"); return 0; } +#ifdef IS_NW if (hw_config->irq > 31 || hw_config->irq < 16) { - printk("WaveArtist: Bad IRQ %d\n", hw_config->irq); + printk(KERN_ERR "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { - printk("WaveArtist: Bad DMA %d\n", hw_config->dma); + printk(KERN_ERR "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } - +#endif hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; @@ -1854,12 +1871,13 @@ if (devc->dev_no < 0) release_region(hw->io_base, 15); else { +#ifdef IS_VNC init_timer(&vnc_timer); vnc_timer.function = vnc_slider_tick; vnc_timer.expires = jiffies; vnc_timer.data = nr_waveartist_devs; add_timer(&vnc_timer); - +#endif nr_waveartist_devs += 1; vnc_mute(devc, 0); @@ -1909,7 +1927,7 @@ for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else - printk("waveartist: can't find device to unload\n"); + printk(KERN_ERR "waveartist: can't find device to unload\n"); } #ifdef MODULE @@ -1919,10 +1937,10 @@ MODULE_PARM(dma, "i"); /* DMA */ MODULE_PARM(dma2, "i"); /* DMA2 */ -int io = CONFIG_WAVEARTIST_BASE; -int irq = CONFIG_WAVEARTIST_IRQ; -int dma = CONFIG_WAVEARTIST_DMA; -int dma2 = CONFIG_WAVEARTIST_DMA2; +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = NO_DMA; static int attached; @@ -1930,6 +1948,11 @@ int init_module(void) { + if(io == -1 || irq == -1 || dma == -1) + { + printk(KERN_ERR "waveartist:io, irq and dma are mandatory.\n"); + return -EINVAL; + } hw_config.io_base = io; hw_config.irq = irq; hw_config.dma = dma; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/tc/Makefile linux.ac/drivers/tc/Makefile --- linux.vanilla/drivers/tc/Makefile Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/tc/Makefile Tue Jun 22 01:35:01 1999 @@ -0,0 +1,33 @@ +# +# Makefile for the linux 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). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +SUB_DIRS := +MOD_SUB_DIRS := +ALL_SUB_DIRS := + +L_TARGET := tc.a +L_OBJS := tc.o + +# Nasty trick as nobody references tcsyms.o, but we still want it linked. +# Stolen from pci Makefile +ifeq ($(CONFIG_MODULES),y) +O_TARGET = tc_syms.o +OX_OBJS = tcsyms.o +O_OBJS = tc.o +L_OBJS := tc_syms.o +else +L_OBJS := tc.o +endif + +ifdef CONFIG_ZS +L_OBJS += zs.o +endif + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/tc/tc.c linux.ac/drivers/tc/tc.c --- linux.vanilla/drivers/tc/tc.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/tc/tc.c Tue Jun 22 01:35:01 1999 @@ -0,0 +1,236 @@ +/* $Id: $ + * tc-init: We assume the TURBOchannel to be up and running so + * just probe for Modules and fill in the global data structure + * tc_bus. + * + * 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) Harald Koerfgen, 1998 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TC_DEBUG + +slot_info tc_bus[MAX_SLOT]; +static int max_tcslot = 0; +static tcinfo *info = (tcinfo *)0; + +unsigned long system_base = 0; + +extern void (*dbe_board_handler)(struct pt_regs *regs); +extern unsigned long *(*rex_slot_address)(int); +extern void *(*rex_gettcinfo)(void); + +/* + * Interface to the world. Read comment in include/asm-mips/tc.h. + */ + +int search_tc_card(char *name) +{ + int slot; + slot_info *sip; + + for (slot = 0; slot <= max_tcslot; slot++) { + sip = &tc_bus[slot]; + if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) { + return slot; + } + } + + return -ENODEV; +} + +void claim_tc_card(int slot) +{ + if (tc_bus[slot].flags & IN_USE) { + printk("claim_tc_card: attempting to claim a card already in use\n"); + return; + } + tc_bus[slot].flags &= ~FREE; + tc_bus[slot].flags |= IN_USE; +} + +void release_tc_card(int slot) +{ + if (tc_bus[slot].flags & FREE) { + printk("release_tc_card: attempting to release a card already free\n"); + return; + } + tc_bus[slot].flags &= ~IN_USE; + tc_bus[slot].flags |= FREE; +} + +unsigned long get_tc_base_addr(int slot) +{ + return tc_bus[slot].base_addr; +} + +unsigned long get_tc_irq_nr(int slot) +{ + return tc_bus[slot].interrupt; +} + +unsigned long get_tc_speed(void) +{ + return 100000 * (10000 / (unsigned long)info->clk_period); +} + +/* + * Probing for TURBOchannel modules + */ +__initfunc(static void my_dbe_handler(struct pt_regs *regs)) +{ + regs->cp0_epc += 4; +} + +__initfunc(static void tc_probe(unsigned long startaddr, unsigned long size, int max_slot)) +{ + int i, slot; + long offset; + unsigned char *module; + void (*old_be_handler)(struct pt_regs *regs); + + /* Install our exception handler temporarily */ + + old_be_handler = dbe_board_handler; + dbe_board_handler = my_dbe_handler; + for (slot = 0; slot <= max_slot; slot++) { + module = (char *)(startaddr + slot * size); + offset = -1; + if (module[OLDCARD + PATTERN0] == 0x55 && module[OLDCARD + PATTERN1] == 0x00 + && module[OLDCARD + PATTERN2] == 0xaa && module[OLDCARD + PATTERN3] == 0xff) + offset = OLDCARD; + if (module[PATTERN0] == 0x55 && module[PATTERN1] == 0x00 + && module[PATTERN2] == 0xaa && module[PATTERN3] == 0xff) + offset = 0; + + if (offset != -1) { + tc_bus[slot].base_addr = (unsigned long)module; + for(i = 0; i < 8; i++) { + tc_bus[slot].firmware[i] = module[FIRM_VER + offset + 4 * i]; + tc_bus[slot].vendor[i] = module[VENDOR + offset + 4 * i]; + tc_bus[slot].name[i] = module[MODULE + offset + 4 * i]; + } + tc_bus[slot].firmware[8] = 0; + tc_bus[slot].vendor[8] = 0; + tc_bus[slot].name[8] = 0; + /* + * Looks unneccesary, but we may change + * TC? in the future + */ + switch (slot) { + case 0: + tc_bus[slot].interrupt = TC0; + break; + case 1: + tc_bus[slot].interrupt = TC1; + break; + case 2: + tc_bus[slot].interrupt = TC2; + break; + /* + * Yuck! DS5000/200 onboard devices + */ + case 5: + tc_bus[slot].interrupt = SCSI_INT; + break; + case 6: + tc_bus[slot].interrupt = ETHER; + break; + default: + tc_bus[slot].interrupt = -1; + break; + } + } + } + + dbe_board_handler = old_be_handler; +} + +/* + * the main entry + */ +__initfunc(void tc_init(void)) +{ + int tc_clock; + int i; + unsigned long slot0addr; + unsigned long slot_size; + + if (!TURBOCHANNEL) + return; + + for (i = 0; i < MAX_SLOT; i++) { + tc_bus[i].base_addr = 0; + tc_bus[i].name[0] = 0; + tc_bus[i].vendor[0] = 0; + tc_bus[i].firmware[0] = 0; + tc_bus[i].interrupt = -1; + tc_bus[i].flags = FREE; + } + + info = (tcinfo *) rex_gettcinfo(); + slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0)); + + switch (mips_machtype) { + case MACH_DS5000_200: + max_tcslot = 6; + break; + case MACH_DS5000_1XX: + case MACH_DS5000_2X0: + max_tcslot = 2; + break; + case MACH_DS5000_XX: + default: + max_tcslot = 1; + break; + } + + tc_clock = 10000 / info->clk_period; + + if (TURBOCHANNEL && info->slot_size && slot0addr) { + printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision, + tc_clock / 10, tc_clock % 10); + printk("(%sparity)\n", info->parity ? "" : "no "); + + slot_size = info->slot_size << 20; + + tc_probe(slot0addr, slot_size, max_tcslot); + + /* + * All TURBOchannel DECstations have the onboard devices + * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module + * would be. + */ + if(mips_machtype == MACH_DS5000_XX) + i = 2; + else + i = 1; + + system_base = slot0addr + slot_size * (max_tcslot + i); + +#ifdef TC_DEBUG + for (i = 0; i <= max_tcslot; i++) + if (tc_bus[i].base_addr) { + printk(" slot %d: ", i); + printk("%s %s %s\n", tc_bus[i].vendor, + tc_bus[i].name, tc_bus[i].firmware); + } +#endif + } + +} diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/tc/tcsyms.c linux.ac/drivers/tc/tcsyms.c --- linux.vanilla/drivers/tc/tcsyms.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/tc/tcsyms.c Mon Jul 19 03:45:44 1999 @@ -0,0 +1,13 @@ +/* + * Turbo Channel Services -- Exported Symbols + * + */ + +#include +#include + +EXPORT_SYMBOL(get_tc_irq_nr); +EXPORT_SYMBOL(claim_tc_card); +EXPORT_SYMBOL(search_tc_card); +EXPORT_SYMBOL(get_tc_speed); +EXPORT_SYMBOL(get_tc_base_addr); diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/tc/zs.c linux.ac/drivers/tc/zs.c --- linux.vanilla/drivers/tc/zs.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/tc/zs.c Tue Jun 22 01:35:01 1999 @@ -0,0 +1,2107 @@ +/* + * decserial.c: Serial port driver for IOASIC DECsatations. + * + * Derived from drivers/macintosh/macserial.c by Harald Koerfgen. + * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. + * + * DECstation changes + * Copyright (C) 1998 Harald Koerfgen (Harald.Koerfgen@home.ivm.de) + * + * For the rest of the code the original Copyright applies: + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Keyboard and mouse are not supported right now. If you want to change this, + * you might want to have a look at drivers/sbus/char/sunserial.c to see + * how this might be done. HK + */ + +#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 +#include +#include +#include +#include +#ifdef CONFIG_KGDB +#include +#endif + +#include "zs.h" + + +/* + * It would be nice to dynamically allocate everything that + * depends on NUM_SERIAL, so we could support any number of + * Z8530s, but for now... + */ +#define NUM_SERIAL 2 /* Max number of ZS chips supported */ +#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */ + +#define RECOVERY_DELAY udelay(2) + +struct dec_zschannel zs_channels[NUM_CHANNELS]; + +struct dec_serial zs_soft[NUM_CHANNELS]; +int zs_channels_found; +struct dec_serial *zs_chain; /* list of all channels */ + +struct tty_struct zs_ttys[NUM_CHANNELS]; + +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +#endif + +#ifdef CONFIG_KGDB +struct dec_zschannel *zs_kgdbchan; +static unsigned char scc_inittab[] = { + 9, 0x80, /* reset A side (CHRA) */ + 13, 0, /* set baud rate divisor */ + 12, 1, + 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */ + 11, 0x50, /* clocks = br gen (RCBR | TCBR) */ + 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */ + 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/ + 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/ +}; +#endif + +static unsigned char zs_init_regs[16] __initdata = { + 0, /* write 0 */ + 0, /* write 1 */ + 0xf0, /* write 2 */ + (Rx8), /* write 3 */ + (X16CLK | SB1), /* write 4 */ + (Tx8), /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + (VIS), /* write 9 */ + (NRZ), /* write 10 */ + (TCBR | RCBR), /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + (BRSRC | BRENABL), /* write 14 */ + 0 /* write 15 */ +}; + +#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */ + +DECLARE_TASK_QUEUE(tq_zs_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * Debugging. + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_THROTTLE +#undef SERIAL_PARANOIA_CHECK + +#define RS_STROBE_TIME 10 +#define RS_ISR_PASS_LIMIT 256 + +#define _INLINE_ inline + +static void probe_sccs(void); +static void change_speed(struct dec_serial *info); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +static struct tty_struct *serial_table[NUM_CHANNELS]; +static struct termios *serial_termios[NUM_CHANNELS]; +static struct termios *serial_termios_locked[NUM_CHANNELS]; + +#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[4096]; /* This is cheating */ +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct dec_serial *info, + dev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%d, %d) in %s\n"; + static const char *badinfo = + "Warning: null mac_serial for (%d, %d) in %s\n"; + + if (!info) { + printk(badinfo, MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 0, 0 }; + +/* + * Reading and writing Z8530 registers. + */ +static inline unsigned char read_zsreg(struct dec_zschannel *channel, + unsigned char reg) +{ + unsigned char retval; + + if (reg != 0) { + *channel->control = reg & 0xf; + RECOVERY_DELAY; + } + retval = *channel->control; + RECOVERY_DELAY; + return retval; +} + +static inline void write_zsreg(struct dec_zschannel *channel, + unsigned char reg, unsigned char value) +{ + if (reg != 0) { + *channel->control = reg & 0xf; + RECOVERY_DELAY; + } + *channel->control = value; + RECOVERY_DELAY; + return; +} + +static inline unsigned char read_zsdata(struct dec_zschannel *channel) +{ + unsigned char retval; + + retval = *channel->data; + RECOVERY_DELAY; + return retval; +} + +static inline void write_zsdata(struct dec_zschannel *channel, + unsigned char value) +{ + *channel->data = value; + RECOVERY_DELAY; + return; +} + +static inline void load_zsregs(struct dec_zschannel *channel, + unsigned char *regs) +{ +/* ZS_CLEARERR(channel); + ZS_CLEARFIFO(channel); */ + /* Load 'em up */ + write_zsreg(channel, R4, regs[R4]); + write_zsreg(channel, R3, regs[R3] & ~RxENABLE); + write_zsreg(channel, R5, regs[R5] & ~TxENAB); + write_zsreg(channel, R9, regs[R9]); + write_zsreg(channel, R1, regs[R1]); + write_zsreg(channel, R2, regs[R2]); + write_zsreg(channel, R10, regs[R10]); + write_zsreg(channel, R11, regs[R11]); + write_zsreg(channel, R12, regs[R12]); + write_zsreg(channel, R13, regs[R13]); + write_zsreg(channel, R14, regs[R14]); + write_zsreg(channel, R15, regs[R15]); + write_zsreg(channel, R3, regs[R3]); + write_zsreg(channel, R5, regs[R5]); + return; +} + +/* Sets or clears DTR/RTS on the requested line */ +static inline void zs_rtsdtr(struct dec_serial *ss, int set) +{ + if (ss->zs_channel != ss->zs_chan_a) { + if (set) + ss->zs_chan_a->curregs[5] |= (RTS | DTR); + else + ss->zs_chan_a->curregs[5] &= ~(RTS | DTR); + write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]); + } + return; +} + +/* Utility routines for the Zilog */ +static inline int get_zsbaud(struct dec_serial *ss) +{ + struct dec_zschannel *channel = ss->zs_channel; + int brg; + + /* The baud rate is split up between two 8-bit registers in + * what is termed 'BRG time constant' format in my docs for + * the chip, it is a function of the clk rate the chip is + * receiving which happens to be constant. + */ + brg = (read_zsreg(channel, 13) << 8); + brg |= read_zsreg(channel, 12); + return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor))); +} + +/* On receive, this clears errors and the receiver interrupts */ +static inline void rs_recv_clear(struct dec_zschannel *zsc) +{ + write_zsreg(zsc, 0, ERR_RES); + write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */ +} + +/* + * ---------------------------------------------------------------------- + * + * 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. + * + * - 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 dec_serial *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_zs_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct dec_serial *info, + struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, stat, flag; + + while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) { + + stat = read_zsreg(info->zs_channel, R1); + ch = read_zsdata(info->zs_channel); + +#ifdef CONFIG_KGDB + if (info->kgdb_channel) { + if (ch == 0x03 || ch == '$') + breakpoint(); + if (stat & (Rx_OVR|FRM_ERR|PAR_ERR)) + write_zsreg(info->zs_channel, 0, ERR_RES); + return; + } +#endif + if (!tty) + continue; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + static int flip_buf_ovf; + ++flip_buf_ovf; + continue; + } + tty->flip.count++; + { + static int flip_max_cnt; + if (flip_max_cnt < tty->flip.count) + flip_max_cnt = tty->flip.count; + } + if (stat & Rx_OVR) { + flag = TTY_OVERRUN; + } else if (stat & FRM_ERR) { + flag = TTY_FRAME; + } else if (stat & PAR_ERR) { + flag = TTY_PARITY; + } else + flag = 0; + if (flag) + /* reset the error indication */ + write_zsreg(info->zs_channel, 0, ERR_RES); + *tty->flip.flag_buf_ptr++ = flag; + *tty->flip.char_buf_ptr++ = ch; + } + tty_flip_buffer_push(tty); +} + +static void transmit_chars(struct dec_serial *info) +{ + if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) + return; + info->tx_active = 0; + + if (info->x_char) { + /* Send next char */ + write_zsdata(info->zs_channel, info->x_char); + info->x_char = 0; + info->tx_active = 1; + return; + } + + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) { + write_zsreg(info->zs_channel, 0, RES_Tx_P); + return; + } + /* Send char */ + write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + info->tx_active = 1; + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); +} + +static _INLINE_ void status_handle(struct dec_serial *info) +{ + unsigned char status; + + /* Get status from Read Register 0 */ + status = read_zsreg(info->zs_channel, 0); + + /* FIXEM: Check for DCD transitions */ + if (((status ^ info->read_reg_zero) & DCD) != 0 + && info->tty && !C_CLOCAL(info->tty)) { + if (status & DCD) { + wake_up_interruptible(&info->open_wait); + } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { + if (info->tty) + tty_hangup(info->tty); + } + } + + /* Check for CTS transitions */ + if (info->tty && C_CRTSCTS(info->tty)) { + /* + * For some reason, on the Power Macintosh, + * it seems that the CTS bit is 1 when CTS is + * *negated* and 0 when it is asserted. + * The DCD bit doesn't seem to be inverted + * like this. + */ + if ((status & CTS) != 0) { + if (info->tx_stopped) { + info->tx_stopped = 0; + if (!info->tx_active) + transmit_chars(info); + } + } else { + info->tx_stopped = 1; + } + } + + /* Clear status condition... */ + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + info->read_reg_zero = status; +} + +/* + * This is the serial driver's generic interrupt routine + */ +void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct dec_serial *info = (struct dec_serial *) dev_id; + unsigned char zs_intreg; + int shift; + + /* NOTE: The read register 3, which holds the irq status, + * does so for both channels on each chip. Although + * the status value itself must be read from the A + * channel and is only valid when read from channel A. + * Yes... broken hardware... + */ +#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) + + if (info->zs_chan_a == info->zs_channel) + shift = 3; /* Channel A */ + else + shift = 0; /* Channel B */ + + for (;;) { + zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; + if ((zs_intreg & CHAN_IRQMASK) == 0) + break; + + if (zs_intreg & CHBRxIP) { + receive_chars(info, regs); + } + if (zs_intreg & CHBTxIP) { + transmit_chars(info); + } + if (zs_intreg & CHBEXT) { + status_handle(info); + } + } +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + +#if 1 + save_flags(flags); cli(); + if (info->zs_channel->curregs[5] & TxENAB) { + info->zs_channel->curregs[5] &= ~TxENAB; + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + } + restore_flags(flags); +#endif +} + +static void rs_start(struct tty_struct *tty) +{ + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); +#if 1 + if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) { + info->zs_channel->curregs[5] |= TxENAB; + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + } +#else + if (info->xmit_cnt && info->xmit_buf && !info->tx_active) { + transmit_chars(info); + } +#endif + restore_flags(flags); +} + +/* + * 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_zs_serial); +} + +static void do_softint(void *private_) +{ + struct dec_serial *info = (struct dec_serial *) 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); + } +} + +static void rs_timer(void) +{ +} + +static int startup(struct dec_serial * info) +{ + unsigned long flags; + + if (info->flags & ZILOG_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + save_flags(flags); cli(); + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...", info->line, info->irq); +#endif + + /* + * Clear the receive FIFO. + */ + ZS_CLEARFIFO(info->zs_channel); + info->xmit_fifo_size = 1; + + /* + * Clear the interrupt registers. + */ + write_zsreg(info->zs_channel, 0, ERR_RES); + write_zsreg(info->zs_channel, 0, RES_H_IUS); + + /* + * Turn on RTS and DTR. + */ + zs_rtsdtr(info, 1); + + /* + * Finally, enable sequencing and interrupts + */ + info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); + info->zs_channel->curregs[3] |= (RxENABLE | Rx8); + info->zs_channel->curregs[5] |= (TxENAB | Tx8); + info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE); + info->zs_channel->curregs[9] |= (VIS | MIE); + write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); + write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]); + write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); + + /* + * And clear the interrupt registers again for luck. + */ + write_zsreg(info->zs_channel, 0, ERR_RES); + write_zsreg(info->zs_channel, 0, RES_H_IUS); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set the speed of the serial port + */ + change_speed(info); + + /* Save the current value of RR0 */ + info->read_reg_zero = read_zsreg(info->zs_channel, 0); + + info->flags |= ZILOG_INITIALIZED; + restore_flags(flags); + return 0; +} + +/* + * 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 dec_serial * info) +{ + unsigned long flags; + + if (!(info->flags & ZILOG_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + info->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->zs_channel->curregs[1] = 0; + write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */ + + info->zs_channel->curregs[3] &= ~RxENABLE; + write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); + + info->zs_channel->curregs[5] &= ~TxENAB; + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + if (!info->tty || C_HUPCL(info->tty)) { + info->zs_chan_a->curregs[5] &= ~(DTR | RTS); + write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ZILOG_INITIALIZED; + restore_flags(flags); +} + +/* + * 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 dec_serial *info) +{ + unsigned short port; + unsigned cflag; + int i; + int brg; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!(port = info->port)) + return; + i = cflag & CBAUD; + + save_flags(flags); cli(); + info->zs_baud = baud_table[i]; + info->clk_divisor = 16; + + switch (info->zs_baud) { + default: + info->zs_channel->curregs[4] = X16CLK; + brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + info->zs_channel->curregs[12] = (brg & 255); + info->zs_channel->curregs[13] = ((brg >> 8) & 255); + } + + /* byte size and parity */ + info->zs_channel->curregs[3] &= ~RxNBITS_MASK; + info->zs_channel->curregs[5] &= ~TxNBITS_MASK; + switch (cflag & CSIZE) { + case CS5: + info->zs_channel->curregs[3] |= Rx5; + info->zs_channel->curregs[5] |= Tx5; + break; + case CS6: + info->zs_channel->curregs[3] |= Rx6; + info->zs_channel->curregs[5] |= Tx6; + break; + case CS7: + info->zs_channel->curregs[3] |= Rx7; + info->zs_channel->curregs[5] |= Tx7; + break; + case CS8: + default: /* defaults to 8 bits */ + info->zs_channel->curregs[3] |= Rx8; + info->zs_channel->curregs[5] |= Tx8; + break; + } + + info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); + if (cflag & CSTOPB) { + info->zs_channel->curregs[4] |= SB2; + } else { + info->zs_channel->curregs[4] |= SB1; + } + if (cflag & PARENB) { + info->zs_channel->curregs[4] |= PAR_ENA; + } + if (!(cflag & PARODD)) { + info->zs_channel->curregs[4] |= PAR_EVEN; + } + + if (!(cflag & CLOCAL)) { + if (!(info->zs_channel->curregs[15] & DCDIE)) + info->read_reg_zero = read_zsreg(info->zs_channel, 0); + info->zs_channel->curregs[15] |= DCDIE; + } else + info->zs_channel->curregs[15] &= ~DCDIE; + if (cflag & CRTSCTS) { + info->zs_channel->curregs[15] |= CTSIE; + if ((read_zsreg(info->zs_channel, 0) & CTS) != 0) + info->tx_stopped = 1; + } else { + info->zs_channel->curregs[15] &= ~CTSIE; + info->tx_stopped = 0; + } + + /* Load up the new values */ + load_zsregs(info->zs_channel, info->zs_channel->curregs); + + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped || + !info->xmit_buf) + return; + + /* Enable transmitter */ + save_flags(flags); cli(); + transmit_chars(info); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + save_flags(flags); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + if (from_user) { + down(&tmp_buf_sem); + copy_from_user(tmp_buf, buf, c); + 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); + up(&tmp_buf_sem); + } else + 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; + total += c; + } + + if (info->xmit_cnt && !tty->stopped && !info->tx_stopped + && !info->tx_active) + transmit_chars(info); + restore_flags(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct dec_serial *info = (struct dec_serial *)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 dec_serial *info = (struct dec_serial *)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 dec_serial *info = (struct dec_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + 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); +} + +/* + * ------------------------------------------------------------ + * 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 dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + 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)) { + save_flags(flags); cli(); + info->x_char = STOP_CHAR(tty); + if (!info->tx_active) + transmit_chars(info); + restore_flags(flags); + } + + if (C_CRTSCTS(tty)) { + /* + * Here we want to turn off the RTS line. On Macintoshes, + * we only get the DTR line, which goes to both DTR and + * RTS on the modem. RTS doesn't go out to the serial + * port socket. So you should make sure your modem is + * set to ignore DTR if you're using CRTSCTS. + */ + save_flags(flags); cli(); + info->zs_chan_a->curregs[5] &= ~(DTR | RTS); + write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); + restore_flags(flags); + } +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + 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)) { + save_flags(flags); cli(); + if (info->x_char) + info->x_char = 0; + else { + info->x_char = START_CHAR(tty); + if (!info->tx_active) + transmit_chars(info); + } + restore_flags(flags); + } + + if (C_CRTSCTS(tty)) { + /* Assert RTS and DTR lines */ + save_flags(flags); cli(); + info->zs_chan_a->curregs[5] |= DTR | RTS; + write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); + restore_flags(flags); + } +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct dec_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 = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + return copy_to_user(retinfo,&tmp,sizeof(*retinfo)); +} + +static int set_serial_info(struct dec_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct dec_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()) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ZILOG_USR_MASK) != + (info->flags & ~ZILOG_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ZILOG_USR_MASK) | + (new_serial.flags & ZILOG_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + 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->flags = ((info->flags & ~ZILOG_FLAGS) | + (new_serial.flags & ZILOG_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + 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 dec_serial * info, unsigned int *value) +{ + unsigned char status; + + cli(); + status = read_zsreg(info->zs_channel, 0); + sti(); + put_user(status,value); + return 0; +} + +static int get_modem_info(struct dec_serial *info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + + cli(); + control = info->zs_chan_a->curregs[5]; + status = read_zsreg(info->zs_channel, 0); + sti(); + result = ((control & RTS) ? TIOCM_RTS: 0) + | ((control & DTR) ? TIOCM_DTR: 0) + | ((status & DCD) ? TIOCM_CAR: 0) + | ((status & CTS) ? 0: TIOCM_CTS); + put_user(result,value); + return 0; +} + +static int set_modem_info(struct dec_serial *info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg, bits; + + error = verify_area(VERIFY_READ, value, sizeof(int)); + if (error) + return error; + get_user(arg, value); + bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0); + cli(); + switch (cmd) { + case TIOCMBIS: + info->zs_chan_a->curregs[5] |= bits; + break; + case TIOCMBIC: + info->zs_chan_a->curregs[5] &= ~bits; + break; + case TIOCMSET: + info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits; + break; + default: + sti(); + return -EINVAL; + } + write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); + sti(); + return 0; +} + +/* + * rs_break - turn transmit break condition on/off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct dec_serial *info = (struct dec_serial *) 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) + info->zs_channel->curregs[5] |= SND_BRK; + else + info->zs_channel->curregs[5] &= ~SND_BRK; + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct dec_serial * info = (struct dec_serial *)tty->driver_data; + +#ifdef CONFIG_KGDB + if (info->kgdb_channel) + return -ENODEV; +#endif + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + 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 TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + 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: + 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 dec_serial)); + if (error) + return error; + copy_from_user((struct dec_serial *) arg, + info, sizeof(struct dec_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct dec_serial *info = (struct dec_serial *)tty->driver_data; + int was_stopped; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + was_stopped = info->tx_stopped; + + change_speed(info); + + if (was_stopped && !info->tx_stopped) + rs_start(tty); +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. + * Wait for the last remaining data to be sent. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct dec_serial * info = (struct dec_serial *)tty->driver_data; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, info->count); +#endif + 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("rs_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 |= ZILOG_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ZILOG_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ZILOG_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 != ZILOG_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receiver and receive interrupts. + */ + info->zs_channel->curregs[3] &= ~RxENABLE; + write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); + info->zs_channel->curregs[1] = 0; /* disable any rx ints */ + write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); + ZS_CLEARFIFO(info->zs_channel); + if (info->flags & ZILOG_INITIALIZED) { + /* + * Before we drop DTR, make sure the SCC transmitter + * has completely drained. + */ + 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 &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| + ZILOG_CLOSING); + wake_up_interruptible(&info->close_wait); + 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 dec_serial *info = (struct dec_serial *) tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + 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. + */ + 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); + while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { + 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; +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct dec_serial * info = (struct dec_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_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 dec_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 & ZILOG_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ZILOG_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 & ZILOG_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ZILOG_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 & ZILOG_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ZILOG_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ZILOG_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 + * 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 + printk("block_til_ready before block: ttys%d, count = %d\n", + info->line, info->count); +#endif + cli(); + if (!tty_hung_up_p(filp)) + info->count--; + sti(); + info->blocked_open++; + while (1) { + cli(); + if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + zs_rtsdtr(info, 1); + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ZILOG_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ZILOG_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && + !(info->flags & ZILOG_CLOSING) && + (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ZILOG_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its ZILOG structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct dec_serial *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= zs_channels_found)) + return -ENODEV; + info = zs_soft + line; + +#ifdef CONFIG_KGDB + if (info->kgdb_channel) + return -ENODEV; +#endif + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); +#endif + + info->count++; + tty->driver_data = info; + info->tty = tty; + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ZILOG_CLOSING)) { + if (info->flags & ZILOG_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ZILOG_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->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 + printk("rs_open ttys%d successful...", info->line); +#endif +/* tty->low_latency = 1; */ + return 0; +} + +/* Finally, routines used to initialize the serial driver. */ + +__initfunc(static void show_serial_version(void)) +{ + printk("DECstation Z8530 serial driver version 0.03\n"); +} + +/* Initialize Z8530s zs_channels + */ + +__initfunc(static void probe_sccs(void)) +{ + struct dec_serial **pp; + int i, n, n_chips = 0, n_channels, chip, channel; + unsigned long flags; + + /* + * did we get here by accident? + */ + if(!IOASIC) { + printk("Not on JUNKIO machine, skipping probe_sccs\n"); + return; + } + + /* + * When serial console is activated, tc_init has not been called yet + * and system_base is undefined. Unfortunately we have to hardcode + * system_base for this case :-(. HK + */ + switch(mips_machtype) { + case MACH_DS5000_2X0: + system_base = 0xbf800000; + n_chips = 2; + break; + case MACH_DS5000_1XX: + system_base = 0xbc000000; + n_chips = 2; + break; + case MACH_DS5000_XX: + system_base = 0xbc000000; + n_chips = 1; + break; + } + + pp = &zs_chain; + + n_channels = 0; + + for (chip = 0; chip < n_chips; chip++) { + for (channel = 0; channel <= 1; channel++) { + /* + * The sccs reside on the high byte of the 16 bit IOBUS + */ + zs_channels[n_channels].control = (volatile unsigned char *) + system_base + (0 == chip ? SCC0 : SCC1) + (0 == channel ? 1 : 9); + zs_channels[n_channels].data = zs_channels[n_channels].control + 4; + zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; + zs_soft[n_channels].irq = SERIAL; + + if (0 == channel) + zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1]; + else + zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels]; + + *pp = &zs_soft[n_channels]; + pp = &zs_soft[n_channels].zs_next; + n_channels++; + } + } + + *pp = 0; + zs_channels_found = n_channels; + + for (n = 0; n < zs_channels_found; n++) { + for (i = 0; i < 16; i++) { + zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i]; + } + } + +/* save_and_cli(flags); + for (n = 0; n < zs_channels_found; n++) { + if (((int)zs_channels[n].control & 0xf) == 1) { + write_zsreg(zs_soft[channel].zs_chan_a, R9, FHWRES); + udelay(10000); + write_zsreg(zs_soft[channel].zs_chan_a, R9, 0); + } + load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs); + } + restore_flags(flags); */ +} + +/* zs_init inits the driver */ +__initfunc(int zs_init(void)) +{ + int channel, i; + unsigned long flags; + struct dec_serial *info; + + if(!IOASIC) + return -ENODEV; + + /* Setup base handler, and timer table. */ + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + /* Find out how many Z8530 SCCs we have */ + if (zs_chain == 0) + probe_sccs(); + + show_serial_version(); + + /* Initialize the tty_driver structure */ + /* Not all of this is exactly right for us. */ + + 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 = zs_channels_found; + 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.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.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; + + /* + * 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(); + + for (channel = 0; channel < zs_channels_found; ++channel) { +#ifdef CONFIG_KGDB + if (zs_soft[channel].kgdb_channel) { + continue; + } +#endif + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + + if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ, + "SCC", &zs_soft[channel])) + printk(KERN_ERR "decserial: can't get irq %d\n", + SERIAL); + + /* If console serial line, then enable interrupts. */ +/* if (zs_soft[channel].is_cons) { + write_zsreg(zs_soft[channel].zs_channel, R1, + (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB)); + write_zsreg(zs_soft[channel].zs_channel, R9, + (VIS | MIE)); + } +*/ + } + + for (info = zs_chain, i = 0; info; info = info->zs_next, i++) + { +#ifdef CONFIG_KGDB + if (info->kgdb_channel) { + continue; + } +#endif + info->magic = SERIAL_MAGIC; + info->port = (int) info->zs_channel->control; + info->line = i; + info->tty = 0; + info->custom_divisor = 16; + 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->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + printk("tty%02d at 0x%08x (irq = %d)", info->line, + info->port, info->irq); + printk(" is a Z85C30 SCC\n"); + } + + restore_flags(flags); + + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +/* PowerMac: Unused at this time, just here to make things link. */ +int register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ + return; +} + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ + +/* This is for console output */ +static void +zs_console_putchar(struct dec_serial *info, char ch) +{ + int loops = 10000; + unsigned long flags; + + if(!info->zs_channel) + return; + + save_flags(flags); cli(); + + while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops) + RECOVERY_DELAY; + *(info->zs_channel->data) = ch; + RECOVERY_DELAY; + + restore_flags(flags); +} + +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + struct dec_serial *info; + int i; + unsigned char nine; + + info = zs_soft + co->index; + +#if 0 + /* + * disable master interrupt if necessary + */ + nine = info->zs_channel->curregs[9]; + if(nine & MIE) + write_zsreg(info->zs_channel, R9, nine & ~MIE); +#endif + /* + * do it + */ + for (i = 0; i < count; i++, s++) { + if(*s == '\n') + zs_console_putchar(info, '\r'); + zs_console_putchar(info, *s); + } + /* + * restore master interrupt enable + */ +#if 0 + write_zsreg(info->zs_channel, R9, nine); +#endif +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + return 0; +} + +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 dec_serial *info; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + char *s; + unsigned long flags; + + if(!IOASIC) + return -ENODEV; + + info = zs_soft + co->index; + + if (zs_chain == 0) + probe_sccs(); + + info->is_cons = 1; + + 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; +#if 1 + save_and_cli(flags); + + /* + * Turn on RTS and DTR. + */ + zs_rtsdtr(info, 1); + + /* + * Finally, enable sequencing + */ + info->zs_channel->curregs[3] |= (RxENABLE | Rx8); + info->zs_channel->curregs[5] |= (TxENAB | Tx8); + info->zs_channel->curregs[9] |= (VIS); + write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); + write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); + write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); + + /* + * Clear the interrupt registers. + */ + write_zsreg(info->zs_channel, 0, ERR_RES); + write_zsreg(info->zs_channel, 0, RES_H_IUS); + + /* + * Set the speed of the serial port + */ + change_speed(info); + + /* Save the current value of RR0 */ + info->read_reg_zero = read_zsreg(info->zs_channel, 0); + + zs_soft[co->index].clk_divisor = 16; + zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]); + + restore_flags(flags); +#endif + 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 zs_serial_console_init(long kmem_start, long kmem_end)) +{ + register_console(&sercons); + return kmem_start; +} +#endif /* ifdef CONFIG_SERIAL_CONSOLE */ + +#ifdef CONFIG_KGDB +/* These are for receiving and sending characters under the kgdb + * source level kernel debugger. + */ +void putDebugChar(char kgdb_char) +{ + struct dec_zschannel *chan = zs_kgdbchan; + while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) + RECOVERY_DELAY; + write_zsdata(chan, kgdb_char); +} +char getDebugChar(void) +{ + struct dec_zschannel *chan = zs_kgdbchan; + while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) + eieio(); /*barrier();*/ + return read_zsdata(chan); +} +void kgdb_interruptible(int yes) +{ + struct dec_zschannel *chan = zs_kgdbchan; + int one, nine; + nine = read_zsreg(chan, 9); + if (yes == 1) { + one = EXT_INT_ENAB|INT_ALL_Rx; + nine |= MIE; + printk("turning serial ints on\n"); + } else { + one = RxINT_DISAB; + nine &= ~MIE; + printk("turning serial ints off\n"); + } + write_zsreg(chan, 1, one); + write_zsreg(chan, 9, nine); +} +/* This sets up the serial port we're using, and turns on + * interrupts for that channel, so kgdb is usable once we're done. + */ +static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps) +{ + int brg; + int i, x; + volatile char *sccc = ms->control; + brg = BPS_TO_BRG(bps, ZS_CLOCK/16); + printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg); + for (i = 20000; i != 0; --i) { + x = *sccc; eieio(); + } + for (i = 0; i < sizeof(scc_inittab); ++i) { + write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]); + i++; + } +} +/* This is called at boot time to prime the kgdb serial debugging + * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 + * for /dev/ttyb which is determined in setup_arch() from the + * boot command line flags. + */ +__initfunc(void zs_kgdb_hook(int tty_num)) +{ + /* Find out how many Z8530 SCCs we have */ + if (zs_chain == 0) + probe_sccs(); + zs_soft[tty_num].zs_channel = &zs_channels[tty_num]; + zs_kgdbchan = zs_soft[tty_num].zs_channel; + zs_soft[tty_num].change_needed = 0; + zs_soft[tty_num].clk_divisor = 16; + zs_soft[tty_num].zs_baud = 38400; + zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ + zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ + /* Turn on transmitter/receiver at 8-bits/char */ + kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400); + printk("KGDB: on channel %d initialized\n", tty_num); + set_debug_traps(); /* init stub */ +} +#endif /* ifdef CONFIG_KGDB */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/tc/zs.h linux.ac/drivers/tc/zs.h --- linux.vanilla/drivers/tc/zs.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/tc/zs.h Tue Jun 22 01:35:01 1999 @@ -0,0 +1,405 @@ +/* + * macserial.h: Definitions for the Macintosh Z8530 serial driver. + * + * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. + * + * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _DECSERIAL_H +#define _DECSERIAL_H + +#define NUM_ZSREGS 16 + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + int reserved[4]; +}; + +/* + * For the close wait times, 0 means wait forever for serial port to + * flush its output. 65535 means don't wait at all. + */ +#define ZILOG_CLOSING_WAIT_INF 0 +#define ZILOG_CLOSING_WAIT_NONE 65535 + +/* + * Definitions for ZILOG_struct (and serial_struct) flags field + */ +#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ZILOG_SPD_MASK 0x0030 +#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */ +#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ +#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +/* Software state per channel */ + +#ifdef __KERNEL__ +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * For definitions of the flags field, see tty.h + */ + +struct dec_zschannel { + volatile unsigned char *control; + volatile unsigned char *data; + + /* Current write register values */ + unsigned char curregs[NUM_ZSREGS]; +}; + +struct dec_serial { + struct dec_serial *zs_next; /* For IRQ servicing chain */ + struct dec_zschannel *zs_channel; /* Channel registers */ + struct dec_zschannel *zs_chan_a; /* A side registers */ + unsigned char read_reg_zero; + + char soft_carrier; /* Use soft carrier on this channel */ + char break_abort; /* Is serial console in, so process brk/abrt */ + char kgdb_channel; /* Kgdb is running on this channel */ + char is_cons; /* Is this our console. */ + unsigned char tx_active; /* character is being xmitted */ + unsigned char tx_stopped; /* output is suspended */ + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int zs_baud; + + char change_needed; + + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; +}; + + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +#endif /* __KERNEL__ */ + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ +#define RxNBITS_MASK 0xc0 + +/* Write Register 4 */ + +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ +#define SB_MASK 0xc + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ +#define XCLK_MASK 0xC0 + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define TxNBITS_MASK 0x60 +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define SOFTACK 0x20 /* Software Interrupt Acknowledge */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define FRM_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) +#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ + garbage = read_zsdata(channel); \ + garbage = read_zsdata(channel); \ + garbage = read_zsdata(channel); \ + } while(0) + +#endif /* !(_DECSERIAL_H) */ diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Config.in linux.ac/drivers/usb/Config.in --- linux.vanilla/drivers/usb/Config.in Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Config.in Fri Jun 4 23:52:47 1999 @@ -21,6 +21,7 @@ bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB fi + bool 'USB hub support (just say yes)' CONFIG_USB_HUB bool 'USB mouse support' CONFIG_USB_MOUSE bool 'USB keyboard support' CONFIG_USB_KBD bool 'USB audio parsing support' CONFIG_USB_AUDIO diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/Makefile linux.ac/drivers/usb/Makefile --- linux.vanilla/drivers/usb/Makefile Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/Makefile Fri Jun 4 23:52:47 1999 @@ -18,7 +18,11 @@ M_OBJS := L_OBJS := LX_OBJS := -USBX_OBJS := usb.o hub.o usb-debug.o +USBX_OBJS := usb.o usb-debug.o + +ifeq ($(CONFIG_USB_HUB),y) + USBX_OBJS += hub.o +endif ifeq ($(CONFIG_USB_MOUSE),y) USBX_OBJS += mouse.o diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/README.ohci_hcd linux.ac/drivers/usb/README.ohci_hcd --- linux.vanilla/drivers/usb/README.ohci_hcd Thu May 27 22:11:56 1999 +++ linux.ac/drivers/usb/README.ohci_hcd Thu Jan 1 01:00:00 1970 @@ -1,112 +0,0 @@ - -The OHCI HCD layer is a simple but nearly complete implementation of what the -USB people would call a HCD for the OHCI. - (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled) -It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree). -The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. - -- Roman Weissgaerber - - - * v2.1 1999/05/09 ep_addr correction, code cleanup - * v0.2.0 1999/05/04 - * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers) - * virtual root hub is now an option, - * memory allocation based on kmalloc and kfree now, simple Bus error handling, - * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion - * - * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff - * from Greg Smith (ohci.c): better reset ohci-controller handling, hub - * - * v0.1.0 1999/04/27 initial release - -to remove the module try: -killall root-hub -: -rmmod usb-ohci-hcd - -Features: -- virtual root hub, all basic hub descriptors and commands (state: complete) - this is an option now (v0.2.0) - #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB) - default is without. - (at the moment: the Virtual Root Hub option is not recommended) - - files: ohci-root-hub.c, ohci-root-hub.h - - -- Endpoint Descriptor (ED) handling more static approach - (EDs should be allocated in parallel to the SET CONFIGURATION command and they live - as long as the function (device) is alive or another configuration is choosen. - In the HCD layer the EDs has to be allocated manually either by calling a subroutine - or by sending a USB root hub vendor specific command to the virtual root hub. - At the alternate linux usb stack EDs will be added (allocated) at their first use. - - files: ohci-hcd.c ohci-hcd.h - routines: (do not use for drivers, use the top layer alternate usb commands instead) - - int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, - int interval, int load, f_handler handler, int ep_size, int speed) - adds an endpoint, (if the endpoint already exists some parameters will be updated) - - int usb_ohci_rm_ep(struct usb_ohci_ed *ed, struct ohci * ohci) - removes an endpoint and all pending TDs of that EP - - usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr) - removes all Endpoints of a function (device) - -- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers - The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has - to take care of buffer allocation. - files: ohci-hcd.c ohci-hcd.h - - There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL): - - int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) - - CTRL: ctrl, ctrl_len ... cmd buffer - data, data_len ... data buffer (in or out) - INT, BULK: ctrl = NULL, ctrl_len=0, - data, data_len ... data buffer (in or out) - ISO: tbd - - There is no buffer reinsertion done by the internal HCD function. - (The interface layer does this for a INT-pipe on request.) - If you want a transfer then you have to - provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED - you can send as many as you like. They should come back by the callback f_handler in - the same order (for each endpoint, not globally) If an error occurs all - queued transfers of an endpoint will return unsent. They will be marked with an error status. - - e.g double-buffering for int transfers: - - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - and when a data0 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0) - and when a data1 packet returns by the callback f_handler requeue it: - ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0) - - lw0, lw1 are private fields for upper layers for ids or fine grained handlers. - The alternate usb uses them for dev_id and usb_device_irq handler. - - -- Done list handling: returns the requests (callback f_handler in ED) and does - some error handling, root-hub request dequeuing - (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0)) - -ep_addr union or int is for addressing devices&endpoints: -__u8 ep_addr.bep.ep ... bit 3..0 endpoint address - bit 4 0 - bit 6,5 type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO - bit 7 direction 1 IN, 0 OUT - -__u8 ep_addr.bep.fa ... bit 6..0 function address - bit 7 0 - -(__u8 ep_addr.bep.hc ... host controller nr) not used -(__u8 ep_addr.bep.host ... host nr) not used - - - diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.c linux.ac/drivers/usb/audio.c --- linux.vanilla/drivers/usb/audio.c Wed Apr 28 19:14:28 1999 +++ linux.ac/drivers/usb/audio.c Fri Jun 4 23:52:47 1999 @@ -4,6 +4,7 @@ #include #include #include "usb.h" +#include "audio.h" static int usb_audio_probe(struct usb_device *dev); static void usb_audio_disconnect(struct usb_device *dev); @@ -108,6 +109,7 @@ int usb_audio_init(void) { + printk("Registering audio devices.\n"); usb_register(&usb_audio_driver); return 0; } @@ -118,9 +120,95 @@ void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) { + if(interface->audio==NULL) + { + interface->audio = (struct usb_audio_if *)kmalloc(sizeof(struct usb_audio_if), GFP_KERNEL); + if(interface->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(interface->audio, 0, sizeof(struct usb_audio_if)); + } + printk("audio_if: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + case 1:printk(" header.\n");break; + case 2:printk(" input.\n");break; + case 3:printk(" output.\n");break; + case 4:printk(" mixer.\n");break; + case 5:printk(" selector.\n");break; + case 6:printk(" feature.\n");break; + case 7:printk(" processor.\n");break; + case 8:printk(" extension.\n");break; + } } -void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) +void usb_audio_endpoint(struct usb_endpoint_descriptor *endpoint, u8 *data) { + if(endpoint->audio==NULL) + { + endpoint->audio = (struct usb_audio_endpoint *)kmalloc(sizeof(struct usb_audio_endpoint), GFP_KERNEL); + if(endpoint->audio==NULL) + { + printk(KERN_WARNING "usb_audio: out of memory.\n"); + return; + } + memset(endpoint->audio, 0, sizeof(struct usb_audio_endpoint)); + } + printk("audio_ep: type %d subtype %d.\n", data[1], data[2]); + switch(data[2]) + { + + case 0x01: + if(data[3]&1) + printk(" ep has frequency control.\n"); + if(data[3]&2) + printk(" ep has pitch control.\n"); + if(data[3]&128) + printk(" ep supports no partial frames.\n"); + printk(" ep lock delay %04X", + data[5]|data[6]<<8); + switch(data[4]) + { + case 1:printk("mS");break; + case 2:printk(" samples");break; + } + printk("\n"); + break; + } } + +/* + * There is duplication of the loops here, but it avoids the core + * code having to know anything about audio. + */ + +void usb_audio_destroy(struct usb_device *dev) +{ + int c, i; + struct usb_config_descriptor *cf; + struct usb_interface_descriptor *ifp; + + if(dev->config==NULL) + return; + + for(c=0;cdescriptor.bNumConfigurations;c++) + { + cf=&dev->config[c]; + if(cf->interface==NULL) + break; + for(i=0;ibNumInterfaces;i++) + { + ifp=&cf->interface[i]; + if(ifp->endpoint==NULL) + break; + if(ifp->endpoint->audio) + kfree(ifp->endpoint->audio); + } + if(cf->interface->audio) + kfree(cf->interface->audio); + } +} + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/audio.h linux.ac/drivers/usb/audio.h --- linux.vanilla/drivers/usb/audio.h Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/usb/audio.h Fri Jun 4 23:52:47 1999 @@ -0,0 +1,33 @@ +#define MAX_AUDIO_IFACE 8 +#define MAX_AUDIO_ENDPOINT 8 + +/* + * This isnt a byte valid image of the descriptor. + * The dorks didnt do sensible alignment + */ + +struct usb_audio_if_data +{ + u8 data[MAX_AUDIO_IFACE*2+32]; +}; + +struct usb_audio_ep_data +{ + u8 data[7]; +}; + + +struct usb_audio_if +{ + u16 count; + struct usb_audio_if_data iface[MAX_AUDIO_IFACE]; +}; + +struct usb_audio_endpoint +{ + u16 count; + struct usb_audio_ep_data endpoint[MAX_AUDIO_ENDPOINT]; +}; + + + \ No newline at end of file diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/uhci.c linux.ac/drivers/usb/uhci.c --- linux.vanilla/drivers/usb/uhci.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/uhci.c Fri Jun 4 23:52:47 1999 @@ -898,6 +898,7 @@ dev = uhci->root_hub = usb_to_uhci(usb); usb->bus = bus; + bus->root_hub = uhci_to_usb(uhci->root_hub); /* Initialize the root hub */ /* UHCI specs says devices must have 2 ports, but goes on to say */ @@ -1191,7 +1192,9 @@ #ifdef CONFIG_USB_KBD usb_kbd_init(); #endif +#ifdef CONFIG_USB_HUB hub_init(); +#endif #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.c linux.ac/drivers/usb/usb.c --- linux.vanilla/drivers/usb/usb.c Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.c Fri Jun 4 23:52:47 1999 @@ -311,6 +311,9 @@ if(dev->config==NULL) return; + + usb_audio_destroy(dev); + for(c=0;cdescriptor.bNumConfigurations;c++) { cf=&dev->config[c]; diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/usb/usb.h linux.ac/drivers/usb/usb.h --- linux.vanilla/drivers/usb/usb.h Thu May 27 22:11:57 1999 +++ linux.ac/drivers/usb/usb.h Sat Jun 5 00:12:41 1999 @@ -367,9 +367,11 @@ #ifdef CONFIG_USB_AUDIO void usb_audio_interface(struct usb_interface_descriptor *, u8 *); void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +void usb_audio_destroy(struct usb_device *); #else extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {} extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {} +extern inline void usb_audio_destroy(struct usb_device *) {} #endif #endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Config.in linux.ac/drivers/video/Config.in --- linux.vanilla/drivers/video/Config.in Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Config.in Fri Jun 4 23:52:46 1999 @@ -74,6 +74,7 @@ fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA + bool 'VGA 16-color graphics console' CONFIG_FB_VGA16 define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -141,6 +142,7 @@ tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 # tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC + bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA else # Guess what we need @@ -282,6 +284,9 @@ if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then define_bool CONFIG_FBCON_MAC m fi + fi + if [ "$CONFIG_FB_VGA16" = "y" ]; then + define_bool CONFIG_FBCON_VGA_PLANES y fi if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then define_bool CONFIG_FBCON_VGA y diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/Makefile linux.ac/drivers/video/Makefile --- linux.vanilla/drivers/video/Makefile Fri May 28 00:32:59 1999 +++ linux.ac/drivers/video/Makefile Mon Jul 19 04:20:38 1999 @@ -192,9 +192,11 @@ ifeq ($(CONFIG_FB_TGA),y) L_OBJS += tgafb.o +CONFIG_FBGEN_BUILTIN = y else ifeq ($(CONFIG_FB_TGA),m) M_OBJS += tgafb.o + CONFIG_FBGEN_MODULE = y endif endif @@ -202,6 +204,10 @@ L_OBJS += vesafb.o endif +ifeq ($(CONFIG_FB_VGA16),y) +L_OBJS += vga16fb.o +endif + ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -462,6 +468,14 @@ endif endif +ifeq ($(CONFIG_FBCON_VGA_PLANES),y) +OX_OBJS += fbcon-vga-planes.o +else + ifeq ($(CONFIG_FBCON_VGA_PLANES),m) + MX_OBJS += fbcon-vga-planes.o + endif +endif + ifeq ($(CONFIG_FBCON_VGA),y) OX_OBJS += fbcon-vga.o else @@ -483,6 +497,16 @@ else ifeq ($(CONFIG_MDA_CONSOLE),m) M_OBJS += mdacon.o + endif +endif + +# Newport Text Console + +ifeq ($(CONFIG_SGI_NEWPORT_CONSOLE),y) +L_OBJS += newport_con.o vga_font.o +else + ifeq ($(CONFIG_SGI_NEWPORT_CONSOLE),m) + M_OBJS += newport_con.o vga_font.o endif endif diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/video/fbcon-vga-planes.c linux.ac/drivers/video/fbcon-vga-planes.c --- linux.vanilla/drivers/video/fbcon-vga-planes.c Thu Jan 1 01:00:00 1970 +++ linux.ac/drivers/video/fbcon-vga-planes.c Fri Jun 4 23:52:46 1999 @@ -0,0 +1,364 @@ +/* + * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations + * for VGA 4-plane modes + * + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on code by Michael Schmitz + * Based on the old macfb.c 4bpp code by Alan Cox + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. */ + +#include +#include +#include +#include +#include +#include + +#include + +#include